Merge branch 'master' into cool-ipcs
This commit is contained in:
@@ -5,44 +5,43 @@
|
||||
#define EXOTIC_BLEED_MULTIPLIER 4 //Multiplies the actually bled amount by this number for the purposes of turf reaction calculations.
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/suppress_bloodloss(amount)
|
||||
if(bleedsuppress)
|
||||
/mob/living/carbon/monkey/handle_blood()
|
||||
if(bodytemperature <= TCRYO || (HAS_TRAIT(src, TRAIT_HUSK))) //cryosleep or husked people do not pump the blood.
|
||||
return
|
||||
else
|
||||
bleedsuppress = TRUE
|
||||
addtimer(CALLBACK(src, .proc/resume_bleeding), amount)
|
||||
|
||||
var/temp_bleed = 0
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
temp_bleed += BP.get_bleed_rate()
|
||||
BP.generic_bleedstacks = max(0, BP.generic_bleedstacks - 1)
|
||||
if(temp_bleed)
|
||||
bleed(temp_bleed)
|
||||
|
||||
//Blood regeneration if there is some space
|
||||
if(blood_volume < BLOOD_VOLUME_NORMAL)
|
||||
blood_volume += 0.1 // regenerate blood VERY slowly
|
||||
if(blood_volume < BLOOD_VOLUME_OKAY)
|
||||
adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1))
|
||||
|
||||
/mob/living/carbon/human/proc/resume_bleeding()
|
||||
bleedsuppress = 0
|
||||
if(stat != DEAD && bleed_rate)
|
||||
if(stat != DEAD && is_bleeding())
|
||||
to_chat(src, "<span class='warning'>The blood soaks through your bandage.</span>")
|
||||
|
||||
|
||||
/mob/living/carbon/monkey/handle_blood()
|
||||
if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_NOCLONE))) //cryosleep or husked people do not pump the blood.
|
||||
//Blood regeneration if there is some space
|
||||
if(blood_volume < (BLOOD_VOLUME_NORMAL * blood_ratio))
|
||||
blood_volume += 0.1 // regenerate blood VERY slowly
|
||||
if(blood_volume < (BLOOD_VOLUME_OKAY * blood_ratio))
|
||||
adjustOxyLoss(round(((BLOOD_VOLUME_NORMAL * blood_ratio) - blood_volume) * 0.02, 1))
|
||||
|
||||
// Takes care blood loss and regeneration
|
||||
/mob/living/carbon/human/handle_blood()
|
||||
|
||||
if(NOBLOOD in dna.species.species_traits)
|
||||
bleed_rate = 0
|
||||
if(NOBLOOD in dna.species.species_traits || bleedsuppress || (HAS_TRAIT(src, TRAIT_FAKEDEATH)))
|
||||
return
|
||||
|
||||
if(bleed_rate < 0)
|
||||
bleed_rate = 0
|
||||
|
||||
if(HAS_TRAIT(src, TRAIT_NOMARROW)) //Bloodsuckers don't need to be here.
|
||||
return
|
||||
|
||||
if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_NOCLONE))) //cryosleep or husked people do not pump the blood.
|
||||
if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_HUSK))) //cryosleep or husked people do not pump the blood.
|
||||
|
||||
//Blood regeneration if there is some space
|
||||
if(blood_volume < (BLOOD_VOLUME_NORMAL * blood_ratio) && !HAS_TRAIT(src, TRAIT_NOHUNGER))
|
||||
if(blood_volume < BLOOD_VOLUME_NORMAL && !HAS_TRAIT(src, TRAIT_NOHUNGER))
|
||||
var/nutrition_ratio = 0
|
||||
switch(nutrition)
|
||||
if(0 to NUTRITION_LEVEL_STARVING)
|
||||
@@ -55,22 +54,23 @@
|
||||
nutrition_ratio = 0.8
|
||||
else
|
||||
nutrition_ratio = 1
|
||||
if(HAS_TRAIT(src, TRAIT_HIGH_BLOOD))
|
||||
nutrition_ratio *= 1.2
|
||||
if(satiety > 80)
|
||||
nutrition_ratio *= 1.25
|
||||
adjust_nutrition(-nutrition_ratio * HUNGER_FACTOR)
|
||||
blood_volume = min((BLOOD_VOLUME_NORMAL * blood_ratio), blood_volume + 0.5 * nutrition_ratio)
|
||||
blood_volume = min(BLOOD_VOLUME_NORMAL, blood_volume + 0.5 * nutrition_ratio)
|
||||
|
||||
//Effects of bloodloss
|
||||
var/word = pick("dizzy","woozy","faint")
|
||||
switch(blood_volume * INVERSE(blood_ratio))
|
||||
switch(blood_volume)
|
||||
if(BLOOD_VOLUME_MAXIMUM to BLOOD_VOLUME_EXCESS)
|
||||
if(prob(10))
|
||||
to_chat(src, "<span class='warning'>You feel terribly bloated.</span>")
|
||||
if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE)
|
||||
if(prob(5))
|
||||
to_chat(src, "<span class='warning'>You feel [word].</span>")
|
||||
adjustOxyLoss(round(((BLOOD_VOLUME_NORMAL * blood_ratio) - blood_volume) * 0.01, 1))
|
||||
adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.01, 1))
|
||||
if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY)
|
||||
adjustOxyLoss(round(((BLOOD_VOLUME_NORMAL * blood_ratio) - blood_volume) * 0.02, 1))
|
||||
adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1))
|
||||
if(prob(5))
|
||||
blur_eyes(6)
|
||||
to_chat(src, "<span class='warning'>You feel very [word].</span>")
|
||||
@@ -87,24 +87,11 @@
|
||||
//Bleeding out
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
var/brutedamage = BP.brute_dam
|
||||
temp_bleed += BP.get_bleed_rate()
|
||||
BP.generic_bleedstacks = max(0, BP.generic_bleedstacks - 1)
|
||||
|
||||
if(BP.status == BODYPART_ROBOTIC) //for the moment, synth limbs won't bleed, but soon, my pretty.
|
||||
continue
|
||||
|
||||
//We want an accurate reading of .len
|
||||
listclearnulls(BP.embedded_objects)
|
||||
for(var/obj/item/embeddies in BP.embedded_objects)
|
||||
if(!embeddies.isEmbedHarmless())
|
||||
temp_bleed += 0.5
|
||||
|
||||
if(brutedamage >= 20)
|
||||
temp_bleed += (brutedamage * 0.013)
|
||||
|
||||
bleed_rate = max(bleed_rate - 0.5, temp_bleed)//if no wounds, other bleed effects (heparin) naturally decreases
|
||||
|
||||
if(bleed_rate && !bleedsuppress && !(HAS_TRAIT(src, TRAIT_FAKEDEATH)))
|
||||
bleed(bleed_rate)
|
||||
if(temp_bleed)
|
||||
bleed(temp_bleed)
|
||||
|
||||
//Makes a blood drop, leaking amt units of blood from the mob
|
||||
/mob/living/carbon/proc/bleed(amt)
|
||||
@@ -128,9 +115,11 @@
|
||||
/mob/living/proc/restore_blood()
|
||||
blood_volume = initial(blood_volume)
|
||||
|
||||
/mob/living/carbon/human/restore_blood()
|
||||
/mob/living/carbon/restore_blood()
|
||||
blood_volume = (BLOOD_VOLUME_NORMAL * blood_ratio)
|
||||
bleed_rate = 0
|
||||
for(var/i in bodyparts)
|
||||
var/obj/item/bodypart/BP = i
|
||||
BP.generic_bleedstacks = 0
|
||||
|
||||
/****************************************************
|
||||
BLOOD TRANSFERS
|
||||
@@ -188,7 +177,7 @@
|
||||
blood_data["viruses"] += D.Copy()
|
||||
|
||||
blood_data["blood_DNA"] = dna.unique_enzymes
|
||||
blood_data["bloodcolor"] = bloodtype_to_color(dna.blood_type)
|
||||
blood_data["bloodcolor"] = dna.species.exotic_blood_color
|
||||
if(disease_resistances && disease_resistances.len)
|
||||
blood_data["resistances"] = disease_resistances.Copy()
|
||||
var/list/temp_chem = list()
|
||||
|
||||
@@ -37,10 +37,10 @@
|
||||
C.put_in_hands(B1)
|
||||
C.put_in_hands(B2)
|
||||
C.regenerate_icons()
|
||||
src.notransform = TRUE
|
||||
src.mob_transforming = TRUE
|
||||
spawn(0)
|
||||
bloodpool_sink(B)
|
||||
src.notransform = FALSE
|
||||
src.mob_transforming = FALSE
|
||||
return 1
|
||||
|
||||
/mob/living/proc/bloodpool_sink(obj/effect/decal/cleanable/B)
|
||||
@@ -73,7 +73,7 @@
|
||||
|
||||
if(victim.stat == CONSCIOUS)
|
||||
src.visible_message("<span class='warning'>[victim] kicks free of the blood pool just before entering it!</span>", null, "<span class='notice'>You hear splashing and struggling.</span>")
|
||||
else if(victim.reagents && victim.reagents.has_reagent(/datum/reagent/consumable/ethanol/demonsblood))
|
||||
else if(victim.reagents?.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(/datum/reagent/consumable/ethanol/devilskiss))
|
||||
if(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
|
||||
@@ -155,7 +155,7 @@
|
||||
addtimer(CALLBACK(src, /atom/.proc/remove_atom_colour, TEMPORARY_COLOUR_PRIORITY, newcolor), 6 SECONDS)
|
||||
|
||||
/mob/living/proc/phasein(obj/effect/decal/cleanable/B)
|
||||
if(src.notransform)
|
||||
if(src.mob_transforming)
|
||||
to_chat(src, "<span class='warning'>Finish eating first!</span>")
|
||||
return 0
|
||||
B.visible_message("<span class='warning'>[B] starts to bubble...</span>")
|
||||
|
||||
@@ -39,7 +39,9 @@
|
||||
laws.set_laws_config()
|
||||
|
||||
/obj/item/mmi/attackby(obj/item/O, mob/user, params)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
if(!user.CheckActionCooldown(CLICK_CD_MELEE))
|
||||
return
|
||||
user.DelayNextAction()
|
||||
if(istype(O, /obj/item/organ/brain)) //Time to stick a brain in it --NEO
|
||||
var/obj/item/organ/brain/newbrain = O
|
||||
if(brain)
|
||||
|
||||
@@ -100,3 +100,9 @@
|
||||
client.mouse_pointer_icon = M.mouse_pointer
|
||||
if (client && ranged_ability && ranged_ability.ranged_mousepointer)
|
||||
client.mouse_pointer_icon = ranged_ability.ranged_mousepointer
|
||||
|
||||
/mob/living/brain/proc/get_traumas()
|
||||
. = list()
|
||||
if(istype(loc, /obj/item/organ/brain))
|
||||
var/obj/item/organ/brain/B = loc
|
||||
. = B.traumas
|
||||
|
||||
@@ -76,9 +76,6 @@
|
||||
REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, C)
|
||||
C.update_hair()
|
||||
|
||||
/obj/item/organ/brain/prepare_eat()
|
||||
return // Too important to eat.
|
||||
|
||||
/obj/item/organ/brain/proc/transfer_identity(mob/living/L)
|
||||
name = "[L.name]'s brain"
|
||||
if(brainmob)
|
||||
@@ -105,7 +102,7 @@
|
||||
to_chat(brainmob, "<span class='notice'>You feel slightly disoriented. That's normal when you're just a brain.</span>")
|
||||
|
||||
/obj/item/organ/brain/attackby(obj/item/O, mob/user, params)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user.DelayNextAction(CLICK_CD_MELEE)
|
||||
if(brainmob)
|
||||
O.attack(brainmob, user) //Oh noooeeeee
|
||||
|
||||
@@ -342,6 +339,8 @@
|
||||
max_traumas = TRAUMA_LIMIT_BASIC
|
||||
if(TRAUMA_RESILIENCE_SURGERY)
|
||||
max_traumas = TRAUMA_LIMIT_SURGERY
|
||||
if(TRAUMA_RESILIENCE_WOUND)
|
||||
max_traumas = TRAUMA_LIMIT_WOUND
|
||||
if(TRAUMA_RESILIENCE_LOBOTOMY)
|
||||
max_traumas = TRAUMA_LIMIT_LOBOTOMY
|
||||
if(TRAUMA_RESILIENCE_MAGIC)
|
||||
@@ -400,7 +399,7 @@
|
||||
return
|
||||
|
||||
var/trauma_type = pick(possible_traumas)
|
||||
gain_trauma(trauma_type, resilience)
|
||||
return gain_trauma(trauma_type, resilience)
|
||||
|
||||
//Cure a random trauma of a certain resilience level
|
||||
/obj/item/organ/brain/proc/cure_trauma_type(brain_trauma_type = /datum/brain_trauma, resilience = TRAUMA_RESILIENCE_BASIC)
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
|
||||
/mob/living/brain/Life()
|
||||
set invisibility = 0
|
||||
if (notransform)
|
||||
/mob/living/brain/BiologicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
if(!loc)
|
||||
return
|
||||
. = ..()
|
||||
handle_emp_damage()
|
||||
|
||||
/mob/living/brain/update_stat()
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
status_flags = CANUNCONSCIOUS|CANPUSH
|
||||
|
||||
var/heat_protection = 0.5
|
||||
heat_protection = 0.5
|
||||
var/leaping = 0
|
||||
gib_type = /obj/effect/decal/cleanable/blood/gibs/xeno
|
||||
unique_name = 1
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
/mob/living/carbon/alien/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
|
||||
return ..(AM, skipcatch = TRUE, hitpush = FALSE)
|
||||
|
||||
/mob/living/carbon/alien/can_embed(obj/item/I)
|
||||
return FALSE
|
||||
|
||||
/*Code for aliens attacking aliens. Because aliens act on a hivemind, I don't see them as very aggressive with each other.
|
||||
As such, they can either help or harm other aliens. Help works like the human help command while harm is a simple nibble.
|
||||
In all, this is a lot like the monkey code. /N
|
||||
@@ -48,7 +45,7 @@ In all, this is a lot like the monkey code. /N
|
||||
return attack_alien(L)
|
||||
|
||||
|
||||
/mob/living/carbon/alien/attack_hand(mob/living/carbon/human/M)
|
||||
/mob/living/carbon/alien/on_attack_hand(mob/living/carbon/human/M)
|
||||
. = ..()
|
||||
if(.) //To allow surgery to return properly.
|
||||
return
|
||||
@@ -77,7 +74,6 @@ In all, this is a lot like the monkey code. /N
|
||||
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
|
||||
apply_damage(rand(1, 3), BRUTE, affecting)
|
||||
|
||||
|
||||
/mob/living/carbon/alien/attack_animal(mob/living/simple_animal/M)
|
||||
. = ..()
|
||||
if(.)
|
||||
|
||||
@@ -57,8 +57,17 @@
|
||||
|
||||
/mob/living/carbon/alien/humanoid/Topic(href, href_list)
|
||||
..()
|
||||
//strip panel
|
||||
//strip panel & embeds
|
||||
if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
|
||||
if(href_list["embedded_object"])
|
||||
var/obj/item/bodypart/L = locate(href_list["embedded_limb"]) in bodyparts
|
||||
if(!L)
|
||||
return
|
||||
var/obj/item/I = locate(href_list["embedded_object"]) in L.embedded_objects
|
||||
if(!I || I.loc != src) //no item, no limb, or item is not in limb or in the alien anymore
|
||||
return
|
||||
SEND_SIGNAL(src, COMSIG_CARBON_EMBED_RIP, I, L)
|
||||
return
|
||||
if(href_list["pouches"])
|
||||
visible_message("<span class='danger'>[usr] tries to empty [src]'s pouches.</span>", \
|
||||
"<span class='userdanger'>[usr] tries to empty [src]'s pouches.</span>")
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"<span class='userdanger'>[user] has [hitverb] [src]!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/alien/humanoid/attack_hand(mob/living/carbon/human/M)
|
||||
/mob/living/carbon/alien/humanoid/on_attack_hand(mob/living/carbon/human/M)
|
||||
. = ..()
|
||||
if(.) //To allow surgery to return properly.
|
||||
return
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
/mob/living/carbon/alien/humanoid/doUnEquip(obj/item/I)
|
||||
. = ..()
|
||||
if(!. || !I)
|
||||
return
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
|
||||
/mob/living/carbon/alien/larva/attack_hand(mob/living/carbon/human/M)
|
||||
/mob/living/carbon/alien/larva/on_attack_hand(mob/living/carbon/human/M)
|
||||
. = ..()
|
||||
if(. || M.a_intent == INTENT_HELP || M.a_intent == INTENT_GRAB)
|
||||
return
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
|
||||
|
||||
/mob/living/carbon/alien/larva/Life()
|
||||
set invisibility = 0
|
||||
if (notransform)
|
||||
/mob/living/carbon/alien/larva/BiologicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
if(..()) //not dead
|
||||
// GROW!
|
||||
if(amount_grown < max_grown)
|
||||
amount_grown++
|
||||
update_icons()
|
||||
// GROW!
|
||||
if(amount_grown < max_grown)
|
||||
amount_grown++
|
||||
update_icons()
|
||||
|
||||
|
||||
/mob/living/carbon/alien/larva/update_stat()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/mob/living/carbon/alien/Life()
|
||||
/mob/living/carbon/alien/BiologicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
findQueen()
|
||||
return..()
|
||||
|
||||
/mob/living/carbon/alien/check_breath(datum/gas_mixture/breath)
|
||||
if(status_flags & GODMODE)
|
||||
@@ -12,26 +13,23 @@
|
||||
|
||||
var/toxins_used = 0
|
||||
var/tox_detect_threshold = 0.02
|
||||
var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME
|
||||
var/list/breath_gases = breath.gases
|
||||
var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.return_temperature())/BREATH_VOLUME
|
||||
|
||||
//Partial pressure of the toxins in our breath
|
||||
var/Toxins_pp = (breath_gases[/datum/gas/plasma]/breath.total_moles())*breath_pressure
|
||||
var/Toxins_pp = (breath.get_moles(/datum/gas/plasma)/breath.total_moles())*breath_pressure
|
||||
|
||||
if(Toxins_pp > tox_detect_threshold) // Detect toxins in air
|
||||
adjustPlasma(breath_gases[/datum/gas/plasma]*250)
|
||||
adjustPlasma(breath.get_moles(/datum/gas/plasma)*250)
|
||||
throw_alert("alien_tox", /obj/screen/alert/alien_tox)
|
||||
|
||||
toxins_used = breath_gases[/datum/gas/plasma]
|
||||
toxins_used = breath.get_moles(/datum/gas/plasma)
|
||||
|
||||
else
|
||||
clear_alert("alien_tox")
|
||||
|
||||
//Breathe in toxins and out oxygen
|
||||
breath_gases[/datum/gas/plasma] -= toxins_used
|
||||
breath_gases[/datum/gas/oxygen] += toxins_used
|
||||
|
||||
GAS_GARBAGE_COLLECT(breath.gases)
|
||||
breath.adjust_moles(/datum/gas/plasma, -toxins_used)
|
||||
breath.adjust_moles(/datum/gas/oxygen, toxins_used)
|
||||
|
||||
//BREATH TEMPERATURE
|
||||
handle_breath_temperature(breath)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/obj/item/organ/alien
|
||||
icon_state = "xgibmid2"
|
||||
food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/acid = 10)
|
||||
var/list/alien_powers = list()
|
||||
organ_flags = ORGAN_NO_SPOIL
|
||||
organ_flags = ORGAN_NO_SPOIL|ORGAN_EDIBLE
|
||||
|
||||
/obj/item/organ/alien/Initialize()
|
||||
. = ..()
|
||||
@@ -26,12 +27,6 @@
|
||||
owner.RemoveAbility(P)
|
||||
..()
|
||||
|
||||
/obj/item/organ/alien/prepare_eat()
|
||||
var/obj/S = ..()
|
||||
S.reagents.add_reagent(/datum/reagent/toxin/acid, 10)
|
||||
return S
|
||||
|
||||
|
||||
/obj/item/organ/alien/plasmavessel
|
||||
name = "plasma vessel"
|
||||
icon_state = "plasma"
|
||||
@@ -39,17 +34,13 @@
|
||||
zone = BODY_ZONE_CHEST
|
||||
slot = "plasmavessel"
|
||||
alien_powers = list(/obj/effect/proc_holder/alien/plant, /obj/effect/proc_holder/alien/transfer)
|
||||
food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/plasma = 10)
|
||||
|
||||
var/storedPlasma = 100
|
||||
var/max_plasma = 250
|
||||
var/heal_rate = 5
|
||||
var/plasma_rate = 10
|
||||
|
||||
/obj/item/organ/alien/plasmavessel/prepare_eat()
|
||||
var/obj/S = ..()
|
||||
S.reagents.add_reagent(/datum/reagent/toxin/plasma, storedPlasma/10)
|
||||
return S
|
||||
|
||||
/obj/item/organ/alien/plasmavessel/large
|
||||
name = "large plasma vessel"
|
||||
icon_state = "plasma_large"
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
name = "alien embryo"
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
icon_state = "larva0_dead"
|
||||
food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/acid = 10)
|
||||
var/stage = 0
|
||||
var/bursting = FALSE
|
||||
|
||||
@@ -16,11 +17,6 @@
|
||||
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()
|
||||
. = ..()
|
||||
if(!owner)
|
||||
@@ -92,7 +88,7 @@
|
||||
ghost.transfer_ckey(new_xeno, FALSE)
|
||||
SEND_SOUND(new_xeno, sound('sound/voice/hiss5.ogg',0,0,0,100)) //To get the player's attention
|
||||
new_xeno.Paralyze(6)
|
||||
new_xeno.notransform = TRUE
|
||||
new_xeno.mob_transforming = TRUE
|
||||
new_xeno.invisibility = INVISIBILITY_MAXIMUM
|
||||
|
||||
sleep(6)
|
||||
@@ -102,7 +98,7 @@
|
||||
|
||||
if(new_xeno)
|
||||
new_xeno.SetParalyzed(0)
|
||||
new_xeno.notransform = FALSE
|
||||
new_xeno.mob_transforming = FALSE
|
||||
new_xeno.invisibility = 0
|
||||
|
||||
var/mob/living/carbon/old_owner = owner
|
||||
|
||||
@@ -58,8 +58,7 @@
|
||||
/obj/item/clothing/mask/facehugger/attack_alien(mob/user) //can be picked up by aliens
|
||||
return attack_hand(user)
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/clothing/mask/facehugger/attack_hand(mob/user)
|
||||
/obj/item/clothing/mask/facehugger/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
if((stat == CONSCIOUS && !sterile) && !isalien(user))
|
||||
if(Leap(user))
|
||||
return
|
||||
@@ -88,6 +87,7 @@
|
||||
Die()
|
||||
|
||||
/obj/item/clothing/mask/facehugger/equipped(mob/M)
|
||||
. = ..()
|
||||
Attach(M)
|
||||
|
||||
/obj/item/clothing/mask/facehugger/Crossed(atom/target)
|
||||
@@ -254,7 +254,7 @@
|
||||
return FALSE
|
||||
if(AmBloodsucker(M))
|
||||
return FALSE
|
||||
|
||||
|
||||
if(ismonkey(M))
|
||||
return 1
|
||||
|
||||
|
||||
@@ -47,16 +47,13 @@
|
||||
|
||||
|
||||
/mob/living/carbon/swap_hand(held_index)
|
||||
. = ..()
|
||||
if(!.)
|
||||
var/obj/item/held_item = get_active_held_item()
|
||||
to_chat(usr, "<span class='warning'>Your other hand is too busy holding [held_item].</span>")
|
||||
return
|
||||
if(!held_index)
|
||||
held_index = (active_hand_index % held_items.len)+1
|
||||
|
||||
var/obj/item/item_in_hand = src.get_active_held_item()
|
||||
if(item_in_hand) //this segment checks if the item in your hand is twohanded.
|
||||
var/obj/item/twohanded/TH = item_in_hand
|
||||
if(istype(TH))
|
||||
if(TH.wielded == 1)
|
||||
to_chat(usr, "<span class='warning'>Your other hand is too busy holding [TH]</span>")
|
||||
return
|
||||
var/oindex = active_hand_index
|
||||
active_hand_index = held_index
|
||||
if(hud_used)
|
||||
@@ -90,12 +87,24 @@
|
||||
if(user != src && (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 1
|
||||
return STOP_ATTACK_PROC_CHAIN
|
||||
|
||||
if(!all_wounds || !(user.a_intent == INTENT_HELP || user == src))
|
||||
return ..()
|
||||
|
||||
for(var/i in shuffle(all_wounds))
|
||||
var/datum/wound/W = i
|
||||
if(W.try_treating(I, user))
|
||||
return STOP_ATTACK_PROC_CHAIN
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
|
||||
. = ..()
|
||||
var/hurt = TRUE
|
||||
var/extra_speed = 0
|
||||
if(throwingdatum.thrower != src)
|
||||
extra_speed = min(max(0, throwingdatum.speed - initial(throw_speed)), 3)
|
||||
if(GetComponent(/datum/component/tackler))
|
||||
return
|
||||
if(throwingdatum?.thrower && iscyborg(throwingdatum.thrower))
|
||||
@@ -105,18 +114,18 @@
|
||||
if(hit_atom.density && isturf(hit_atom))
|
||||
if(hurt)
|
||||
DefaultCombatKnockdown(20)
|
||||
take_bodypart_damage(10)
|
||||
take_bodypart_damage(10 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5)
|
||||
if(iscarbon(hit_atom) && hit_atom != src)
|
||||
var/mob/living/carbon/victim = hit_atom
|
||||
if(victim.movement_type & FLYING)
|
||||
return
|
||||
if(hurt)
|
||||
victim.take_bodypart_damage(10)
|
||||
take_bodypart_damage(10)
|
||||
victim.take_bodypart_damage(10 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5)
|
||||
take_bodypart_damage(10 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5)
|
||||
victim.DefaultCombatKnockdown(20)
|
||||
DefaultCombatKnockdown(20)
|
||||
visible_message("<span class='danger'>[src] crashes into [victim], knocking them both over!</span>",\
|
||||
"<span class='userdanger'>You violently crash into [victim]!</span>")
|
||||
visible_message("<span class='danger'>[src] crashes into [victim] [extra_speed ? "really hard" : ""], knocking them both over!</span>",\
|
||||
"<span class='userdanger'>You violently crash into [victim] [extra_speed ? "extra hard" : ""]!</span>")
|
||||
playsound(src,'sound/weapons/punch1.ogg',50,1)
|
||||
|
||||
|
||||
@@ -156,6 +165,7 @@
|
||||
if(IS_STAMCRIT(src))
|
||||
to_chat(src, "<span class='warning'>You're too exhausted.</span>")
|
||||
return
|
||||
|
||||
var/random_turn = a_intent == INTENT_HARM
|
||||
//END OF CIT CHANGES
|
||||
|
||||
@@ -182,7 +192,7 @@
|
||||
to_chat(src, "<span class='notice'>You gently let go of [throwable_mob].</span>")
|
||||
return
|
||||
|
||||
adjustStaminaLossBuffered(25)//CIT CHANGE - throwing an entire person shall be very tiring
|
||||
adjustStaminaLossBuffered(STAM_COST_THROW_MOB * ((throwable_mob.mob_size+1)**2))// throwing an entire person shall be very tiring
|
||||
var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors
|
||||
var/turf/end_T = get_turf(target)
|
||||
if(start_T && end_T)
|
||||
@@ -199,12 +209,18 @@
|
||||
adjustStaminaLossBuffered(I.getweight(src, STAM_COST_THROW_MULT, SKILL_THROW_STAM_COST))
|
||||
|
||||
if(thrown_thing)
|
||||
visible_message("<span class='danger'>[src] has thrown [thrown_thing].</span>")
|
||||
log_message("has thrown [thrown_thing]", LOG_ATTACK)
|
||||
var/power_throw = 0
|
||||
if(HAS_TRAIT(src, TRAIT_HULK))
|
||||
power_throw++
|
||||
if(pulling && grab_state >= GRAB_NECK)
|
||||
power_throw++
|
||||
visible_message("<span class='danger'>[src] throws [thrown_thing][power_throw ? " really hard!" : "."]</span>", \
|
||||
"<span class='danger'>You throw [thrown_thing][power_throw ? " really hard!" : "."]</span>")
|
||||
log_message("has thrown [thrown_thing] [power_throw ? "really hard" : ""]", LOG_ATTACK)
|
||||
do_attack_animation(target, no_effect = 1)
|
||||
playsound(loc, 'sound/weapons/punchmiss.ogg', 50, 1, -1)
|
||||
newtonian_move(get_dir(target, src))
|
||||
thrown_thing.safe_throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src, null, null, null, move_force, random_turn)
|
||||
thrown_thing.safe_throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed + power_throw, src, null, null, null, move_force, random_turn)
|
||||
|
||||
/mob/living/carbon/restrained(ignore_grab)
|
||||
. = (handcuffed || (!ignore_grab && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE))
|
||||
@@ -295,14 +311,11 @@
|
||||
return
|
||||
if(restrained())
|
||||
// too soon.
|
||||
if(last_special > world.time)
|
||||
return
|
||||
var/buckle_cd = 600
|
||||
if(handcuffed)
|
||||
var/obj/item/restraints/O = src.get_item_by_slot(SLOT_HANDCUFFED)
|
||||
buckle_cd = O.breakouttime
|
||||
changeNext_move(min(CLICK_CD_BREAKOUT, buckle_cd))
|
||||
last_special = world.time + min(CLICK_CD_BREAKOUT, buckle_cd)
|
||||
MarkResistTime()
|
||||
visible_message("<span class='warning'>[src] attempts to unbuckle [p_them()]self!</span>", \
|
||||
"<span class='notice'>You attempt to unbuckle yourself... (This will take around [round(buckle_cd/600,1)] minute\s, and you need to stay still.)</span>")
|
||||
if(do_after(src, buckle_cd, 0, target = src, required_mobility_flags = MOBILITY_RESIST))
|
||||
@@ -316,39 +329,26 @@
|
||||
buckled.user_unbuckle_mob(src,src)
|
||||
|
||||
/mob/living/carbon/resist_fire()
|
||||
if(last_special > world.time)
|
||||
return
|
||||
fire_stacks -= 5
|
||||
DefaultCombatKnockdown(60, TRUE, TRUE)
|
||||
spin(32,2)
|
||||
visible_message("<span class='danger'>[src] rolls on the floor, trying to put [p_them()]self out!</span>", \
|
||||
"<span class='notice'>You stop, drop, and roll!</span>")
|
||||
last_special = world.time + 30
|
||||
MarkResistTime(30)
|
||||
sleep(30)
|
||||
if(fire_stacks <= 0)
|
||||
visible_message("<span class='danger'>[src] has successfully extinguished [p_them()]self!</span>", \
|
||||
"<span class='notice'>You extinguish yourself.</span>")
|
||||
ExtinguishMob()
|
||||
|
||||
/mob/living/carbon/resist_restraints(ignore_delay = FALSE)
|
||||
/mob/living/carbon/resist_restraints()
|
||||
var/obj/item/I = null
|
||||
var/type = 0
|
||||
if(!ignore_delay && (last_special > world.time))
|
||||
to_chat(src, "<span class='warning'>You don't have the energy to resist your restraints that fast!</span>")
|
||||
return
|
||||
if(handcuffed)
|
||||
I = handcuffed
|
||||
type = 1
|
||||
else if(legcuffed)
|
||||
I = legcuffed
|
||||
type = 2
|
||||
if(I)
|
||||
if(type == 1)
|
||||
changeNext_move(min(CLICK_CD_BREAKOUT, I.breakouttime))
|
||||
last_special = world.time + CLICK_CD_BREAKOUT
|
||||
if(type == 2)
|
||||
changeNext_move(min(CLICK_CD_RANGE, I.breakouttime))
|
||||
last_special = world.time + CLICK_CD_RANGE
|
||||
MarkResistTime()
|
||||
cuff_resist(I)
|
||||
|
||||
/mob/living/carbon/proc/cuff_resist(obj/item/I, breakouttime = 600, cuff_break = 0)
|
||||
@@ -393,7 +393,7 @@
|
||||
if (W)
|
||||
W.layer = initial(W.layer)
|
||||
W.plane = initial(W.plane)
|
||||
changeNext_move(0)
|
||||
SetNextAction(0)
|
||||
if (legcuffed)
|
||||
var/obj/item/W = legcuffed
|
||||
legcuffed = null
|
||||
@@ -406,7 +406,7 @@
|
||||
if (W)
|
||||
W.layer = initial(W.layer)
|
||||
W.plane = initial(W.plane)
|
||||
changeNext_move(0)
|
||||
SetNextAction(0)
|
||||
update_equipment_speed_mods() // In case cuffs ever change speed
|
||||
|
||||
/mob/living/carbon/proc/clear_cuffs(obj/item/I, cuff_break)
|
||||
@@ -895,6 +895,9 @@
|
||||
var/datum/disease/D = thing
|
||||
if(D.severity != DISEASE_SEVERITY_POSITIVE)
|
||||
D.cure(FALSE)
|
||||
for(var/thing in all_wounds)
|
||||
var/datum/wound/W = thing
|
||||
W.remove_wound()
|
||||
if(admin_revive)
|
||||
regenerate_limbs()
|
||||
regenerate_organs()
|
||||
@@ -985,6 +988,10 @@
|
||||
if(SANITY_NEUTRAL to SANITY_GREAT)
|
||||
. *= 0.90
|
||||
|
||||
for(var/i in status_effects)
|
||||
var/datum/status_effect/S = i
|
||||
. *= S.interact_speed_modifier()
|
||||
|
||||
|
||||
/mob/living/carbon/proc/create_internal_organs()
|
||||
for(var/X in internal_organs)
|
||||
@@ -1160,3 +1167,68 @@
|
||||
dna.features["body_model"] = MALE
|
||||
if(update_icon)
|
||||
update_body()
|
||||
|
||||
/mob/living/carbon/check_obscured_slots()
|
||||
if(head)
|
||||
if(head.flags_inv & HIDEMASK)
|
||||
LAZYOR(., SLOT_WEAR_MASK)
|
||||
if(head.flags_inv & HIDEEYES)
|
||||
LAZYOR(., SLOT_GLASSES)
|
||||
if(head.flags_inv & HIDEEARS)
|
||||
LAZYOR(., SLOT_EARS)
|
||||
|
||||
if(wear_mask)
|
||||
if(wear_mask.flags_inv & HIDEEYES)
|
||||
LAZYOR(., SLOT_GLASSES)
|
||||
|
||||
// if any of our bodyparts are bleeding
|
||||
/mob/living/carbon/proc/is_bleeding()
|
||||
for(var/i in bodyparts)
|
||||
var/obj/item/bodypart/BP = i
|
||||
if(BP.get_bleed_rate())
|
||||
return TRUE
|
||||
|
||||
// get our total bleedrate
|
||||
/mob/living/carbon/proc/get_total_bleed_rate()
|
||||
var/total_bleed_rate = 0
|
||||
for(var/i in bodyparts)
|
||||
var/obj/item/bodypart/BP = i
|
||||
total_bleed_rate += BP.get_bleed_rate()
|
||||
|
||||
return total_bleed_rate
|
||||
|
||||
/**
|
||||
* generate_fake_scars()- for when you want to scar someone, but you don't want to hurt them first. These scars don't count for temporal scarring (hence, fake)
|
||||
*
|
||||
* If you want a specific wound scar, pass that wound type as the second arg, otherwise you can pass a list like WOUND_LIST_SLASH to generate a random cut scar.
|
||||
*
|
||||
* Arguments:
|
||||
* * num_scars- A number for how many scars you want to add
|
||||
* * forced_type- Which wound or category of wounds you want to choose from, WOUND_LIST_BLUNT, WOUND_LIST_SLASH, or WOUND_LIST_BURN (or some combination). If passed a list, picks randomly from the listed wounds. Defaults to all 3 types
|
||||
*/
|
||||
/mob/living/carbon/proc/generate_fake_scars(num_scars, forced_type)
|
||||
for(var/i in 1 to num_scars)
|
||||
var/datum/scar/scaries = new
|
||||
var/obj/item/bodypart/scar_part = pick(bodyparts)
|
||||
|
||||
var/wound_type
|
||||
if(forced_type)
|
||||
if(islist(forced_type))
|
||||
wound_type = pick(forced_type)
|
||||
else
|
||||
wound_type = forced_type
|
||||
else
|
||||
wound_type = pick(GLOB.global_all_wound_types)
|
||||
|
||||
var/datum/wound/phantom_wound = new wound_type
|
||||
scaries.generate(scar_part, phantom_wound)
|
||||
scaries.fake = TRUE
|
||||
QDEL_NULL(phantom_wound)
|
||||
|
||||
/**
|
||||
* get_biological_state is a helper used to see what kind of wounds we roll for. By default we just assume carbons (read:monkeys) are flesh and bone, but humans rely on their species datums
|
||||
*
|
||||
* go look at the species def for more info [/datum/species/proc/get_biological_state]
|
||||
*/
|
||||
/mob/living/carbon/proc/get_biological_state()
|
||||
return BIO_FLESH_BONE
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
/mob/living/carbon/check_unarmed_parry_activation_special()
|
||||
return ..() && length(get_empty_held_indexes())
|
||||
@@ -65,32 +65,21 @@
|
||||
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)
|
||||
I.embedded()
|
||||
L.receive_damage(I.w_class*I.embedding["impact_pain_mult"])
|
||||
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, attackchain_flags = NONE, damage_multiplier = 1)
|
||||
var/totitemdamage = pre_attacked_by(I, user) * damage_multiplier
|
||||
var/impacting_zone = (user == src)? check_zone(user.zone_selected) : ran_zone(user.zone_selected)
|
||||
var/list/block_return = list()
|
||||
if((user != src) && (mob_run_block(I, totitemdamage, "the [I]", ((attackchain_flags & ATTACKCHAIN_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE) | ATTACK_TYPE_MELEE, I.armour_penetration, user, impacting_zone, block_return) & BLOCK_SUCCESS))
|
||||
if((user != src) && (mob_run_block(I, totitemdamage, "the [I]", ((attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE) | ATTACK_TYPE_MELEE, I.armour_penetration, user, impacting_zone, block_return) & BLOCK_SUCCESS))
|
||||
return FALSE
|
||||
totitemdamage = block_calculate_resultant_damage(totitemdamage, block_return)
|
||||
var/obj/item/bodypart/affecting = get_bodypart(impacting_zone)
|
||||
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)
|
||||
send_item_attack_message(I, user, affecting.name, affecting, totitemdamage)
|
||||
I.do_stagger_action(src, user, totitemdamage)
|
||||
if(I.force)
|
||||
apply_damage(totitemdamage, I.damtype, affecting) //CIT CHANGE - replaces I.force with totitemdamage
|
||||
apply_damage(totitemdamage, I.damtype, affecting, wound_bonus = I.wound_bonus, bare_wound_bonus = I.bare_wound_bonus, sharpness = I.get_sharpness()) //CIT CHANGE - replaces I.force with totitemdamage
|
||||
if(I.damtype == BRUTE && affecting.status == BODYPART_ORGANIC)
|
||||
var/basebloodychance = affecting.brute_dam + totitemdamage
|
||||
if(prob(basebloodychance))
|
||||
@@ -111,19 +100,12 @@
|
||||
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)
|
||||
/mob/living/carbon/on_attack_hand(mob/living/carbon/human/user, act_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
if(.) //was the attack blocked?
|
||||
return
|
||||
@@ -138,11 +120,15 @@
|
||||
ContactContractDisease(D)
|
||||
|
||||
if(lying && surgeries.len)
|
||||
if(user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM)
|
||||
if(act_intent == INTENT_HELP || act_intent == INTENT_DISARM)
|
||||
for(var/datum/surgery/S in surgeries)
|
||||
if(S.next_step(user, user.a_intent))
|
||||
if(S.next_step(user, act_intent))
|
||||
return TRUE
|
||||
|
||||
for(var/i in all_wounds)
|
||||
var/datum/wound/W = i
|
||||
if(W.try_handling(user))
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/attack_paw(mob/living/carbon/monkey/M)
|
||||
|
||||
@@ -159,15 +145,14 @@
|
||||
|
||||
if(M.a_intent == INTENT_HELP)
|
||||
help_shake_act(M)
|
||||
return 0
|
||||
return TRUE
|
||||
|
||||
. = ..()
|
||||
if(.) //successful monkey bite.
|
||||
for(var/thing in M.diseases)
|
||||
var/datum/disease/D = thing
|
||||
ForceContractDisease(D)
|
||||
return 1
|
||||
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/attack_slime(mob/living/simple_animal/slime/M)
|
||||
. = ..()
|
||||
@@ -306,12 +291,12 @@
|
||||
target_message = "<span class='notice'>[M] gives you a pat on the head to make you feel better!</span>")
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "headpat", /datum/mood_event/headpat)
|
||||
friendly_check = TRUE
|
||||
if(S?.can_wag_tail(src) && !dna.species.is_wagging_tail())
|
||||
var/static/list/many_tails = list("tail_human", "tail_lizard", "mam_tail")
|
||||
for(var/T in many_tails)
|
||||
if(S.mutant_bodyparts[T] && dna.features[T] != "None")
|
||||
emote("wag")
|
||||
break
|
||||
if(!(client?.prefs.cit_toggles & NO_AUTO_WAG))
|
||||
if(S?.can_wag_tail(src) && !dna.species.is_wagging_tail())
|
||||
var/static/list/many_tails = list("tail_human", "tail_lizard", "mam_tail")
|
||||
for(var/T in many_tails)
|
||||
if(S.mutant_bodyparts[T] && dna.features[T] != "None")
|
||||
emote("wag")
|
||||
|
||||
else if(check_zone(M.zone_selected) == BODY_ZONE_R_ARM || check_zone(M.zone_selected) == BODY_ZONE_L_ARM)
|
||||
M.visible_message( \
|
||||
@@ -408,7 +393,7 @@
|
||||
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
|
||||
return TRUE
|
||||
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>")
|
||||
@@ -478,3 +463,40 @@
|
||||
if (BP.status < 2)
|
||||
amount += BP.burn_dam
|
||||
return amount
|
||||
|
||||
/mob/living/carbon/proc/get_interaction_efficiency(zone)
|
||||
var/obj/item/bodypart/limb = get_bodypart(zone)
|
||||
if(!limb)
|
||||
return
|
||||
|
||||
/mob/living/carbon/send_item_attack_message(obj/item/I, mob/living/user, hit_area, obj/item/bodypart/hit_bodypart, totitemdamage)
|
||||
var/message_verb = "attacked"
|
||||
if(length(I.attack_verb))
|
||||
message_verb = "[pick(I.attack_verb)]"
|
||||
else if(!I.force)
|
||||
return
|
||||
|
||||
var/extra_wound_details = ""
|
||||
if(I.damtype == BRUTE && hit_bodypart.can_dismember())
|
||||
var/mangled_state = hit_bodypart.get_mangled_state()
|
||||
var/bio_state = get_biological_state()
|
||||
if(mangled_state == BODYPART_MANGLED_BOTH)
|
||||
extra_wound_details = ", threatening to sever it entirely"
|
||||
else if((mangled_state == BODYPART_MANGLED_FLESH && I.get_sharpness()) || (mangled_state & BODYPART_MANGLED_BONE && bio_state == BIO_JUST_BONE))
|
||||
extra_wound_details = ", [I.get_sharpness() == SHARP_EDGED ? "slicing" : "piercing"] through to the bone"
|
||||
else if((mangled_state == BODYPART_MANGLED_BONE && I.get_sharpness()) || (mangled_state & BODYPART_MANGLED_FLESH && bio_state == BIO_JUST_FLESH))
|
||||
extra_wound_details = ", [I.get_sharpness() == SHARP_EDGED ? "slicing" : "piercing"] at the remaining tissue"
|
||||
|
||||
var/message_hit_area = ""
|
||||
if(hit_area)
|
||||
message_hit_area = " in the [hit_area]"
|
||||
var/attack_message = "[src] is [message_verb][message_hit_area] with [I][extra_wound_details]!"
|
||||
var/attack_message_local = "You're [message_verb][message_hit_area] with [I][extra_wound_details]!"
|
||||
if(user in viewers(src, null))
|
||||
attack_message = "[user] [message_verb] [src][message_hit_area] with [I][extra_wound_details]!"
|
||||
attack_message_local = "[user] [message_verb] you[message_hit_area] with [I][extra_wound_details]!"
|
||||
if(user == src)
|
||||
attack_message_local = "You [message_verb] yourself[message_hit_area] with [I][extra_wound_details]"
|
||||
visible_message("<span class='danger'>[attack_message]</span>",\
|
||||
"<span class='userdanger'>[attack_message_local]</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
return TRUE
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
var/obj/item/head = null
|
||||
|
||||
var/obj/item/gloves = null //only used by humans
|
||||
var/obj/item/shoes = null //only used by humans.
|
||||
var/obj/item/clothing/shoes/shoes = null //only used by humans.
|
||||
var/obj/item/clothing/glasses/glasses = null //only used by humans.
|
||||
var/obj/item/ears = null //only used by humans.
|
||||
|
||||
@@ -64,3 +64,17 @@
|
||||
|
||||
var/drunkenness = 0 //Overall drunkenness - check handle_alcohol() in life.dm for effects
|
||||
var/tackling = FALSE //Whether or not we are tackling, this will prevent the knock into effects for carbons
|
||||
|
||||
/// All of the wounds a carbon has afflicted throughout their limbs
|
||||
var/list/all_wounds
|
||||
/// All of the scars a carbon has afflicted throughout their limbs
|
||||
var/list/all_scars
|
||||
|
||||
/// Protection (insulation) from the heat, Value 0-1 corresponding to the percentage of protection
|
||||
var/heat_protection = 0 // No heat protection
|
||||
/// Protection (insulation) from the cold, Value 0-1 corresponding to the percentage of protection
|
||||
var/cold_protection = 0 // No cold protection
|
||||
|
||||
/// Timer id of any transformation
|
||||
var/transformation_timer
|
||||
|
||||
|
||||
@@ -1,32 +1,33 @@
|
||||
|
||||
|
||||
/mob/living/carbon/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE)
|
||||
/mob/living/carbon/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = SHARP_NONE)
|
||||
SEND_SIGNAL(src, COMSIG_MOB_APPLY_DAMGE, damage, damagetype, def_zone)
|
||||
var/hit_percent = (100-blocked)/100
|
||||
if(!forced && hit_percent <= 0)
|
||||
return 0
|
||||
|
||||
var/obj/item/bodypart/BP = null
|
||||
if(isbodypart(def_zone)) //we specified a bodypart object
|
||||
BP = def_zone
|
||||
else
|
||||
if(!def_zone)
|
||||
def_zone = ran_zone(def_zone)
|
||||
BP = get_bodypart(check_zone(def_zone))
|
||||
if(!BP)
|
||||
BP = bodyparts[1]
|
||||
if(!spread_damage)
|
||||
if(isbodypart(def_zone)) //we specified a bodypart object
|
||||
BP = def_zone
|
||||
else
|
||||
if(!def_zone)
|
||||
def_zone = ran_zone(def_zone)
|
||||
BP = get_bodypart(check_zone(def_zone))
|
||||
if(!BP)
|
||||
BP = bodyparts[1]
|
||||
|
||||
var/damage_amount = forced ? damage : damage * hit_percent
|
||||
switch(damagetype)
|
||||
if(BRUTE)
|
||||
if(BP)
|
||||
if(damage > 0 ? BP.receive_damage(damage_amount) : BP.heal_damage(abs(damage_amount), 0))
|
||||
if(BP.receive_damage(damage_amount, 0, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness))
|
||||
update_damage_overlays()
|
||||
else //no bodypart, we deal damage with a more general method.
|
||||
adjustBruteLoss(damage_amount, forced = forced)
|
||||
if(BURN)
|
||||
if(BP)
|
||||
if(damage > 0 ? BP.receive_damage(0, damage_amount) : BP.heal_damage(0, abs(damage_amount)))
|
||||
if(BP.receive_damage(0, damage_amount, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness))
|
||||
update_damage_overlays()
|
||||
else
|
||||
adjustFireLoss(damage_amount, forced = forced)
|
||||
@@ -201,12 +202,12 @@
|
||||
//Damages ONE bodypart randomly selected from damagable ones.
|
||||
//It automatically updates damage overlays if necessary
|
||||
//It automatically updates health status
|
||||
/mob/living/carbon/take_bodypart_damage(brute = 0, burn = 0, stamina = 0)
|
||||
/mob/living/carbon/take_bodypart_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE, required_status, check_armor = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = SHARP_NONE)
|
||||
var/list/obj/item/bodypart/parts = get_damageable_bodyparts()
|
||||
if(!parts.len)
|
||||
return
|
||||
var/obj/item/bodypart/picked = pick(parts)
|
||||
if(picked.receive_damage(brute, burn, stamina))
|
||||
if(picked.receive_damage(brute, burn, stamina,check_armor ? run_armor_check(picked, (brute ? "melee" : burn ? "fire" : stamina ? "bullet" : null)) : FALSE, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness))
|
||||
update_damage_overlays()
|
||||
|
||||
//Heal MANY bodyparts, in random order
|
||||
@@ -234,12 +235,12 @@
|
||||
update_damage_overlays()
|
||||
update_stamina() //CIT CHANGE - makes sure update_stamina() always gets called after a health update
|
||||
|
||||
// damage MANY bodyparts, in random order
|
||||
/mob/living/carbon/take_overall_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE)
|
||||
/// damage MANY bodyparts, in random order
|
||||
/mob/living/carbon/take_overall_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE, required_status)
|
||||
if(status_flags & GODMODE)
|
||||
return //godmode
|
||||
|
||||
var/list/obj/item/bodypart/parts = get_damageable_bodyparts()
|
||||
var/list/obj/item/bodypart/parts = get_damageable_bodyparts(required_status)
|
||||
var/update = 0
|
||||
while(parts.len && (brute > 0 || burn > 0 || stamina > 0))
|
||||
var/obj/item/bodypart/picked = pick(parts)
|
||||
@@ -252,7 +253,7 @@
|
||||
var/stamina_was = picked.stamina_dam
|
||||
|
||||
|
||||
update |= picked.receive_damage(brute_per_part, burn_per_part, stamina_per_part, FALSE)
|
||||
update |= picked.receive_damage(brute_per_part, burn_per_part, stamina_per_part, FALSE, required_status, wound_bonus = CANT_WOUND) // disabling wounds from these for now cuz your entire body snapping cause your heart stopped would suck
|
||||
|
||||
brute = round(brute - (picked.brute_dam - brute_was), DAMAGE_PRECISION)
|
||||
burn = round(burn - (picked.burn_dam - burn_was), DAMAGE_PRECISION)
|
||||
@@ -265,45 +266,11 @@
|
||||
update_damage_overlays()
|
||||
update_stamina()
|
||||
|
||||
/* TO_REMOVE
|
||||
/mob/living/carbon/getOrganLoss(ORGAN_SLOT_BRAIN)
|
||||
. = 0
|
||||
var/obj/item/organ/brain/B = getorganslot(ORGAN_SLOT_BRAIN)
|
||||
if(B)
|
||||
. = B.get_brain_damage()
|
||||
|
||||
//Some sources of brain damage shouldn't be deadly
|
||||
/mob/living/carbon/adjustOrganLoss(ORGAN_SLOT_BRAIN, amount, maximum = BRAIN_DAMAGE_DEATH)
|
||||
if(status_flags & GODMODE)
|
||||
return FALSE
|
||||
var/prev_brainloss = getOrganLoss(ORGAN_SLOT_BRAIN)
|
||||
var/obj/item/organ/brain/B = getorganslot(ORGAN_SLOT_BRAIN)
|
||||
if(!B)
|
||||
return
|
||||
B.adjust_brain_damage(amount, maximum)
|
||||
if(amount <= 0) //cut this early
|
||||
return
|
||||
var/brainloss = getOrganLoss(ORGAN_SLOT_BRAIN)
|
||||
if(brainloss > BRAIN_DAMAGE_MILD)
|
||||
if(prob(amount * ((2 * (100 + brainloss - BRAIN_DAMAGE_MILD)) / 100))) //Base chance is the hit damage; for every point of damage past the threshold the chance is increased by 2%
|
||||
gain_trauma_type(BRAIN_TRAUMA_MILD)
|
||||
if(brainloss > BRAIN_DAMAGE_SEVERE)
|
||||
if(prob(amount * ((2 * (100 + brainloss - BRAIN_DAMAGE_SEVERE)) / 100))) //Base chance is the hit damage; for every point of damage past the threshold the chance is increased by 2%
|
||||
if(prob(20))
|
||||
gain_trauma_type(BRAIN_TRAUMA_SPECIAL)
|
||||
else
|
||||
gain_trauma_type(BRAIN_TRAUMA_SEVERE)
|
||||
|
||||
if(prev_brainloss < BRAIN_DAMAGE_MILD && brainloss >= BRAIN_DAMAGE_MILD)
|
||||
to_chat(src, "<span class='warning'>You feel lightheaded.</span>")
|
||||
else if(prev_brainloss < BRAIN_DAMAGE_SEVERE && brainloss >= BRAIN_DAMAGE_SEVERE)
|
||||
to_chat(src, "<span class='warning'>You feel less in control of your thoughts.</span>")
|
||||
else if(prev_brainloss < (BRAIN_DAMAGE_DEATH - 20) && brainloss >= (BRAIN_DAMAGE_DEATH - 20))
|
||||
to_chat(src, "<span class='warning'>You can feel your mind flickering on and off...</span>")
|
||||
|
||||
/mob/living/carbon/setBrainLoss(amount)
|
||||
var/obj/item/organ/brain/B = getorganslot(ORGAN_SLOT_BRAIN)
|
||||
if(B)
|
||||
var/adjusted_amount = amount - B.get_brain_damage()
|
||||
B.adjust_brain_damage(adjusted_amount, null)
|
||||
*/
|
||||
///Returns a list of bodyparts with wounds (in case someone has a wound on an otherwise fully healed limb)
|
||||
/mob/living/carbon/proc/get_wounded_bodyparts(brute = FALSE, burn = FALSE, stamina = FALSE, status)
|
||||
var/list/obj/item/bodypart/parts = list()
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
if(LAZYLEN(BP.wounds))
|
||||
parts += BP
|
||||
return parts
|
||||
|
||||
@@ -44,6 +44,9 @@
|
||||
msg += "<B>[t_He] [t_has] \a [icon2html(I, user)] [I] stuck to [t_his] [BP.name]!</B>\n"
|
||||
else
|
||||
msg += "<B>[t_He] [t_has] \a [icon2html(I, user)] [I] embedded in [t_his] [BP.name]!</B>\n"
|
||||
for(var/i in BP.wounds)
|
||||
var/datum/wound/W = i
|
||||
msg += "[W.get_examine_description(user)]\n"
|
||||
|
||||
for(var/X in disabled)
|
||||
var/obj/item/bodypart/BP = X
|
||||
@@ -99,6 +102,22 @@
|
||||
if(pulledby && pulledby.grab_state)
|
||||
msg += "[t_He] [t_is] restrained by [pulledby]'s grip.\n"
|
||||
|
||||
var/scar_severity = 0
|
||||
for(var/i in all_scars)
|
||||
var/datum/scar/S = i
|
||||
if(S.is_visible(user))
|
||||
scar_severity += S.severity
|
||||
|
||||
switch(scar_severity)
|
||||
if(1 to 2)
|
||||
msg += "<span class='smallnoticeital'>[t_He] [t_has] visible scarring, you can look again to take a closer look...</span>\n"
|
||||
if(3 to 4)
|
||||
msg += "<span class='notice'><i>[t_He] [t_has] several bad scars, you can look again to take a closer look...</i></span>\n"
|
||||
if(5 to 6)
|
||||
msg += "<span class='notice'><b><i>[t_He] [t_has] significantly disfiguring scarring, you can look again to take a closer look...</i></b></span>\n"
|
||||
if(7 to INFINITY)
|
||||
msg += "<span class='notice'><b><i>[t_He] [t_is] just absolutely fucked up, you can look again to take a closer look...</i></b></span>\n"
|
||||
|
||||
if(msg.len)
|
||||
. += "<span class='warning'>[msg.Join("")]</span>"
|
||||
|
||||
@@ -135,3 +154,25 @@
|
||||
. += "[t_He] look[p_s()] ecstatic."
|
||||
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, .)
|
||||
. += "*---------*</span>"
|
||||
|
||||
/mob/living/carbon/examine_more(mob/user)
|
||||
if(!all_scars)
|
||||
return ..()
|
||||
|
||||
var/list/visible_scars
|
||||
for(var/i in all_scars)
|
||||
var/datum/scar/S = i
|
||||
if(S.is_visible(user))
|
||||
LAZYADD(visible_scars, S)
|
||||
|
||||
if(!visible_scars)
|
||||
return ..()
|
||||
|
||||
var/msg = list("<span class='notice'><i>You examine [src] closer, and note the following...</i></span>")
|
||||
for(var/i in visible_scars)
|
||||
var/datum/scar/S = i
|
||||
var/scar_text = S.get_examine_description(user)
|
||||
if(scar_text)
|
||||
msg += "[scar_text]"
|
||||
|
||||
return msg
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
// depending on the species, it will run the corresponding apply_damage code there
|
||||
/mob/living/carbon/human/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = SHARP_NONE)
|
||||
return dna.species.apply_damage(damage, damagetype, def_zone, blocked, src, forced, spread_damage, wound_bonus, bare_wound_bonus, sharpness)
|
||||
|
||||
/mob/living/carbon/human/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE)
|
||||
// depending on the species, it will run the corresponding apply_damage code there
|
||||
return dna.species.apply_damage(damage, damagetype, def_zone, blocked, src, forced)
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
status_flags = GODMODE|CANPUSH
|
||||
mouse_drag_pointer = MOUSE_INACTIVE_POINTER
|
||||
var/in_use = FALSE
|
||||
vore_flags = NO_VORE
|
||||
|
||||
/mob/living/carbon/human/vore
|
||||
vore_flags = DEVOURABLE | DIGESTABLE | FEEDING
|
||||
|
||||
INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
|
||||
|
||||
@@ -17,7 +21,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
|
||||
/mob/living/carbon/human/dummy/proc/wipe_state()
|
||||
delete_equipment()
|
||||
icon_render_key = null
|
||||
cut_overlays(TRUE)
|
||||
cut_overlays()
|
||||
|
||||
//Inefficient pooling/caching way.
|
||||
GLOBAL_LIST_EMPTY(human_dummy_list)
|
||||
@@ -43,6 +47,5 @@ GLOBAL_LIST_EMPTY(dummy_mob_list)
|
||||
return
|
||||
var/mob/living/carbon/human/dummy/D = GLOB.human_dummy_list[slotnumber]
|
||||
if(istype(D))
|
||||
D.set_species(/datum/species/human,icon_update = TRUE, pref_load = TRUE) //for some fucking reason, if you don't change the species every time, some species will dafault certain things when it's their own species on the mannequin two times in a row, like lizards losing spines and tails setting to smooth. If you can find a fix for this that isn't this, good on you
|
||||
D.wipe_state()
|
||||
D.in_use = FALSE
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
message = "cries."
|
||||
emote_type = EMOTE_AUDIBLE
|
||||
|
||||
/datum/emote/living/carbon/human/cry/run_emote(mob/user, params)
|
||||
. = ..()
|
||||
if(. && isipcperson(user))
|
||||
do_fake_sparks(5,FALSE,user)
|
||||
|
||||
/datum/emote/living/carbon/human/dap
|
||||
key = "dap"
|
||||
key_third_person = "daps"
|
||||
@@ -187,3 +192,71 @@
|
||||
key_third_person = "chimes"
|
||||
message = "chimes."
|
||||
sound = 'sound/machines/chime.ogg'
|
||||
|
||||
//rock paper scissors emote handling
|
||||
/mob/living/carbon/human/proc/beginRockPaperScissors(var/chosen_move)
|
||||
GLOB.rockpaperscissors_players[src] = list(chosen_move, ROCKPAPERSCISSORS_NOT_DECIDED)
|
||||
do_after_advanced(src, ROCKPAPERSCISSORS_TIME_LIMIT, src, DO_AFTER_REQUIRES_USER_ON_TURF|DO_AFTER_NO_COEFFICIENT|DO_AFTER_NO_PROGRESSBAR|DO_AFTER_DISALLOW_MOVING_ABSOLUTE_USER, CALLBACK(src, .proc/rockpaperscissors_tick))
|
||||
var/new_entry = GLOB.rockpaperscissors_players[src]
|
||||
if(new_entry[2] == ROCKPAPERSCISSORS_NOT_DECIDED)
|
||||
to_chat(src, "You put your hand back down.")
|
||||
GLOB.rockpaperscissors_players -= src
|
||||
|
||||
/mob/living/carbon/human/proc/rockpaperscissors_tick() //called every cycle of the progress bar for rock paper scissors while waiting for an opponent
|
||||
var/mob/living/carbon/human/opponent
|
||||
for(var/mob/living/carbon/human/potential_opponent in (GLOB.rockpaperscissors_players - src)) //dont play against yourself
|
||||
if(get_dist(src, potential_opponent) <= ROCKPAPERSCISSORS_RANGE)
|
||||
opponent = potential_opponent
|
||||
break
|
||||
if(opponent)
|
||||
//we found an opponent before they found us
|
||||
var/move_to_number = list("rock" = 0, "paper" = 1, "scissors" = 2)
|
||||
var/our_move = move_to_number[GLOB.rockpaperscissors_players[src][1]]
|
||||
var/their_move = move_to_number[GLOB.rockpaperscissors_players[opponent][1]]
|
||||
var/result_us = ROCKPAPERSCISSORS_WIN
|
||||
var/result_them = ROCKPAPERSCISSORS_LOSE
|
||||
if(our_move == their_move)
|
||||
result_us = ROCKPAPERSCISSORS_TIE
|
||||
result_them = ROCKPAPERSCISSORS_TIE
|
||||
else
|
||||
if(((our_move + 1) % 3) == their_move)
|
||||
result_us = ROCKPAPERSCISSORS_LOSE
|
||||
result_them = ROCKPAPERSCISSORS_WIN
|
||||
//we decided our results so set them in the list
|
||||
GLOB.rockpaperscissors_players[src][2] = result_us
|
||||
GLOB.rockpaperscissors_players[opponent][2] = result_them
|
||||
|
||||
//show what happened
|
||||
src.visible_message("<b>[src]</b> makes [GLOB.rockpaperscissors_players[src][1]] with their hand!")
|
||||
opponent.visible_message("<b>[opponent]</b> makes [GLOB.rockpaperscissors_players[opponent][1]] with their hands!")
|
||||
switch(result_us)
|
||||
if(ROCKPAPERSCISSORS_TIE)
|
||||
src.visible_message("It was a tie!")
|
||||
if(ROCKPAPERSCISSORS_WIN)
|
||||
src.visible_message("<b>[src]</b> wins!")
|
||||
if(ROCKPAPERSCISSORS_LOSE)
|
||||
src.visible_message("<b>[opponent]</b> wins!")
|
||||
|
||||
//make the progress bar end so that each player can handle the result
|
||||
return DO_AFTER_STOP
|
||||
|
||||
//no opponent was found, so keep searching
|
||||
return DO_AFTER_PROCEED
|
||||
|
||||
//the actual emotes
|
||||
/datum/emote/living/carbon/human/rockpaperscissors
|
||||
message = "is attempting to play rock paper scissors!"
|
||||
|
||||
/datum/emote/living/carbon/human/rockpaperscissors/rock
|
||||
key = "rock"
|
||||
|
||||
/datum/emote/living/carbon/human/rockpaperscissors/paper
|
||||
key = "paper"
|
||||
|
||||
/datum/emote/living/carbon/human/rockpaperscissors/scissors
|
||||
key = "scissors"
|
||||
|
||||
/datum/emote/living/carbon/human/rockpaperscissors/run_emote(mob/living/carbon/human/user, params)
|
||||
if(!(user in GLOB.rockpaperscissors_players)) //no using the emote again while already playing!
|
||||
. = ..()
|
||||
user.beginRockPaperScissors(key)
|
||||
|
||||
@@ -163,16 +163,19 @@
|
||||
msg += "<B>[t_He] [t_has] \a [icon2html(I, user)] [I] stuck to [t_his] [BP.name]!</B>\n"
|
||||
else
|
||||
msg += "<B>[t_He] [t_has] \a [icon2html(I, user)] [I] embedded in [t_his] [BP.name]!</B>\n"
|
||||
for(var/i in BP.wounds)
|
||||
var/datum/wound/iter_wound = i
|
||||
msg += "[iter_wound.get_examine_description(user)]\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"
|
||||
|
||||
if(BP.is_disabled() != BODYPART_DISABLED_WOUND) // skip if it's disabled by a wound (cuz we'll be able to see the bone sticking out!)
|
||||
if(!(BP.get_damage(include_stamina = FALSE) >= BP.max_damage)) //we don't care if it's stamcritted
|
||||
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
|
||||
@@ -246,16 +249,52 @@
|
||||
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"
|
||||
var/apparent_blood_volume = blood_volume
|
||||
if(dna.species.use_skintones && skin_tone == "albino")
|
||||
apparent_blood_volume -= 150 // enough to knock you down one tier
|
||||
switch(apparent_blood_volume)
|
||||
if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE)
|
||||
msg += "[t_He] [t_has] pale skin.\n"
|
||||
if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY)
|
||||
msg += "<b>[t_He] look[p_s()] like pale death.</b>\n"
|
||||
if(-INFINITY to BLOOD_VOLUME_BAD)
|
||||
msg += "<span class='deadsay'><b>[t_He] resemble[p_s()] a crushed, empty juice pouch.</b></span>\n"
|
||||
|
||||
if(bleedsuppress)
|
||||
msg += "[t_He] [t_is] bandaged with something.\n"
|
||||
else if(bleed_rate)
|
||||
if(bleed_rate >= 8) //8 is the rate at which heparin causes you to bleed
|
||||
msg += "<b>[t_He] [t_is] bleeding uncontrollably!</b>\n"
|
||||
msg += "[t_He] [t_is] embued with a power that defies bleeding.\n" // only statues and highlander sword can cause this so whatever
|
||||
else if(is_bleeding())
|
||||
var/list/obj/item/bodypart/bleeding_limbs = list()
|
||||
|
||||
for(var/i in bodyparts)
|
||||
var/obj/item/bodypart/BP = i
|
||||
if(BP.get_bleed_rate())
|
||||
bleeding_limbs += BP
|
||||
|
||||
var/num_bleeds = LAZYLEN(bleeding_limbs)
|
||||
var/list/bleed_text
|
||||
if(appears_dead)
|
||||
bleed_text = list("<span class='deadsay'><B>Blood is visible in [t_his] open")
|
||||
else
|
||||
msg += "<B>[t_He] [t_is] bleeding!</B>\n"
|
||||
bleed_text = list("<B>[t_He] [t_is] bleeding from [t_his]")
|
||||
|
||||
switch(num_bleeds)
|
||||
if(1 to 2)
|
||||
bleed_text += " [bleeding_limbs[1].name][num_bleeds == 2 ? " and [bleeding_limbs[2].name]" : ""]"
|
||||
if(3 to INFINITY)
|
||||
for(var/i in 1 to (num_bleeds - 1))
|
||||
var/obj/item/bodypart/BP = bleeding_limbs[i]
|
||||
bleed_text += " [BP.name],"
|
||||
bleed_text += " and [bleeding_limbs[num_bleeds].name]"
|
||||
|
||||
|
||||
if(appears_dead)
|
||||
bleed_text += ", but it has pooled and is not flowing.</span></B>\n"
|
||||
else
|
||||
if(reagents.has_reagent(/datum/reagent/toxin/heparin))
|
||||
bleed_text += " incredibly quickly"
|
||||
|
||||
bleed_text += "!</B>\n"
|
||||
msg += bleed_text.Join()
|
||||
|
||||
if(reagents.has_reagent(/datum/reagent/teslium))
|
||||
msg += "[t_He] [t_is] emitting a gentle blue glow!\n"
|
||||
@@ -331,6 +370,21 @@
|
||||
if(digitalcamo)
|
||||
msg += "[t_He] [t_is] moving [t_his] body in an unnatural and blatantly inhuman manner.\n"
|
||||
|
||||
var/scar_severity = 0
|
||||
for(var/i in all_scars)
|
||||
var/datum/scar/S = i
|
||||
if(S.is_visible(user))
|
||||
scar_severity += S.severity
|
||||
|
||||
switch(scar_severity)
|
||||
if(1 to 2)
|
||||
msg += "<span class='smallnoticeital'>[t_He] [t_has] visible scarring, you can look again to take a closer look...</span>\n"
|
||||
if(3 to 4)
|
||||
msg += "<span class='notice'><i>[t_He] [t_has] several bad scars, you can look again to take a closer look...</i></span>\n"
|
||||
if(5 to 6)
|
||||
msg += "<span class='notice'><b><i>[t_He] [t_has] significantly disfiguring scarring, you can look again to take a closer look...</i></b></span>\n"
|
||||
if(7 to INFINITY)
|
||||
msg += "<span class='notice'><b><i>[t_He] [t_is] just absolutely fucked up, you can look again to take a closer look...</i></b></span>\n"
|
||||
|
||||
if (length(msg))
|
||||
. += "<span class='warning'>[msg.Join("")]</span>"
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
enable_intentional_sprint_mode()
|
||||
|
||||
RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /atom.proc/clean_blood)
|
||||
GLOB.human_list += src
|
||||
|
||||
|
||||
/mob/living/carbon/human/ComponentInitialize()
|
||||
@@ -47,6 +48,7 @@
|
||||
/mob/living/carbon/human/Destroy()
|
||||
QDEL_NULL(physiology)
|
||||
QDEL_NULL_LIST(vore_organs) // CITADEL EDIT belly stuff
|
||||
GLOB.human_list -= src
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/prepare_data_huds()
|
||||
@@ -152,8 +154,12 @@
|
||||
|
||||
dat += "<tr><td> </td></tr>"
|
||||
|
||||
dat += "<tr><td><B>Exosuit:</B></td><td><A href='?src=[REF(src)];item=[SLOT_WEAR_SUIT]'>[(wear_suit && !(wear_suit.item_flags & ABSTRACT)) ? wear_suit : "<font color=grey>Empty</font>"]</A></td></tr>"
|
||||
dat += "<tr><td><B>Exosuit:</B></td><td><A href='?src=[REF(src)];item=[SLOT_WEAR_SUIT]'>[(wear_suit && !(wear_suit.item_flags & ABSTRACT)) ? wear_suit : "<font color=grey>Empty</font>"]</A>"
|
||||
if(wear_suit)
|
||||
if(istype(wear_suit, /obj/item/clothing/suit/space/hardsuit))
|
||||
var/hardsuit_head = head && istype(head, /obj/item/clothing/head/helmet/space/hardsuit)
|
||||
dat += " <A href='?src=[REF(src)];toggle_helmet=[SLOT_WEAR_SUIT]'>[hardsuit_head ? "Retract Helmet" : "Extend Helmet"]</A>"
|
||||
dat += "</td></tr>"
|
||||
dat += "<tr><td> ↳<B>Suit Storage:</B></td><td><A href='?src=[REF(src)];item=[SLOT_S_STORE]'>[(s_store && !(s_store.item_flags & ABSTRACT)) ? s_store : "<font color=grey>Empty</font>"]</A>"
|
||||
if(has_breathable_mask && istype(s_store, /obj/item/tank))
|
||||
dat += " <A href='?src=[REF(src)];internal=[SLOT_S_STORE]'>[internal ? "Disable Internals" : "Set Internals"]</A>"
|
||||
@@ -164,7 +170,11 @@
|
||||
if(SLOT_SHOES in obscured)
|
||||
dat += "<tr><td><font color=grey><B>Shoes:</B></font></td><td><font color=grey>Obscured</font></td></tr>"
|
||||
else
|
||||
dat += "<tr><td><B>Shoes:</B></td><td><A href='?src=[REF(src)];item=[SLOT_SHOES]'>[(shoes && !(shoes.item_flags & ABSTRACT)) ? shoes : "<font color=grey>Empty</font>"]</A></td></tr>"
|
||||
dat += "<tr><td><B>Shoes:</B></td><td><A href='?src=[REF(src)];item=[SLOT_SHOES]'>[(shoes && !(shoes.item_flags & ABSTRACT)) ? shoes : "<font color=grey>Empty</font>"]</A>"
|
||||
if(shoes && shoes.can_be_tied && shoes.tied != SHOES_KNOTTED)
|
||||
dat += " <A href='?src=[REF(src)];shoes=[SLOT_SHOES]'>[shoes.tied ? "Untie shoes" : "Knot shoes"]</A>"
|
||||
|
||||
dat += "</td></tr>"
|
||||
|
||||
if(SLOT_GLOVES in obscured)
|
||||
dat += "<tr><td><font color=grey><B>Gloves:</B></font></td><td><font color=grey>Obscured</font></td></tr>"
|
||||
@@ -222,13 +232,28 @@
|
||||
return
|
||||
SEND_SIGNAL(src, COMSIG_CARBON_EMBED_RIP, I, L)
|
||||
return
|
||||
|
||||
if(href_list["toggle_helmet"])
|
||||
if(!istype(head, /obj/item/clothing/head/helmet/space/hardsuit))
|
||||
return
|
||||
var/obj/item/clothing/head/helmet/space/hardsuit/hardsuit_head = head
|
||||
visible_message("<span class='danger'>[usr] tries to [hardsuit_head ? "retract" : "extend"] [src]'s helmet.</span>", \
|
||||
"<span class='userdanger'>[usr] tries to [hardsuit_head ? "retract" : "extend"] [src]'s helmet.</span>", \
|
||||
target = usr, target_message = "<span class='danger'>You try to [hardsuit_head ? "retract" : "extend"] [src]'s helmet.</span>")
|
||||
if(!do_mob(usr, src, hardsuit_head ? head.strip_delay : POCKET_STRIP_DELAY))
|
||||
return
|
||||
if(!istype(wear_suit, /obj/item/clothing/suit/space/hardsuit) || (hardsuit_head ? (!head || head != hardsuit_head) : head))
|
||||
return
|
||||
var/obj/item/clothing/suit/space/hardsuit/hardsuit = wear_suit //This should be an hardsuit given all our checks
|
||||
if(hardsuit.ToggleHelmet(FALSE))
|
||||
visible_message("<span class='danger'>[usr] [hardsuit_head ? "retract" : "extend"] [src]'s helmet</span>", \
|
||||
"<span class='userdanger'>[usr] [hardsuit_head ? "retract" : "extend"] [src]'s helmet</span>", \
|
||||
target = usr, target_message = "<span class='danger'>You [hardsuit_head ? "retract" : "extend"] [src]'s helmet.</span>")
|
||||
return
|
||||
if(href_list["item"])
|
||||
var/slot = text2num(href_list["item"])
|
||||
if(slot in check_obscured_slots())
|
||||
to_chat(usr, "<span class='warning'>You can't reach that! Something is covering it.</span>")
|
||||
return
|
||||
|
||||
if(href_list["pockets"])
|
||||
var/strip_mod = 1
|
||||
var/strip_silence = FALSE
|
||||
@@ -273,6 +298,12 @@
|
||||
if (!strip_silence)
|
||||
to_chat(src, "<span class='warning'>You feel your [pocket_side] pocket being fumbled with!</span>")
|
||||
|
||||
if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY, null, FALSE))
|
||||
// separate from first canusetopic
|
||||
var/mob/living/user = usr
|
||||
if(istype(user) && href_list["shoes"] && (user.mobility_flags & MOBILITY_USE)) // we need to be on the ground, so we'll be a bit looser
|
||||
shoes.handle_tying(usr)
|
||||
|
||||
..() //CITADEL CHANGE - removes a tab from behind this ..() so that flavortext can actually be examined
|
||||
|
||||
|
||||
@@ -369,7 +400,7 @@
|
||||
// Checks the user has security clearence before allowing them to change arrest status via hud, comment out to enable all access
|
||||
var/allowed_access = null
|
||||
var/obj/item/clothing/glasses/G = H.glasses
|
||||
if (!(G.obj_flags |= EMAGGED))
|
||||
if (!(G.obj_flags & EMAGGED))
|
||||
if(H.wear_id)
|
||||
var/list/access = H.wear_id.GetAccess()
|
||||
if(ACCESS_SEC_DOORS in access)
|
||||
@@ -511,33 +542,15 @@
|
||||
// Might need re-wording.
|
||||
to_chat(user, "<span class='alert'>There is no exposed flesh or thin material [above_neck(target_zone) ? "on [p_their()] head" : "on [p_their()] body"].</span>")
|
||||
|
||||
/mob/living/carbon/human/proc/check_obscured_slots()
|
||||
var/list/obscured = list()
|
||||
|
||||
/mob/living/carbon/human/check_obscured_slots()
|
||||
. = ..()
|
||||
if(wear_suit)
|
||||
if(wear_suit.flags_inv & HIDEGLOVES)
|
||||
obscured |= SLOT_GLOVES
|
||||
LAZYOR(., SLOT_GLOVES)
|
||||
if(wear_suit.flags_inv & HIDEJUMPSUIT)
|
||||
obscured |= SLOT_W_UNIFORM
|
||||
LAZYOR(., SLOT_W_UNIFORM)
|
||||
if(wear_suit.flags_inv & HIDESHOES)
|
||||
obscured |= SLOT_SHOES
|
||||
|
||||
if(head)
|
||||
if(head.flags_inv & HIDEMASK)
|
||||
obscured |= SLOT_WEAR_MASK
|
||||
if(head.flags_inv & HIDEEYES)
|
||||
obscured |= SLOT_GLASSES
|
||||
if(head.flags_inv & HIDEEARS)
|
||||
obscured |= SLOT_EARS
|
||||
|
||||
if(wear_mask)
|
||||
if(wear_mask.flags_inv & HIDEEYES)
|
||||
obscured |= SLOT_GLASSES
|
||||
|
||||
if(obscured.len)
|
||||
return obscured
|
||||
else
|
||||
return null
|
||||
LAZYOR(., SLOT_SHOES)
|
||||
|
||||
/mob/living/carbon/human/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null)
|
||||
if(judgement_criteria & JUDGE_EMAGGED)
|
||||
@@ -732,8 +745,7 @@
|
||||
|
||||
/mob/living/carbon/human/resist_restraints()
|
||||
if(wear_suit && wear_suit.breakouttime)
|
||||
changeNext_move(CLICK_CD_BREAKOUT)
|
||||
last_special = world.time + CLICK_CD_BREAKOUT
|
||||
MarkResistTime()
|
||||
cuff_resist(wear_suit)
|
||||
else
|
||||
..()
|
||||
@@ -982,7 +994,7 @@
|
||||
if(target.incapacitated(FALSE, TRUE) || incapacitated(FALSE, TRUE))
|
||||
target.visible_message("<span class='warning'>[target] can't hang onto [src]!</span>")
|
||||
return
|
||||
buckle_mob(target, TRUE, TRUE, FALSE, 0, 2, FALSE)
|
||||
buckle_mob(target, TRUE, TRUE, FALSE, 1, 2, FALSE)
|
||||
else
|
||||
visible_message("<span class='warning'>[target] fails to climb onto [src]!</span>")
|
||||
else
|
||||
@@ -1028,15 +1040,9 @@
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/human/proc/clear_shove_slowdown()
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/shove)
|
||||
var/active_item = get_active_held_item()
|
||||
if(is_type_in_typecache(active_item, GLOB.shove_disarming_types))
|
||||
visible_message("<span class='warning'>[src.name] regains their grip on \the [active_item]!</span>", "<span class='warning'>You regain your grip on \the [active_item]</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
|
||||
/mob/living/carbon/human/updatehealth()
|
||||
. = ..()
|
||||
|
||||
dna?.species.spec_updatehealth(src)
|
||||
if(HAS_TRAIT(src, TRAIT_IGNORESLOWDOWN)) //if we want to ignore slowdown from damage and equipment
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying)
|
||||
@@ -1054,10 +1060,21 @@
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying)
|
||||
|
||||
|
||||
/mob/living/carbon/human/do_after_coefficent()
|
||||
. = ..()
|
||||
. *= physiology.do_after_speed
|
||||
|
||||
/mob/living/carbon/human/is_bleeding()
|
||||
if(NOBLOOD in dna.species.species_traits || bleedsuppress)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/get_total_bleed_rate()
|
||||
if(NOBLOOD in dna.species.species_traits)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/species
|
||||
var/race = null
|
||||
|
||||
@@ -1182,6 +1199,9 @@
|
||||
/mob/living/carbon/human/species/lizard
|
||||
race = /datum/species/lizard
|
||||
|
||||
/mob/living/carbon/human/species/ethereal
|
||||
race = /datum/species/ethereal
|
||||
|
||||
/mob/living/carbon/human/species/lizard/ashwalker
|
||||
race = /datum/species/lizard/ashwalker
|
||||
|
||||
|
||||
@@ -34,6 +34,19 @@
|
||||
protection += physiology.armor.getRating(d_type)
|
||||
return protection
|
||||
|
||||
///Get all the clothing on a specific body part
|
||||
/mob/living/carbon/human/proc/clothingonpart(obj/item/bodypart/def_zone)
|
||||
var/list/covering_part = list()
|
||||
var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform, back, gloves, shoes, belt, s_store, glasses, ears, wear_id, wear_neck) //Everything but pockets. Pockets are l_store and r_store. (if pockets were allowed, putting something armored, gloves or hats for example, would double up on the armor)
|
||||
for(var/bp in body_parts)
|
||||
if(!bp)
|
||||
continue
|
||||
if(bp && istype(bp , /obj/item/clothing))
|
||||
var/obj/item/clothing/C = bp
|
||||
if(C.body_parts_covered & def_zone.body_part)
|
||||
covering_part += C
|
||||
return covering_part
|
||||
|
||||
/mob/living/carbon/human/on_hit(obj/item/projectile/P)
|
||||
if(dna && dna.species)
|
||||
dna.species.on_hit(P, src)
|
||||
@@ -106,18 +119,21 @@
|
||||
visible_message("<span class='danger'>[user] [hulk_verb_continous] [src]!</span>", \
|
||||
"<span class='userdanger'>[user] [hulk_verb_continous] you!</span>", null, COMBAT_MESSAGE_RANGE, null, user,
|
||||
"<span class='danger'>You [hulk_verb_simple] [src]!</span>")
|
||||
adjustBruteLoss(15)
|
||||
apply_damage(15, BRUTE, wound_bonus=10)
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/attack_hand(mob/user)
|
||||
/mob/living/carbon/human/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
if(.) //To allow surgery to return properly.
|
||||
return
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
dna.species.spec_attack_hand(H, src)
|
||||
dna.species.spec_attack_hand(H, src, null, act_intent, unarmed_attack_flags)
|
||||
|
||||
/mob/living/carbon/human/attack_paw(mob/living/carbon/monkey/M)
|
||||
if(!M.CheckActionCooldown(CLICK_CD_MELEE))
|
||||
return
|
||||
M.DelayNextAction()
|
||||
var/dam_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
|
||||
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
|
||||
if(!affecting)
|
||||
@@ -217,16 +233,17 @@
|
||||
if(!affecting)
|
||||
affecting = get_bodypart(BODY_ZONE_CHEST)
|
||||
var/armor = run_armor_check(affecting, "melee", armour_penetration = M.armour_penetration)
|
||||
apply_damage(damage, M.melee_damage_type, affecting, armor)
|
||||
|
||||
apply_damage(damage, M.melee_damage_type, affecting, armor, wound_bonus = M.wound_bonus, bare_wound_bonus = M.bare_wound_bonus, sharpness = M.sharpness)
|
||||
|
||||
/mob/living/carbon/human/attack_slime(mob/living/simple_animal/slime/M)
|
||||
. = ..()
|
||||
if(!.) //unsuccessful slime attack
|
||||
return
|
||||
var/damage = rand(5, 25)
|
||||
var/wound_mod = -45 // 25^1.4=90, 90-45=45
|
||||
if(M.is_adult)
|
||||
damage = rand(10, 35)
|
||||
wound_mod = -90 // 35^1.4=145, 145-90=55
|
||||
|
||||
var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
|
||||
if(!dam_zone) //Dismemberment successful
|
||||
@@ -236,7 +253,7 @@
|
||||
if(!affecting)
|
||||
affecting = get_bodypart(BODY_ZONE_CHEST)
|
||||
var/armor_block = run_armor_check(affecting, "melee")
|
||||
apply_damage(damage, BRUTE, affecting, armor_block)
|
||||
apply_damage(damage, BRUTE, affecting, armor_block, wound_bonus=wound_mod)
|
||||
|
||||
/mob/living/carbon/human/mech_melee_attack(obj/mecha/M)
|
||||
if(M.occupant.a_intent == INTENT_HARM)
|
||||
@@ -282,10 +299,10 @@
|
||||
|
||||
|
||||
/mob/living/carbon/human/ex_act(severity, target, origin)
|
||||
if(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src))
|
||||
if(TRAIT_BOMBIMMUNE in dna.species.species_traits)
|
||||
return
|
||||
..()
|
||||
if (!severity)
|
||||
if (!severity || QDELETED(src))
|
||||
return
|
||||
var/brute_loss = 0
|
||||
var/burn_loss = 0
|
||||
@@ -319,7 +336,8 @@
|
||||
if (!istype(ears, /obj/item/clothing/ears/earmuffs))
|
||||
adjustEarDamage(30, 120)
|
||||
Unconscious(20) //short amount of time for follow up attacks against elusive enemies like wizards
|
||||
Knockdown(200 - (bomb_armor * 1.6)) //between ~4 and ~20 seconds of knockdown depending on bomb armor
|
||||
Knockdown((200 - (bomb_armor * 1.6)) / 4) //between ~1 and ~5 seconds of knockdown depending on bomb armor
|
||||
adjustStaminaLoss(brute_loss)
|
||||
|
||||
if(EXPLODE_LIGHT)
|
||||
brute_loss = 30
|
||||
@@ -328,7 +346,8 @@
|
||||
damage_clothes(max(50 - bomb_armor, 0), BRUTE, "bomb")
|
||||
if (!istype(ears, /obj/item/clothing/ears/earmuffs))
|
||||
adjustEarDamage(15,60)
|
||||
Knockdown(160 - (bomb_armor * 1.6)) //100 bomb armor will prevent knockdown altogether
|
||||
Knockdown((160 - (bomb_armor * 1.6)) / 4) //100 bomb armor will prevent knockdown altogether
|
||||
adjustStaminaLoss(brute_loss)
|
||||
|
||||
take_overall_damage(brute_loss,burn_loss)
|
||||
|
||||
@@ -626,6 +645,20 @@
|
||||
no_damage = TRUE
|
||||
to_send += "\t <span class='[no_damage ? "notice" : "warning"]'>Your [LB.name] [HAS_TRAIT(src, TRAIT_SELF_AWARE) ? "has" : "is"] [status].</span>\n"
|
||||
|
||||
for(var/thing in LB.wounds)
|
||||
var/datum/wound/W = thing
|
||||
var/msg
|
||||
switch(W.severity)
|
||||
if(WOUND_SEVERITY_TRIVIAL)
|
||||
msg = "\t <span class='danger'>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)].</span>"
|
||||
if(WOUND_SEVERITY_MODERATE)
|
||||
msg = "\t <span class='warning'>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!</span>"
|
||||
if(WOUND_SEVERITY_SEVERE)
|
||||
msg = "\t <span class='warning'><b>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!</b></span>"
|
||||
if(WOUND_SEVERITY_CRITICAL)
|
||||
msg = "\t <span class='warning'><b>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!!</b></span>"
|
||||
to_chat(src, msg)
|
||||
|
||||
for(var/obj/item/I in LB.embedded_objects)
|
||||
if(I.isEmbedHarmless())
|
||||
to_chat(src, "\t <a href='?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>There is \a [I] stuck to your [LB.name]!</a>")
|
||||
@@ -635,8 +668,25 @@
|
||||
for(var/t in missing)
|
||||
to_send += "<span class='boldannounce'>Your [parse_zone(t)] is missing!</span>\n"
|
||||
|
||||
if(bleed_rate)
|
||||
to_send += "<span class='danger'>You are bleeding!</span>\n"
|
||||
if(is_bleeding())
|
||||
var/list/obj/item/bodypart/bleeding_limbs = list()
|
||||
for(var/i in bodyparts)
|
||||
var/obj/item/bodypart/BP = i
|
||||
if(BP.get_bleed_rate())
|
||||
bleeding_limbs += BP
|
||||
|
||||
var/num_bleeds = LAZYLEN(bleeding_limbs)
|
||||
var/bleed_text = "<span class='danger'>You are bleeding from your"
|
||||
switch(num_bleeds)
|
||||
if(1 to 2)
|
||||
bleed_text += " [bleeding_limbs[1].name][num_bleeds == 2 ? " and [bleeding_limbs[2].name]" : ""]"
|
||||
if(3 to INFINITY)
|
||||
for(var/i in 1 to (num_bleeds - 1))
|
||||
var/obj/item/bodypart/BP = bleeding_limbs[i]
|
||||
bleed_text += " [BP.name],"
|
||||
bleed_text += " and [bleeding_limbs[num_bleeds].name]"
|
||||
bleed_text += "!</span>"
|
||||
to_chat(src, bleed_text)
|
||||
if(getStaminaLoss())
|
||||
if(getStaminaLoss() > 30)
|
||||
to_send += "<span class='info'>You're completely exhausted.</span>\n"
|
||||
@@ -729,6 +779,89 @@
|
||||
|
||||
..()
|
||||
|
||||
/mob/living/carbon/human/check_self_for_injuries()
|
||||
if(stat == DEAD || stat == UNCONSCIOUS)
|
||||
return
|
||||
|
||||
visible_message("<span class='notice'>[src] examines [p_them()]self.</span>", \
|
||||
"<span class='notice'>You check yourself for injuries.</span>")
|
||||
|
||||
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)
|
||||
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/LB = X
|
||||
missing -= LB.body_zone
|
||||
if(LB.is_pseudopart) //don't show injury text for fake bodyparts; ie chainsaw arms or synthetic armblades
|
||||
continue
|
||||
var/self_aware = FALSE
|
||||
if(HAS_TRAIT(src, TRAIT_SELF_AWARE))
|
||||
self_aware = TRUE
|
||||
var/limb_max_damage = LB.max_damage
|
||||
var/status = ""
|
||||
var/brutedamage = LB.brute_dam
|
||||
var/burndamage = LB.burn_dam
|
||||
if(hallucination)
|
||||
if(prob(30))
|
||||
brutedamage += rand(30,40)
|
||||
if(prob(30))
|
||||
burndamage += rand(30,40)
|
||||
|
||||
if(HAS_TRAIT(src, TRAIT_SELF_AWARE))
|
||||
status = "[brutedamage] brute damage and [burndamage] burn damage"
|
||||
if(!brutedamage && !burndamage)
|
||||
status = "no damage"
|
||||
|
||||
else
|
||||
if(brutedamage > 0)
|
||||
status = LB.light_brute_msg
|
||||
if(brutedamage > (limb_max_damage*0.4))
|
||||
status = LB.medium_brute_msg
|
||||
if(brutedamage > (limb_max_damage*0.8))
|
||||
status = LB.heavy_brute_msg
|
||||
if(brutedamage > 0 && burndamage > 0)
|
||||
status += " and "
|
||||
|
||||
if(burndamage > (limb_max_damage*0.8))
|
||||
status += LB.heavy_burn_msg
|
||||
else if(burndamage > (limb_max_damage*0.2))
|
||||
status += LB.medium_burn_msg
|
||||
else if(burndamage > 0)
|
||||
status += LB.light_burn_msg
|
||||
|
||||
if(status == "")
|
||||
status = "OK"
|
||||
var/no_damage
|
||||
if(status == "OK" || status == "no damage")
|
||||
no_damage = TRUE
|
||||
var/isdisabled = " "
|
||||
if(LB.is_disabled())
|
||||
isdisabled = " is disabled "
|
||||
if(no_damage)
|
||||
isdisabled += " but otherwise "
|
||||
else
|
||||
isdisabled += " and "
|
||||
to_chat(src, "\t <span class='[no_damage ? "notice" : "warning"]'>Your [LB.name][isdisabled][self_aware ? " has " : " is "][status].</span>")
|
||||
|
||||
for(var/thing in LB.wounds)
|
||||
var/datum/wound/W = thing
|
||||
var/msg
|
||||
switch(W.severity)
|
||||
if(WOUND_SEVERITY_TRIVIAL)
|
||||
msg = "\t <span class='danger'>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)].</span>"
|
||||
if(WOUND_SEVERITY_MODERATE)
|
||||
msg = "\t <span class='warning'>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!</span>"
|
||||
if(WOUND_SEVERITY_SEVERE)
|
||||
msg = "\t <span class='warning'><b>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!</b></span>"
|
||||
if(WOUND_SEVERITY_CRITICAL)
|
||||
msg = "\t <span class='warning'><b>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!!</b></span>"
|
||||
to_chat(src, msg)
|
||||
|
||||
for(var/obj/item/I in LB.embedded_objects)
|
||||
if(I.isEmbedHarmless())
|
||||
to_chat(src, "\t <a href='?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>There is \a [I] stuck to your [LB.name]!</a>")
|
||||
else
|
||||
to_chat(src, "\t <a href='?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>There is \a [I] embedded in your [LB.name]!</a>")
|
||||
|
||||
|
||||
/mob/living/carbon/human/damage_clothes(damage_amount, damage_type = BRUTE, damage_flag = 0, def_zone)
|
||||
if(damage_type != BRUTE && damage_type != BURN)
|
||||
|
||||
@@ -7,12 +7,14 @@
|
||||
buckle_lying = FALSE
|
||||
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
|
||||
/// Enable stamina combat
|
||||
combat_flags = COMBAT_FLAGS_DEFAULT
|
||||
combat_flags = COMBAT_FLAGS_DEFAULT | COMBAT_FLAG_UNARMED_PARRY
|
||||
status_flags = CANSTUN|CANKNOCKDOWN|CANUNCONSCIOUS|CANPUSH|CANSTAGGER
|
||||
has_field_of_vision = FALSE //Handled by species.
|
||||
|
||||
blocks_emissive = EMISSIVE_BLOCK_UNIQUE
|
||||
|
||||
block_parry_data = /datum/block_parry_data/unarmed/human
|
||||
|
||||
//Hair colour and style
|
||||
var/hair_color = "000"
|
||||
var/hair_style = "Bald"
|
||||
@@ -49,7 +51,6 @@
|
||||
|
||||
var/special_voice = "" // For changing our voice. Used by a symptom.
|
||||
|
||||
var/bleed_rate = 0 //how much are we bleeding
|
||||
var/bleedsuppress = 0 //for stopping bloodloss, eventually this will be limb-based like bleeding
|
||||
|
||||
var/blood_state = BLOOD_STATE_NOT_BLOODY
|
||||
@@ -71,3 +72,45 @@
|
||||
var/lastpuke = 0
|
||||
var/account_id
|
||||
var/last_fire_update
|
||||
|
||||
/// Unarmed parry data for human
|
||||
/datum/block_parry_data/unarmed/human
|
||||
parry_respect_clickdelay = TRUE
|
||||
parry_stamina_cost = 4
|
||||
parry_attack_types = ATTACK_TYPE_UNARMED
|
||||
parry_flags = PARRY_DEFAULT_HANDLE_FEEDBACK | PARRY_LOCK_ATTACKING
|
||||
|
||||
parry_time_windup = 0
|
||||
parry_time_spindown = 1
|
||||
parry_time_active = 5
|
||||
|
||||
parry_time_perfect = 1
|
||||
parry_time_perfect_leeway = 1
|
||||
parry_imperfect_falloff_percent = 20
|
||||
parry_efficiency_perfect = 100
|
||||
|
||||
parry_efficiency_considered_successful = 0.01
|
||||
parry_efficiency_to_counterattack = 0.01
|
||||
parry_max_attacks = 3
|
||||
parry_cooldown = 30
|
||||
parry_failed_stagger_duration = 0
|
||||
parry_failed_clickcd_duration = 0.4
|
||||
|
||||
parry_data = list( // yeah it's snowflake
|
||||
"HUMAN_PARRY_STAGGER" = 3 SECONDS,
|
||||
"HUMAN_PARRY_PUNCH" = TRUE,
|
||||
"HUMAN_PARRY_MININUM_EFFICIENCY" = 0.9
|
||||
)
|
||||
|
||||
/mob/living/carbon/human/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time)
|
||||
var/datum/block_parry_data/D = return_block_parry_datum(block_parry_data)
|
||||
if(!owner.Adjacent(attacker))
|
||||
return ..()
|
||||
if(parry_efficiency < D.parry_data["HUMAN_PARRY_MINIMUM_EFFICIENCY"])
|
||||
return ..()
|
||||
visible_message("<span class='warning'>[src] strikes back perfectly at [attacker], staggering them!</span>")
|
||||
if(D.parry_data["HUMAN_PARRY_PUNCH"])
|
||||
UnarmedAttack(attacker, TRUE, INTENT_HARM, ATTACK_IS_PARRY_COUNTERATTACK | ATTACK_IGNORE_ACTION | ATTACK_IGNORE_CLICKDELAY | NO_AUTO_CLICKDELAY_HANDLING)
|
||||
var/mob/living/L = attacker
|
||||
if(istype(L))
|
||||
L.Stagger(D.parry_data["HUMAN_PARRY_STAGGER"])
|
||||
|
||||
@@ -151,3 +151,32 @@
|
||||
if(blood_dna.len)
|
||||
last_bloodtype = blood_dna[blood_dna[blood_dna.len]]//trust me this works
|
||||
last_blood_DNA = blood_dna[blood_dna.len]*/
|
||||
|
||||
/// For use formatting all of the scars this human has for saving for persistent scarring
|
||||
/mob/living/carbon/human/proc/format_scars()
|
||||
var/list/missing_bodyparts = get_missing_limbs()
|
||||
if(!all_scars && !length(missing_bodyparts))
|
||||
return
|
||||
var/scars = ""
|
||||
for(var/i in missing_bodyparts)
|
||||
var/datum/scar/scaries = new
|
||||
scars += "[scaries.format_amputated(i)]"
|
||||
for(var/i in all_scars)
|
||||
var/datum/scar/scaries = i
|
||||
scars += "[scaries.format()];"
|
||||
return scars
|
||||
|
||||
/// Takes a single scar from the persistent scar loader and recreates it from the saved data
|
||||
/mob/living/carbon/human/proc/load_scar(scar_line)
|
||||
var/list/scar_data = splittext(scar_line, "|")
|
||||
if(LAZYLEN(scar_data) != SCAR_SAVE_LENGTH)
|
||||
return // invalid, should delete
|
||||
var/version = text2num(scar_data[SCAR_SAVE_VERS])
|
||||
if(!version || version < SCAR_CURRENT_VERSION) // get rid of old scars
|
||||
return
|
||||
var/obj/item/bodypart/the_part = get_bodypart("[scar_data[SCAR_SAVE_ZONE]]")
|
||||
var/datum/scar/scaries = new
|
||||
return scaries.load(the_part, scar_data[SCAR_SAVE_VERS], scar_data[SCAR_SAVE_DESC], scar_data[SCAR_SAVE_PRECISE_LOCATION], text2num(scar_data[SCAR_SAVE_SEVERITY]))
|
||||
|
||||
/mob/living/carbon/human/get_biological_state()
|
||||
return dna.species.get_biological_state()
|
||||
|
||||
@@ -36,8 +36,9 @@
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/experience_pressure_difference()
|
||||
playsound(src, 'sound/effects/space_wind.ogg', 50, 1)
|
||||
/mob/living/carbon/human/experience_pressure_difference(pressure_difference, direction, pressure_resistance_prob_delta = 0, throw_target)
|
||||
if(prob(pressure_difference * 2.5))
|
||||
playsound(src, 'sound/effects/space_wind.ogg', 50, 1)
|
||||
if(shoes && istype(shoes, /obj/item/clothing))
|
||||
var/obj/item/clothing/S = shoes
|
||||
if (S.clothing_flags & NOSLIP)
|
||||
@@ -58,7 +59,7 @@
|
||||
. = ..()
|
||||
for(var/datum/mutation/human/HM in dna.mutations)
|
||||
HM.on_move(NewLoc)
|
||||
if(. && (combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) && !(movement_type & FLYING) && CHECK_ALL_MOBILITY(src, MOBILITY_MOVE|MOBILITY_STAND) && m_intent == MOVE_INTENT_RUN && has_gravity(loc) && !pulledby)
|
||||
if(. && (combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) && !(movement_type & FLYING) && CHECK_ALL_MOBILITY(src, MOBILITY_MOVE|MOBILITY_STAND) && m_intent == MOVE_INTENT_RUN && has_gravity(loc) && (!pulledby || (pulledby.pulledby == src)))
|
||||
if(!HAS_TRAIT(src, TRAIT_FREESPRINT))
|
||||
doSprintLossTiles(1)
|
||||
if((oldpseudoheight - pseudo_z_axis) >= 8)
|
||||
@@ -77,7 +78,7 @@
|
||||
var/turf/T = get_turf(src)
|
||||
if(S.bloody_shoes && S.bloody_shoes[S.blood_state])
|
||||
var/obj/effect/decal/cleanable/blood/footprints/oldFP = locate(/obj/effect/decal/cleanable/blood/footprints) in T
|
||||
if(oldFP && (oldFP.blood_state == S.blood_state && oldFP.color == bloodtype_to_color(S.last_bloodtype)))
|
||||
if(oldFP && (oldFP.blood_state == S.blood_state && oldFP.color == S.last_blood_color))
|
||||
return
|
||||
S.bloody_shoes[S.blood_state] = max(0, S.bloody_shoes[S.blood_state] - BLOOD_LOSS_PER_STEP)
|
||||
var/obj/effect/decal/cleanable/blood/footprints/FP = new /obj/effect/decal/cleanable/blood/footprints(T)
|
||||
@@ -85,7 +86,11 @@
|
||||
FP.entered_dirs |= dir
|
||||
FP.bloodiness = S.bloody_shoes[S.blood_state]
|
||||
if(S.last_bloodtype)
|
||||
FP.blood_DNA += list(S.last_blood_DNA = S.last_bloodtype)
|
||||
FP.blood_DNA[S.last_blood_DNA] = S.last_bloodtype
|
||||
if(!FP.blood_DNA["color"])
|
||||
FP.blood_DNA["color"] = S.last_blood_color
|
||||
else
|
||||
FP.blood_DNA["color"] = BlendRGB(FP.blood_DNA["color"], S.last_blood_color)
|
||||
FP.update_icon()
|
||||
update_inv_shoes()
|
||||
//End bloody footprints
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
/mob/living/carbon/human/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
|
||||
return dna.species.can_equip(I, slot, disable_warning, src, bypass_equip_delay_self)
|
||||
/mob/living/carbon/human/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, clothing_check = FALSE, list/return_warning)
|
||||
return dna.species.can_equip(I, slot, disable_warning, src, bypass_equip_delay_self, clothing_check, return_warning)
|
||||
|
||||
/**
|
||||
* Used to return a list of equipped items on a human mob; does not include held items (use get_all_gear)
|
||||
*
|
||||
* Argument(s):
|
||||
* * Optional - include_pockets (TRUE/FALSE), whether or not to include the pockets and suit storage in the returned list
|
||||
*/
|
||||
|
||||
/mob/living/carbon/human/get_equipped_items(include_pockets = FALSE)
|
||||
var/list/items = ..()
|
||||
if(!include_pockets)
|
||||
items -= list(l_store, r_store, s_store)
|
||||
return items
|
||||
|
||||
// Return the item currently in the slot ID
|
||||
/mob/living/carbon/human/get_item_by_slot(slot_id)
|
||||
@@ -142,7 +155,7 @@
|
||||
//Item is handled and in slot, valid to call callback, for this proc should always be true
|
||||
if(!not_handled)
|
||||
I.equipped(src, slot)
|
||||
|
||||
update_genitals()
|
||||
return not_handled //For future deeper overrides
|
||||
|
||||
/mob/living/carbon/human/equipped_speed_mods()
|
||||
@@ -230,6 +243,7 @@
|
||||
s_store = null
|
||||
if(!QDELETED(src))
|
||||
update_inv_s_store()
|
||||
update_genitals()
|
||||
|
||||
/mob/living/carbon/human/wear_mask_update(obj/item/clothing/C, toggle_off = 1)
|
||||
if((C.flags_inv & (HIDEHAIR|HIDEFACIALHAIR)) || (initial(C.flags_inv) & (HIDEHAIR|HIDEFACIALHAIR)))
|
||||
|
||||
@@ -18,32 +18,21 @@
|
||||
#define THERMAL_PROTECTION_HAND_LEFT 0.025
|
||||
#define THERMAL_PROTECTION_HAND_RIGHT 0.025
|
||||
|
||||
/mob/living/carbon/human/Life(seconds, times_fired)
|
||||
set invisibility = 0
|
||||
if (notransform)
|
||||
/mob/living/carbon/human/BiologicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
handle_active_genes()
|
||||
//heart attack stuff
|
||||
handle_heart()
|
||||
dna.species.spec_life(src) // for mutantraces
|
||||
return (stat != DEAD) && !QDELETED(src)
|
||||
|
||||
. = ..()
|
||||
|
||||
if (QDELETED(src))
|
||||
return 0
|
||||
|
||||
if(.) //not dead
|
||||
handle_active_genes()
|
||||
|
||||
if(stat != DEAD)
|
||||
//heart attack stuff
|
||||
handle_heart()
|
||||
|
||||
/mob/living/carbon/human/PhysicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
//Update our name based on whether our face is obscured/disfigured
|
||||
name = get_visible_name()
|
||||
|
||||
dna.species.spec_life(src) // for mutantraces
|
||||
|
||||
if(stat != DEAD)
|
||||
return 1
|
||||
|
||||
|
||||
/mob/living/carbon/human/calculate_affecting_pressure(pressure)
|
||||
var/headless = !get_bodypart(BODY_ZONE_HEAD) //should the mob be perennially headless (see dullahans), we only take the suit into account, so they can into space.
|
||||
if (wear_suit && istype(wear_suit, /obj/item/clothing) && (headless || (head && istype(head, /obj/item/clothing))))
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
return " (as [get_id_name("Unknown")])"
|
||||
|
||||
/mob/living/carbon/human/proc/forcesay(list/append) //this proc is at the bottom of the file because quote fuckery makes notepad++ cri
|
||||
set waitfor = FALSE // WINGET IS A SLEEP. DO. NOT. SLEEP.
|
||||
if(stat == CONSCIOUS)
|
||||
if(client)
|
||||
var/temp = winget(client, "input", "text")
|
||||
|
||||
@@ -7,7 +7,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
var/id // if the game needs to manually check your race to do something not included in a proc here, it will use this
|
||||
var/limbs_id //this is used if you want to use a different species limb sprites. Mainly used for angels as they look like humans.
|
||||
var/name // this is the fluff name. these will be left generic (such as 'Lizardperson' for the lizard race) so servers can change them to whatever
|
||||
var/default_color = "#FFF" // if alien colors are disabled, this is the color that will be used by that race
|
||||
var/default_color = "#FFFFFF" // if alien colors are disabled, this is the color that will be used by that race
|
||||
|
||||
var/sexes = 1 // whether or not the race has sexual characteristics. at the moment this is only 0 for skeletons and shadows
|
||||
var/has_field_of_vision = TRUE
|
||||
@@ -39,6 +39,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
var/use_skintones = NO_SKINTONES // does it use skintones or not? (spoiler alert this is only used by humans)
|
||||
var/exotic_blood = "" // If your race wants to bleed something other than bog standard blood, change this to reagent id.
|
||||
var/exotic_bloodtype = "" //If your race uses a non standard bloodtype (A+, O-, AB-, etc)
|
||||
var/exotic_blood_color = BLOOD_COLOR_HUMAN //assume human as the default blood colour, override this default by species subtypes
|
||||
var/meat = /obj/item/reagent_containers/food/snacks/meat/slab/human //What the species drops on gibbing
|
||||
var/list/gib_types = list(/obj/effect/gibspawner/human, /obj/effect/gibspawner/human/bodypartless)
|
||||
var/skinned_type
|
||||
@@ -55,6 +56,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
var/list/mutant_organs = list() //Internal organs that are unique to this race.
|
||||
var/speedmod = 0 // this affects the race's speed. positive numbers make it move slower, negative numbers make it move faster
|
||||
var/armor = 0 // overall defense for the race... or less defense, if it's negative.
|
||||
var/attack_type = BRUTE // the type of damage unarmed attacks from this species do
|
||||
var/brutemod = 1 // multiplier for brute damage
|
||||
var/burnmod = 1 // multiplier for burn damage
|
||||
var/coldmod = 1 // multiplier for cold damage
|
||||
@@ -72,7 +74,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
var/datum/outfit/outfit_important_for_life // A path to an outfit that is important for species life e.g. plasmaman outfit
|
||||
|
||||
// species-only traits. Can be found in DNA.dm
|
||||
var/list/species_traits = list()
|
||||
var/list/species_traits = list(HAS_FLESH,HAS_BONE) //by default they can scar and have bones/flesh unless set to something else
|
||||
// generic traits tied to having the species
|
||||
var/list/inherent_traits = list()
|
||||
var/inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID
|
||||
@@ -104,21 +106,31 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
var/whitelisted = 0 //Is this species restricted to certain players?
|
||||
var/whitelist = list() //List the ckeys that can use this species, if it's whitelisted.: list("John Doe", "poopface666", "SeeALiggerPullTheTrigger") Spaces & capitalization can be included or ignored entirely for each key as it checks for both.
|
||||
var/icon_limbs //Overrides the icon used for the limbs of this species. Mainly for downstream, and also because hardcoded icons disgust me. Implemented and maintained as a favor in return for a downstream's implementation of synths.
|
||||
var/species_type
|
||||
|
||||
var/tail_type //type of tail i.e. mam_tail
|
||||
var/wagging_type //type of wagging i.e. waggingtail_lizard
|
||||
|
||||
/// Our default override for typing indicator state
|
||||
var/typing_indicator_state
|
||||
|
||||
//the ids you can use for your species, if empty, it means default only and not changeable
|
||||
var/list/allowed_limb_ids
|
||||
|
||||
///////////
|
||||
// PROCS //
|
||||
///////////
|
||||
|
||||
|
||||
/datum/species/New()
|
||||
|
||||
if(!limbs_id) //if we havent set a limbs id to use, just use our own id
|
||||
limbs_id = id
|
||||
mutant_bodyparts["limbs_id"] = id //done this way to be non-intrusive to the existing system
|
||||
else
|
||||
mutant_bodyparts["limbs_id"] = limbs_id
|
||||
..()
|
||||
|
||||
//update our mutant bodyparts to include unlocked ones
|
||||
mutant_bodyparts += GLOB.unlocked_mutant_parts
|
||||
|
||||
/proc/generate_selectable_species(clear = FALSE)
|
||||
if(clear)
|
||||
@@ -386,7 +398,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
//keep it at the right spot, so we can't have people taking shortcuts
|
||||
var/location = C.dna.mutation_index.Find(inert_mutation)
|
||||
C.dna.mutation_index[location] = new_species.inert_mutation
|
||||
C.dna.default_mutation_genes[location] = C.dna.mutation_index[location]
|
||||
C.dna.mutation_index[new_species.inert_mutation] = create_sequence(new_species.inert_mutation)
|
||||
C.dna.default_mutation_genes[new_species.inert_mutation] = C.dna.mutation_index[new_species.inert_mutation]
|
||||
|
||||
if(!new_species.has_field_of_vision && has_field_of_vision && ishuman(C) && CONFIG_GET(flag/use_field_of_vision))
|
||||
var/datum/component/field_of_vision/F = C.GetComponent(/datum/component/field_of_vision)
|
||||
@@ -644,106 +658,19 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
if(!mutant_bodyparts)
|
||||
return
|
||||
|
||||
var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD)
|
||||
var/tauric = mutant_bodyparts["taur"] && H.dna.features["taur"] && H.dna.features["taur"] != "None"
|
||||
|
||||
if(mutant_bodyparts["tail_lizard"])
|
||||
if((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric)
|
||||
bodyparts_to_add -= "tail_lizard"
|
||||
|
||||
if(mutant_bodyparts["waggingtail_lizard"])
|
||||
if((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric)
|
||||
bodyparts_to_add -= "waggingtail_lizard"
|
||||
else if (mutant_bodyparts["tail_lizard"])
|
||||
bodyparts_to_add -= "waggingtail_lizard"
|
||||
|
||||
if(mutant_bodyparts["tail_human"])
|
||||
if((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric)
|
||||
bodyparts_to_add -= "tail_human"
|
||||
|
||||
if(mutant_bodyparts["waggingtail_human"])
|
||||
if((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric)
|
||||
bodyparts_to_add -= "waggingtail_human"
|
||||
else if (mutant_bodyparts["tail_human"])
|
||||
bodyparts_to_add -= "waggingtail_human"
|
||||
|
||||
if(mutant_bodyparts["spines"])
|
||||
if(!H.dna.features["spines"] || H.dna.features["spines"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR))
|
||||
bodyparts_to_add -= "spines"
|
||||
|
||||
if(mutant_bodyparts["waggingspines"])
|
||||
if(!H.dna.features["spines"] || H.dna.features["spines"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR))
|
||||
bodyparts_to_add -= "waggingspines"
|
||||
else if (mutant_bodyparts["tail"])
|
||||
bodyparts_to_add -= "waggingspines"
|
||||
|
||||
if(mutant_bodyparts["snout"]) //Take a closer look at that snout!
|
||||
if((H.wear_mask && (H.wear_mask.flags_inv & HIDESNOUT)) || (H.head && (H.head.flags_inv & HIDESNOUT)) || !HD || (HD.status == BODYPART_ROBOTIC && !HD.render_like_organic))
|
||||
bodyparts_to_add -= "snout"
|
||||
|
||||
if(mutant_bodyparts["frills"])
|
||||
if(!H.dna.features["frills"] || H.dna.features["frills"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || !HD || HD.status == BODYPART_ROBOTIC)
|
||||
bodyparts_to_add -= "frills"
|
||||
|
||||
if(mutant_bodyparts["horns"])
|
||||
if(!H.dna.features["horns"] || H.dna.features["horns"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || (HD.status == BODYPART_ROBOTIC && !HD.render_like_organic))
|
||||
bodyparts_to_add -= "horns"
|
||||
|
||||
if(mutant_bodyparts["ears"])
|
||||
if(!H.dna.features["ears"] || H.dna.features["ears"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEEARS)) || !HD || (HD.status == BODYPART_ROBOTIC && !HD.render_like_organic))
|
||||
bodyparts_to_add -= "ears"
|
||||
|
||||
if(mutant_bodyparts["wings"])
|
||||
if(!H.dna.features["wings"] || H.dna.features["wings"] == "None" || (H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT) && (!H.wear_suit.species_exception || !is_type_in_list(src, H.wear_suit.species_exception))))
|
||||
bodyparts_to_add -= "wings"
|
||||
|
||||
if(mutant_bodyparts["wings_open"])
|
||||
if(H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT) && (!H.wear_suit.species_exception || !is_type_in_list(src, H.wear_suit.species_exception)))
|
||||
bodyparts_to_add -= "wings_open"
|
||||
else if (mutant_bodyparts["wings"])
|
||||
bodyparts_to_add -= "wings_open"
|
||||
|
||||
if(mutant_bodyparts["insect_fluff"])
|
||||
if(!H.dna.features["insect_fluff"] || H.dna.features["insect_fluff"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT))
|
||||
bodyparts_to_add -= "insect_fluff"
|
||||
|
||||
//CITADEL EDIT
|
||||
//Race specific bodyparts:
|
||||
//Xenos
|
||||
if(mutant_bodyparts["xenodorsal"])
|
||||
if(!H.dna.features["xenodorsal"] || H.dna.features["xenodorsal"] == "None" || (H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT)))
|
||||
bodyparts_to_add -= "xenodorsal"
|
||||
if(mutant_bodyparts["xenohead"])//This is an overlay for different castes using different head crests
|
||||
if(!H.dna.features["xenohead"] || H.dna.features["xenohead"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || (HD.status == BODYPART_ROBOTIC && !HD.render_like_organic))
|
||||
bodyparts_to_add -= "xenohead"
|
||||
if(mutant_bodyparts["xenotail"])
|
||||
if(!H.dna.features["xenotail"] || H.dna.features["xenotail"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT))
|
||||
bodyparts_to_add -= "xenotail"
|
||||
|
||||
//Other Races
|
||||
if(mutant_bodyparts["mam_tail"])
|
||||
if((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric)
|
||||
bodyparts_to_add -= "mam_tail"
|
||||
|
||||
if(mutant_bodyparts["mam_waggingtail"])
|
||||
if((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric)
|
||||
bodyparts_to_add -= "mam_waggingtail"
|
||||
else if (mutant_bodyparts["mam_tail"])
|
||||
bodyparts_to_add -= "mam_waggingtail"
|
||||
|
||||
if(mutant_bodyparts["mam_ears"])
|
||||
if(!H.dna.features["mam_ears"] || H.dna.features["mam_ears"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEEARS)) || !HD || (HD.status == BODYPART_ROBOTIC && !HD.render_like_organic))
|
||||
bodyparts_to_add -= "mam_ears"
|
||||
|
||||
if(mutant_bodyparts["mam_snouts"]) //Take a closer look at that snout!
|
||||
if((H.wear_mask && (H.wear_mask.flags_inv & HIDESNOUT)) || (H.head && (H.head.flags_inv & HIDESNOUT)) || !HD || (HD.status == BODYPART_ROBOTIC && !HD.render_like_organic))
|
||||
bodyparts_to_add -= "mam_snouts"
|
||||
|
||||
if(mutant_bodyparts["taur"])
|
||||
if(!tauric || (H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)))
|
||||
bodyparts_to_add -= "taur"
|
||||
|
||||
//END EDIT
|
||||
for(var/mutant_part in mutant_bodyparts)
|
||||
var/reference_list = GLOB.mutant_reference_list[mutant_part]
|
||||
if(reference_list)
|
||||
var/datum/sprite_accessory/S
|
||||
var/transformed_part = GLOB.mutant_transform_list[mutant_part]
|
||||
if(transformed_part)
|
||||
S = reference_list[H.dna.features[transformed_part]]
|
||||
else
|
||||
S = reference_list[H.dna.features[mutant_part]]
|
||||
if(!S || S.is_not_visible(H, tauric))
|
||||
bodyparts_to_add -= mutant_part
|
||||
|
||||
//Digitigrade legs are stuck in the phantom zone between true limbs and mutant bodyparts. Mainly it just needs more agressive updating than most limbs.
|
||||
var/update_needed = FALSE
|
||||
@@ -780,76 +707,22 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
var/list/dna_feature_as_text_string = list()
|
||||
|
||||
for(var/bodypart in bodyparts_to_add)
|
||||
var/datum/sprite_accessory/S
|
||||
switch(bodypart)
|
||||
if("tail_lizard")
|
||||
S = GLOB.tails_list_lizard[H.dna.features["tail_lizard"]]
|
||||
if("waggingtail_lizard")
|
||||
S = GLOB.animated_tails_list_lizard[H.dna.features["tail_lizard"]]
|
||||
if("tail_human")
|
||||
S = GLOB.tails_list_human[H.dna.features["tail_human"]]
|
||||
if("waggingtail_human")
|
||||
S = GLOB.animated_tails_list_human[H.dna.features["tail_human"]]
|
||||
if("spines")
|
||||
S = GLOB.spines_list[H.dna.features["spines"]]
|
||||
if("waggingspines")
|
||||
S = GLOB.animated_spines_list[H.dna.features["spines"]]
|
||||
if("snout")
|
||||
S = GLOB.snouts_list[H.dna.features["snout"]]
|
||||
if("frills")
|
||||
S = GLOB.frills_list[H.dna.features["frills"]]
|
||||
if("horns")
|
||||
S = GLOB.horns_list[H.dna.features["horns"]]
|
||||
if("ears")
|
||||
S = GLOB.ears_list[H.dna.features["ears"]]
|
||||
if("body_markings")
|
||||
S = GLOB.body_markings_list[H.dna.features["body_markings"]]
|
||||
if("wings")
|
||||
S = GLOB.wings_list[H.dna.features["wings"]]
|
||||
if("wingsopen")
|
||||
S = GLOB.wings_open_list[H.dna.features["wings"]]
|
||||
if("deco_wings")
|
||||
S = GLOB.deco_wings_list[H.dna.features["deco_wings"]]
|
||||
if("legs")
|
||||
S = GLOB.legs_list[H.dna.features["legs"]]
|
||||
if("insect_wings")
|
||||
S = GLOB.insect_wings_list[H.dna.features["insect_wings"]]
|
||||
if("insect_fluff")
|
||||
S = GLOB.insect_fluffs_list[H.dna.features["insect_fluff"]]
|
||||
if("insect_markings")
|
||||
S = GLOB.insect_markings_list[H.dna.features["insect_markings"]]
|
||||
if("caps")
|
||||
S = GLOB.caps_list[H.dna.features["caps"]]
|
||||
if("ipc_screen")
|
||||
S = GLOB.ipc_screens_list[H.dna.features["ipc_screen"]]
|
||||
if("ipc_antenna")
|
||||
S = GLOB.ipc_antennas_list[H.dna.features["ipc_antenna"]]
|
||||
if("mam_tail")
|
||||
S = GLOB.mam_tails_list[H.dna.features["mam_tail"]]
|
||||
if("mam_waggingtail")
|
||||
S = GLOB.mam_tails_animated_list[H.dna.features["mam_tail"]]
|
||||
if("mam_body_markings")
|
||||
S = GLOB.mam_body_markings_list[H.dna.features["mam_body_markings"]]
|
||||
if("mam_ears")
|
||||
S = GLOB.mam_ears_list[H.dna.features["mam_ears"]]
|
||||
if("mam_snouts")
|
||||
S = GLOB.mam_snouts_list[H.dna.features["mam_snouts"]]
|
||||
if("taur")
|
||||
S = GLOB.taur_list[H.dna.features["taur"]]
|
||||
if("xenodorsal")
|
||||
S = GLOB.xeno_dorsal_list[H.dna.features["xenodorsal"]]
|
||||
if("xenohead")
|
||||
S = GLOB.xeno_head_list[H.dna.features["xenohead"]]
|
||||
if("xenotail")
|
||||
S = GLOB.xeno_tail_list[H.dna.features["xenotail"]]
|
||||
var/reference_list = GLOB.mutant_reference_list[bodypart]
|
||||
if(reference_list)
|
||||
var/datum/sprite_accessory/S
|
||||
var/transformed_part = GLOB.mutant_transform_list[bodypart]
|
||||
if(transformed_part)
|
||||
S = reference_list[H.dna.features[transformed_part]]
|
||||
else
|
||||
S = reference_list[H.dna.features[bodypart]]
|
||||
|
||||
if(!S || S.icon_state == "none")
|
||||
continue
|
||||
if(!S || S.icon_state == "none")
|
||||
continue
|
||||
|
||||
for(var/L in S.relevant_layers)
|
||||
LAZYADD(relevant_layers["[L]"], S)
|
||||
if(!S.mutant_part_string)
|
||||
dna_feature_as_text_string[S] = bodypart
|
||||
for(var/L in S.relevant_layers)
|
||||
LAZYADD(relevant_layers["[L]"], S)
|
||||
if(!S.mutant_part_string)
|
||||
dna_feature_as_text_string[S] = bodypart
|
||||
|
||||
var/static/list/layer_text = list(
|
||||
"[BODY_BEHIND_LAYER]" = "BEHIND",
|
||||
@@ -862,10 +735,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
var/g = (H.dna.features["body_model"] == FEMALE) ? "f" : "m"
|
||||
var/list/colorlist = list()
|
||||
var/husk = HAS_TRAIT(H, TRAIT_HUSK)
|
||||
colorlist += husk ? ReadRGB("#a3a3a3") :ReadRGB("[H.dna.features["mcolor"]]0")
|
||||
colorlist += husk ? ReadRGB("#a3a3a3") :ReadRGB("[H.dna.features["mcolor2"]]0")
|
||||
colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features["mcolor3"]]0")
|
||||
colorlist += list(0,0,0, hair_alpha)
|
||||
colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features["mcolor"]]00")
|
||||
colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features["mcolor2"]]00")
|
||||
colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features["mcolor3"]]00")
|
||||
colorlist += husk ? list(0, 0, 0) : list(0, 0, 0, hair_alpha)
|
||||
for(var/index in 1 to colorlist.len)
|
||||
colorlist[index] /= 255
|
||||
|
||||
@@ -1039,7 +912,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
H.apply_overlay(BODY_FRONT_LAYER)
|
||||
H.apply_overlay(HORNS_LAYER)
|
||||
|
||||
|
||||
/*
|
||||
* Equip the outfit required for life. Replaces items currently worn.
|
||||
*/
|
||||
@@ -1070,17 +942,23 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
H.adjustBruteLoss(1)
|
||||
|
||||
/datum/species/proc/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
return
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
|
||||
/datum/species/proc/auto_equip(mob/living/carbon/human/H)
|
||||
// handles the equipping of species-specific gear
|
||||
return
|
||||
|
||||
/datum/species/proc/can_equip(obj/item/I, slot, disable_warning, mob/living/carbon/human/H, bypass_equip_delay_self = FALSE)
|
||||
/datum/species/proc/can_equip(obj/item/I, slot, disable_warning, mob/living/carbon/human/H, bypass_equip_delay_self = FALSE, clothing_check = FALSE, list/return_warning)
|
||||
if(slot in no_equip)
|
||||
if(!I.species_exception || !is_type_in_list(src, I.species_exception))
|
||||
return FALSE
|
||||
|
||||
if(clothing_check && (slot in H.check_obscured_slots()))
|
||||
if(return_warning)
|
||||
return_warning[1] = "<span class='warning'>You are unable to equip that with your current garments in the way!</span>"
|
||||
return FALSE
|
||||
|
||||
var/num_arms = H.get_num_arms(FALSE)
|
||||
var/num_legs = H.get_num_legs(FALSE)
|
||||
|
||||
@@ -1142,8 +1020,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
if(!CHECK_BITFIELD(I.item_flags, NO_UNIFORM_REQUIRED))
|
||||
var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_CHEST)
|
||||
if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC))
|
||||
if(!disable_warning)
|
||||
to_chat(H, "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>")
|
||||
if(return_warning)
|
||||
return_warning[1] = "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>"
|
||||
return FALSE
|
||||
if(!(I.slot_flags & ITEM_SLOT_BELT))
|
||||
return
|
||||
@@ -1184,8 +1062,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
if(!CHECK_BITFIELD(I.item_flags, NO_UNIFORM_REQUIRED))
|
||||
var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_CHEST)
|
||||
if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC))
|
||||
if(!disable_warning)
|
||||
to_chat(H, "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>")
|
||||
if(return_warning)
|
||||
return_warning[1] = "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>"
|
||||
return FALSE
|
||||
if( !(I.slot_flags & ITEM_SLOT_ID) )
|
||||
return FALSE
|
||||
@@ -1199,8 +1077,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_L_LEG)
|
||||
|
||||
if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC))
|
||||
if(!disable_warning)
|
||||
to_chat(H, "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>")
|
||||
if(return_warning)
|
||||
return_warning[1] = "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>"
|
||||
return FALSE
|
||||
if(I.slot_flags & ITEM_SLOT_DENYPOCKET)
|
||||
return FALSE
|
||||
@@ -1215,8 +1093,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_R_LEG)
|
||||
|
||||
if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC))
|
||||
if(!disable_warning)
|
||||
to_chat(H, "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>")
|
||||
if(return_warning)
|
||||
return_warning[1] = "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>"
|
||||
return FALSE
|
||||
if(I.slot_flags & ITEM_SLOT_DENYPOCKET)
|
||||
return FALSE
|
||||
@@ -1229,16 +1107,16 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
if(H.s_store)
|
||||
return FALSE
|
||||
if(!H.wear_suit)
|
||||
if(!disable_warning)
|
||||
to_chat(H, "<span class='warning'>You need a suit before you can attach this [I.name]!</span>")
|
||||
if(return_warning)
|
||||
return_warning[1] = "<span class='warning'>You need a suit before you can attach this [I.name]!</span>"
|
||||
return FALSE
|
||||
if(!H.wear_suit.allowed)
|
||||
if(!disable_warning)
|
||||
to_chat(H, "You somehow have a suit with no defined allowed items for suit storage, stop that.")
|
||||
if(return_warning)
|
||||
return_warning[1] = "You somehow have a suit with no defined allowed items for suit storage, stop that."
|
||||
return FALSE
|
||||
if(I.w_class > WEIGHT_CLASS_BULKY)
|
||||
if(!disable_warning)
|
||||
to_chat(H, "The [I.name] is too big to attach.") //should be src?
|
||||
if(return_warning)
|
||||
return_warning[1] = "The [I.name] is too big to attach."
|
||||
return FALSE
|
||||
if( istype(I, /obj/item/pda) || istype(I, /obj/item/pen) || is_type_in_list(I, H.wear_suit.allowed) )
|
||||
return TRUE
|
||||
@@ -1288,9 +1166,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
/datum/species/proc/check_weakness(obj/item, mob/living/attacker)
|
||||
return FALSE
|
||||
|
||||
////////
|
||||
//LIFE//
|
||||
////////
|
||||
/////////////
|
||||
////LIFE////
|
||||
////////////
|
||||
|
||||
/datum/species/proc/handle_digestion(mob/living/carbon/human/H)
|
||||
if(HAS_TRAIT(src, TRAIT_NOHUNGER))
|
||||
@@ -1365,6 +1243,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
var/hungry = (500 - H.nutrition) / 5 //So overeat would be 100 and default level would be 80
|
||||
if(hungry >= 70)
|
||||
H.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/hunger, multiplicative_slowdown = (hungry / 50))
|
||||
else if(isethereal(H))
|
||||
var/datum/species/ethereal/E = H.dna.species
|
||||
if(E.get_charge(H) <= ETHEREAL_CHARGE_NORMAL)
|
||||
H.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/hunger, multiplicative_slowdown = (1.5 * (1 - E.get_charge(H) / 100)))
|
||||
else
|
||||
H.remove_movespeed_modifier(/datum/movespeed_modifier/hunger)
|
||||
|
||||
@@ -1421,6 +1303,12 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
// ATTACK PROCS //
|
||||
//////////////////
|
||||
|
||||
/datum/species/proc/spec_updatehealth(mob/living/carbon/human/H)
|
||||
return
|
||||
|
||||
/datum/species/proc/spec_fully_heal(mob/living/carbon/human/H)
|
||||
return
|
||||
|
||||
/datum/species/proc/help(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
|
||||
if(target.health >= 0 && !HAS_TRAIT(target, TRAIT_FAKEDEATH))
|
||||
target.help_shake_act(user)
|
||||
@@ -1449,7 +1337,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
target.grabbedby(user)
|
||||
return 1
|
||||
|
||||
/datum/species/proc/harm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
|
||||
/datum/species/proc/harm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style, attackchain_flags = NONE)
|
||||
if(!attacker_style && HAS_TRAIT(user, TRAIT_PACIFISM))
|
||||
to_chat(user, "<span class='warning'>You don't want to harm [target]!</span>")
|
||||
return FALSE
|
||||
@@ -1461,10 +1349,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
target_message = "<span class='warning'>[target] blocks your attack!</span>")
|
||||
return FALSE
|
||||
|
||||
if(HAS_TRAIT(user, TRAIT_PUGILIST))//CITADEL CHANGE - makes punching cause staminaloss but funny martial artist types get a discount
|
||||
user.adjustStaminaLossBuffered(1.5)
|
||||
else
|
||||
user.adjustStaminaLossBuffered(3.5)
|
||||
if(!(attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK))
|
||||
if(HAS_TRAIT(user, TRAIT_PUGILIST))//CITADEL CHANGE - makes punching cause staminaloss but funny martial artist types get a discount
|
||||
user.adjustStaminaLossBuffered(1.5)
|
||||
else
|
||||
user.adjustStaminaLossBuffered(3.5)
|
||||
|
||||
if(attacker_style && attacker_style.harm_act(user,target))
|
||||
return TRUE
|
||||
@@ -1492,23 +1381,26 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
|
||||
//CITADEL CHANGES - makes resting and disabled combat mode reduce punch damage, makes being out of combat mode result in you taking more damage
|
||||
if(!SEND_SIGNAL(target, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
|
||||
damage *= 1.5
|
||||
damage *= 1.2
|
||||
if(!CHECK_MOBILITY(user, MOBILITY_STAND))
|
||||
damage *= 0.5
|
||||
damage *= 0.8
|
||||
if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
|
||||
damage *= 0.25
|
||||
damage *= 0.8
|
||||
//END OF CITADEL CHANGES
|
||||
|
||||
var/obj/item/bodypart/affecting = target.get_bodypart(ran_zone(user.zone_selected))
|
||||
|
||||
var/miss_chance = 100//calculate the odds that a punch misses entirely. considers stamina and brute damage of the puncher. punches miss by default to prevent weird cases
|
||||
if(user.dna.species.punchdamagelow)
|
||||
if(HAS_TRAIT(user, TRAIT_PUGILIST)) //pugilists have a flat 10% miss chance
|
||||
miss_chance = 10
|
||||
if(atk_verb == ATTACK_EFFECT_KICK) //kicks never miss (provided your species deals more than 0 damage)
|
||||
miss_chance = 0
|
||||
else
|
||||
miss_chance = min(10 + ((puncherstam + puncherbrute)*0.5), 100) //probability of miss has a base of 10, and modified based on half brute total. Capped at max 100 to prevent weirdness in prob()
|
||||
if(attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)
|
||||
miss_chance = 0
|
||||
else
|
||||
if(user.dna.species.punchdamagelow)
|
||||
if(atk_verb == ATTACK_EFFECT_KICK) //kicks never miss (provided your species deals more than 0 damage)
|
||||
miss_chance = 0
|
||||
else if(HAS_TRAIT(user, TRAIT_PUGILIST)) //pugilists have a flat 10% miss chance
|
||||
miss_chance = 10
|
||||
else
|
||||
miss_chance = min(10 + max(puncherstam * 0.5, puncherbrute * 0.5), 100) //probability of miss has a base of 10, and modified based on half brute total. Capped at max 100 to prevent weirdness in prob()
|
||||
|
||||
if(!damage || !affecting || prob(miss_chance))//future-proofing for species that have 0 damage/weird cases where no zone is targeted
|
||||
playsound(target.loc, user.dna.species.miss_sound, 25, TRUE, -1)
|
||||
@@ -1535,11 +1427,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
target.dismembering_strike(user, affecting.body_zone)
|
||||
|
||||
if(atk_verb == ATTACK_EFFECT_KICK)//kicks deal 1.5x raw damage + 0.5x stamina damage
|
||||
target.apply_damage(damage*1.5, BRUTE, affecting, armor_block)
|
||||
target.apply_damage(damage*1.5, attack_type, affecting, armor_block)
|
||||
target.apply_damage(damage*0.5, STAMINA, affecting, armor_block)
|
||||
log_combat(user, target, "kicked")
|
||||
else//other attacks deal full raw damage + 2x in stamina damage
|
||||
target.apply_damage(damage, BRUTE, affecting, armor_block)
|
||||
target.apply_damage(damage, attack_type, affecting, armor_block)
|
||||
target.apply_damage(damage*2, STAMINA, affecting, armor_block)
|
||||
log_combat(user, target, "punched")
|
||||
|
||||
@@ -1686,7 +1578,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
/datum/species/proc/spec_hitby(atom/movable/AM, mob/living/carbon/human/H)
|
||||
return
|
||||
|
||||
/datum/species/proc/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
|
||||
/datum/species/proc/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style, act_intent, attackchain_flags)
|
||||
if(!istype(M))
|
||||
return
|
||||
CHECK_DNA_AND_SPECIES(M)
|
||||
@@ -1698,7 +1590,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
attacker_style = M.mind.martial_art
|
||||
if(attacker_style?.pacifism_check && HAS_TRAIT(M, TRAIT_PACIFISM)) // most martial arts are quite harmful, alas.
|
||||
attacker_style = null
|
||||
switch(M.a_intent)
|
||||
switch(act_intent)
|
||||
if("help")
|
||||
help(M, H, attacker_style)
|
||||
|
||||
@@ -1706,7 +1598,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
grab(M, H, attacker_style)
|
||||
|
||||
if("harm")
|
||||
harm(M, H, attacker_style)
|
||||
harm(M, H, attacker_style, attackchain_flags)
|
||||
|
||||
if("disarm")
|
||||
disarm(M, H, attacker_style)
|
||||
@@ -1716,7 +1608,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
// Allows you to put in item-specific reactions based on species
|
||||
if(user != H)
|
||||
var/list/block_return = list()
|
||||
if(H.mob_run_block(I, totitemdamage, "the [I.name]", ((attackchain_flags & ATTACKCHAIN_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE) | ATTACK_TYPE_MELEE, I.armour_penetration, user, affecting.body_zone, block_return) & BLOCK_SUCCESS)
|
||||
if(H.mob_run_block(I, totitemdamage, "the [I.name]", ((attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE) | ATTACK_TYPE_MELEE, I.armour_penetration, user, affecting.body_zone, block_return) & BLOCK_SUCCESS)
|
||||
return 0
|
||||
totitemdamage = block_calculate_resultant_damage(totitemdamage, block_return)
|
||||
if(H.check_martial_melee_block())
|
||||
@@ -1733,24 +1625,23 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
var/armor_block = H.run_armor_check(affecting, "melee", "<span class='notice'>Your armor has protected your [hit_area].</span>", "<span class='notice'>Your armor has softened a hit to your [hit_area].</span>",I.armour_penetration)
|
||||
armor_block = min(90,armor_block) //cap damage reduction at 90%
|
||||
var/Iforce = I.force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords)
|
||||
var/Iwound_bonus = I.wound_bonus
|
||||
|
||||
// this way, you can't wound with a surgical tool on help intent if they have a surgery active and are laying down, so a misclick with a circular saw on the wrong limb doesn't bleed them dry (they still get hit tho)
|
||||
if((I.item_flags & SURGICAL_TOOL) && user.a_intent == INTENT_HELP && (H.mobility_flags & ~MOBILITY_STAND) && (LAZYLEN(H.surgeries) > 0))
|
||||
Iwound_bonus = CANT_WOUND
|
||||
|
||||
var/weakness = H.check_weakness(I, user)
|
||||
apply_damage(totitemdamage * weakness, I.damtype, def_zone, armor_block, H) //CIT CHANGE - replaces I.force with totitemdamage
|
||||
apply_damage(totitemdamage * weakness, I.damtype, def_zone, armor_block, H, wound_bonus = Iwound_bonus, bare_wound_bonus = I.bare_wound_bonus, sharpness = I.get_sharpness())
|
||||
|
||||
H.send_item_attack_message(I, user, hit_area)
|
||||
|
||||
H.send_item_attack_message(I, user, hit_area, affecting, totitemdamage)
|
||||
|
||||
I.do_stagger_action(H, user, totitemdamage)
|
||||
|
||||
if(!totitemdamage)
|
||||
return 0 //item force is zero
|
||||
|
||||
//dismemberment
|
||||
var/probability = I.get_dismemberment_chance(affecting)
|
||||
if(prob(probability) || (HAS_TRAIT(H, TRAIT_EASYDISMEMBER) && prob(probability))) //try twice
|
||||
if(affecting.dismember(I.damtype))
|
||||
I.add_mob_blood(H)
|
||||
playsound(get_turf(H), I.get_dismember_sound(), 80, 1)
|
||||
|
||||
var/bloody = 0
|
||||
if(((I.damtype == BRUTE) && I.force && prob(25 + (I.force * 2))))
|
||||
if(affecting.status == BODYPART_ORGANIC)
|
||||
@@ -1821,6 +1712,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
return TRUE
|
||||
CHECK_DNA_AND_SPECIES(M)
|
||||
CHECK_DNA_AND_SPECIES(H)
|
||||
if(!M.CheckActionCooldown())
|
||||
return
|
||||
M.DelayNextAction(CLICK_CD_MELEE)
|
||||
|
||||
if(!istype(M)) //sanity check for drones.
|
||||
return TRUE
|
||||
@@ -1930,11 +1824,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
target.visible_message("<span class='danger'>[user.name] shoves [target.name]!</span>",
|
||||
"<span class='danger'>[user.name] shoves you!</span>", null, COMBAT_MESSAGE_RANGE, null,
|
||||
user, "<span class='danger'>You shove [target.name]!</span>")
|
||||
target.Stagger(SHOVE_STAGGER_DURATION)
|
||||
var/obj/item/target_held_item = target.get_active_held_item()
|
||||
if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types))
|
||||
target_held_item = null
|
||||
if(!target.has_movespeed_modifier(/datum/movespeed_modifier/shove))
|
||||
target.add_movespeed_modifier(/datum/movespeed_modifier/shove)
|
||||
if(!target.has_status_effect(STATUS_EFFECT_OFF_BALANCE))
|
||||
if(target_held_item)
|
||||
if(!HAS_TRAIT(target_held_item, TRAIT_NODROP))
|
||||
target.visible_message("<span class='danger'>[target.name]'s grip on \the [target_held_item] loosens!</span>",
|
||||
@@ -1942,43 +1836,43 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
append_message += ", loosening their grip on [target_held_item]"
|
||||
else
|
||||
append_message += ", but couldn't loose their grip on [target_held_item]"
|
||||
addtimer(CALLBACK(target, /mob/living/carbon/human/proc/clear_shove_slowdown), SHOVE_SLOWDOWN_LENGTH)
|
||||
else if(target_held_item)
|
||||
if(target.dropItemToGround(target_held_item))
|
||||
target.visible_message("<span class='danger'>[target.name] drops \the [target_held_item]!!</span>",
|
||||
"<span class='danger'>You drop \the [target_held_item]!!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
append_message += ", causing them to drop [target_held_item]"
|
||||
target.ShoveOffBalance(SHOVE_OFFBALANCE_DURATION)
|
||||
log_combat(user, target, "shoved", append_message)
|
||||
|
||||
/datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, forced = FALSE)
|
||||
SEND_SIGNAL(src, COMSIG_MOB_APPLY_DAMGE, damage, damagetype, def_zone)
|
||||
/datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = SHARP_NONE)
|
||||
SEND_SIGNAL(H, COMSIG_MOB_APPLY_DAMGE, damage, damagetype, def_zone, wound_bonus, bare_wound_bonus, sharpness) // make sure putting wound_bonus here doesn't screw up other signals or uses for this signal
|
||||
var/hit_percent = (100-(blocked+armor))/100
|
||||
hit_percent = (hit_percent * (100-H.physiology.damage_resistance))/100
|
||||
if(!forced && hit_percent <= 0)
|
||||
return 0
|
||||
|
||||
var/obj/item/bodypart/BP = null
|
||||
if(isbodypart(def_zone))
|
||||
if(damagetype == STAMINA && istype(def_zone, /obj/item/bodypart/head))
|
||||
BP = H.get_bodypart(check_zone(BODY_ZONE_CHEST))
|
||||
if(!spread_damage)
|
||||
if(isbodypart(def_zone))
|
||||
if(damagetype == STAMINA && istype(def_zone, /obj/item/bodypart/head))
|
||||
BP = H.get_bodypart(check_zone(BODY_ZONE_CHEST))
|
||||
else
|
||||
BP = def_zone
|
||||
else
|
||||
BP = def_zone
|
||||
else
|
||||
if(!def_zone)
|
||||
def_zone = ran_zone(def_zone)
|
||||
if(damagetype == STAMINA && def_zone == BODY_ZONE_HEAD)
|
||||
def_zone = BODY_ZONE_CHEST
|
||||
BP = H.get_bodypart(check_zone(def_zone))
|
||||
|
||||
if(!BP)
|
||||
BP = H.bodyparts[1]
|
||||
if(!def_zone)
|
||||
def_zone = ran_zone(def_zone)
|
||||
if(damagetype == STAMINA && def_zone == BODY_ZONE_HEAD)
|
||||
def_zone = BODY_ZONE_CHEST
|
||||
BP = H.get_bodypart(check_zone(def_zone))
|
||||
if(!BP)
|
||||
BP = H.bodyparts[1]
|
||||
|
||||
switch(damagetype)
|
||||
if(BRUTE)
|
||||
H.damageoverlaytemp = 20
|
||||
var/damage_amount = forced ? damage : damage * hit_percent * brutemod * H.physiology.brute_mod
|
||||
if(BP)
|
||||
if(damage > 0 ? BP.receive_damage(damage_amount, 0) : BP.heal_damage(abs(damage_amount), 0))
|
||||
if(BP.receive_damage(damage_amount, 0, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness))
|
||||
H.update_damage_overlays()
|
||||
if(HAS_TRAIT(H, TRAIT_MASO) && prob(damage_amount))
|
||||
H.mob_climax(forced_climax=TRUE)
|
||||
@@ -1989,7 +1883,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
H.damageoverlaytemp = 20
|
||||
var/damage_amount = forced ? damage : damage * hit_percent * burnmod * H.physiology.burn_mod
|
||||
if(BP)
|
||||
if(damage > 0 ? BP.receive_damage(0, damage_amount) : BP.heal_damage(0, abs(damage_amount)))
|
||||
if(BP.receive_damage(0, damage_amount, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness))
|
||||
H.update_damage_overlays()
|
||||
else
|
||||
H.adjustFireLoss(damage_amount)
|
||||
@@ -2026,6 +1920,16 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
// called before a projectile hit
|
||||
return
|
||||
|
||||
/**
|
||||
* The human species version of [/mob/living/carbon/proc/get_biological_state]. Depends on the HAS_FLESH and HAS_BONE species traits, having bones lets you have bone wounds, having flesh lets you have burn, slash, and piercing wounds
|
||||
*/
|
||||
/datum/species/proc/get_biological_state(mob/living/carbon/human/H)
|
||||
. = BIO_INORGANIC
|
||||
if(HAS_FLESH in species_traits)
|
||||
. |= BIO_JUST_FLESH
|
||||
if(HAS_BONE in species_traits)
|
||||
. |= BIO_JUST_BONE
|
||||
|
||||
/////////////
|
||||
//BREATHING//
|
||||
/////////////
|
||||
@@ -2034,7 +1938,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
if(HAS_TRAIT(H, TRAIT_NOBREATH))
|
||||
return TRUE
|
||||
|
||||
|
||||
/datum/species/proc/handle_environment(datum/gas_mixture/environment, mob/living/carbon/human/H)
|
||||
if(!environment)
|
||||
return
|
||||
@@ -2219,12 +2122,13 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
/datum/species/proc/ExtinguishMob(mob/living/carbon/human/H)
|
||||
return
|
||||
|
||||
|
||||
////////////
|
||||
//Stun//
|
||||
////////////
|
||||
|
||||
/datum/species/proc/spec_stun(mob/living/carbon/human/H,amount)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
. = stunmod * H.physiology.stun_mod * amount
|
||||
|
||||
//////////////
|
||||
@@ -2242,11 +2146,30 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
////////////////
|
||||
|
||||
/datum/species/proc/can_wag_tail(mob/living/carbon/human/H)
|
||||
return FALSE
|
||||
if(!tail_type || !wagging_type)
|
||||
return FALSE
|
||||
else
|
||||
return mutant_bodyparts[tail_type] || mutant_bodyparts[wagging_type]
|
||||
|
||||
/datum/species/proc/is_wagging_tail(mob/living/carbon/human/H)
|
||||
return FALSE
|
||||
return mutant_bodyparts[wagging_type]
|
||||
|
||||
/datum/species/proc/start_wagging_tail(mob/living/carbon/human/H)
|
||||
if(tail_type && wagging_type)
|
||||
if(mutant_bodyparts[tail_type])
|
||||
mutant_bodyparts[wagging_type] = mutant_bodyparts[tail_type]
|
||||
mutant_bodyparts -= tail_type
|
||||
if(tail_type == "tail_lizard") //special lizard thing
|
||||
mutant_bodyparts["waggingspines"] = mutant_bodyparts["spines"]
|
||||
mutant_bodyparts -= "spines"
|
||||
H.update_body()
|
||||
|
||||
/datum/species/proc/stop_wagging_tail(mob/living/carbon/human/H)
|
||||
if(tail_type && wagging_type)
|
||||
if(mutant_bodyparts[wagging_type])
|
||||
mutant_bodyparts[tail_type] = mutant_bodyparts[wagging_type]
|
||||
mutant_bodyparts -= wagging_type
|
||||
if(tail_type == "tail_lizard") //special lizard thing
|
||||
mutant_bodyparts["spines"] = mutant_bodyparts["waggingspines"]
|
||||
mutant_bodyparts -= "waggingspines"
|
||||
H.update_body()
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
id = "abductor"
|
||||
say_mod = "gibbers"
|
||||
sexes = FALSE
|
||||
species_traits = list(NOBLOOD,NOEYES,NOGENITALS,NOAROUSAL)
|
||||
species_traits = list(NOBLOOD,NOEYES,NOGENITALS,NOAROUSAL,HAS_FLESH,HAS_BONE)
|
||||
inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_CHUNKYFINGERS,TRAIT_NOHUNGER,TRAIT_NOBREATH)
|
||||
mutanttongue = /obj/item/organ/tongue/abductor
|
||||
species_type = "alien"
|
||||
|
||||
/datum/species/abductor/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
. = ..()
|
||||
|
||||
@@ -11,3 +11,16 @@
|
||||
mutanttongue = /obj/item/organ/tongue/robot
|
||||
species_language_holder = /datum/language_holder/synthetic
|
||||
limbs_id = "synth"
|
||||
species_type = "robotic"
|
||||
|
||||
/datum/species/android/on_species_gain(mob/living/carbon/C)
|
||||
. = ..()
|
||||
for(var/X in C.bodyparts)
|
||||
var/obj/item/bodypart/O = X
|
||||
O.change_bodypart_status(BODYPART_ROBOTIC, FALSE, TRUE)
|
||||
|
||||
/datum/species/android/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
for(var/X in C.bodyparts)
|
||||
var/obj/item/bodypart/O = X
|
||||
O.change_bodypart_status(BODYPART_ORGANIC,FALSE, TRUE)
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
name = "Angel"
|
||||
id = "angel"
|
||||
default_color = "FFFFFF"
|
||||
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS)
|
||||
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,HAS_FLESH,HAS_BONE)
|
||||
mutant_bodyparts = list("tail_human" = "None", "ears" = "None", "wings" = "Angel")
|
||||
use_skintones = USE_SKINTONES_GRAYSCALE_CUSTOM
|
||||
no_equip = list(SLOT_BACK)
|
||||
blacklisted = 1
|
||||
limbs_id = "human"
|
||||
skinned_type = /obj/item/stack/sheet/animalhide/human
|
||||
species_type = "human" //they're a kind of human
|
||||
|
||||
var/datum/action/innate/flight/fly
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
id = "insect"
|
||||
say_mod = "chitters"
|
||||
default_color = "00FF00"
|
||||
species_traits = list(LIPS,EYECOLOR,HAIR,FACEHAIR,MUTCOLORS,HORNCOLOR,WINGCOLOR)
|
||||
species_traits = list(LIPS,EYECOLOR,HAIR,FACEHAIR,MUTCOLORS,HORNCOLOR,WINGCOLOR,HAS_FLESH,HAS_BONE)
|
||||
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG
|
||||
mutant_bodyparts = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None",
|
||||
mutant_bodyparts = list("mcolor" = "FFFFFF","mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_tail" = "None", "mam_ears" = "None",
|
||||
"insect_wings" = "None", "insect_fluff" = "None", "mam_snouts" = "None", "taur" = "None", "insect_markings" = "None")
|
||||
attack_verb = "slash"
|
||||
attack_sound = 'sound/weapons/slash.ogg'
|
||||
@@ -13,35 +13,11 @@
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/insect
|
||||
liked_food = MEAT | FRUIT
|
||||
disliked_food = TOXIC
|
||||
icon_limbs = DEFAULT_BODYPART_ICON_CITADEL
|
||||
exotic_bloodtype = "BUG"
|
||||
exotic_blood_color = BLOOD_COLOR_BUG
|
||||
|
||||
/datum/species/insect/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
tail_type = "mam_tail"
|
||||
wagging_type = "mam_waggingtail"
|
||||
species_type = "insect"
|
||||
|
||||
/datum/species/insect/spec_stun(mob/living/carbon/human/H,amount)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
. = ..()
|
||||
|
||||
/datum/species/insect/can_wag_tail(mob/living/carbon/human/H)
|
||||
return mutant_bodyparts["mam_tail"] || mutant_bodyparts["mam_waggingtail"]
|
||||
|
||||
/datum/species/insect/is_wagging_tail(mob/living/carbon/human/H)
|
||||
return mutant_bodyparts["mam_waggingtail"]
|
||||
|
||||
/datum/species/insect/start_wagging_tail(mob/living/carbon/human/H)
|
||||
if(mutant_bodyparts["mam_tail"])
|
||||
mutant_bodyparts["mam_waggingtail"] = mutant_bodyparts["mam_tail"]
|
||||
mutant_bodyparts -= "mam_tail"
|
||||
H.update_body()
|
||||
|
||||
/datum/species/insect/stop_wagging_tail(mob/living/carbon/human/H)
|
||||
if(mutant_bodyparts["mam_waggingtail"])
|
||||
mutant_bodyparts["mam_tail"] = mutant_bodyparts["mam_waggingtail"]
|
||||
mutant_bodyparts -= "mam_waggingtail"
|
||||
H.update_body()
|
||||
|
||||
/datum/species/insect/qualifies_for_rank(rank, list/features)
|
||||
return TRUE
|
||||
allowed_limb_ids = list("insect","apid","moth","moth_not_greyscale")
|
||||
|
||||
@@ -17,4 +17,5 @@
|
||||
species_traits = list(NOBLOOD,EYECOLOR,NOGENITALS)
|
||||
inherent_traits = list(TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOLIMBDISABLE,TRAIT_NOHUNGER)
|
||||
sexes = 0
|
||||
gib_types = /obj/effect/gibspawner/robot
|
||||
gib_types = /obj/effect/gibspawner/robot
|
||||
species_type = "robotic"
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "Dullahan"
|
||||
id = "dullahan"
|
||||
default_color = "FFFFFF"
|
||||
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS)
|
||||
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,HAS_FLESH,HAS_BONE)
|
||||
inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH)
|
||||
mutant_bodyparts = list("tail_human" = "None", "ears" = "None", "deco_wings" = "None")
|
||||
use_skintones = USE_SKINTONES_GRAYSCALE_CUSTOM
|
||||
@@ -14,6 +14,7 @@
|
||||
limbs_id = "human"
|
||||
skinned_type = /obj/item/stack/sheet/animalhide/human
|
||||
has_field_of_vision = FALSE //Too much of a trouble, their vision is already bound to their severed head.
|
||||
species_type = "undead"
|
||||
var/pumpkin = FALSE
|
||||
|
||||
var/obj/item/dullahan_relay/myhead
|
||||
|
||||
@@ -6,7 +6,7 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
|
||||
name = "Dwarf"
|
||||
id = "dwarf" //Also called Homo sapiens pumilionis
|
||||
default_color = "FFFFFF"
|
||||
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS)
|
||||
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,HAS_FLESH,HAS_BONE)
|
||||
inherent_traits = list(TRAIT_DWARF,TRAIT_SNOB)
|
||||
limbs_id = "human"
|
||||
use_skintones = USE_SKINTONES_GRAYSCALE_CUSTOM
|
||||
@@ -18,6 +18,7 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
|
||||
mutant_organs = list(/obj/item/organ/dwarfgland) //Dwarven alcohol gland, literal gland warrior
|
||||
mutantliver = /obj/item/organ/liver/dwarf //Dwarven super liver (Otherwise they r doomed)
|
||||
species_language_holder = /datum/language_holder/dwarf
|
||||
species_type = "human" //a kind of human
|
||||
|
||||
/mob/living/carbon/human/species/dwarf //species admin spawn path
|
||||
race = /datum/species/dwarf //and the race the path is set to.
|
||||
@@ -89,11 +90,7 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
|
||||
//These count in on_life ticks which should be 2 seconds per every increment of 1 in a perfect world.
|
||||
var/dwarf_eth_ticker = 0 //Currently set =< 1, that means this will fire the proc around every 2 seconds
|
||||
var/last_alcohol_spam
|
||||
|
||||
/obj/item/organ/dwarfgland/prepare_eat()
|
||||
var/obj/S = ..()
|
||||
S.reagents.add_reagent(/datum/reagent/consumable/ethanol, stored_alcohol/10)
|
||||
return S
|
||||
food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/ethanol = 10)
|
||||
|
||||
/obj/item/organ/dwarfgland/on_life() //Primary loop to hook into to start delayed loops for other loops..
|
||||
. = ..()
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
#define ETHEREAL_COLORS list("#00ffff", "#ffc0cb", "#9400D3", "#4B0082", "#0000FF", "#00FF00", "#FFFF00", "#FF7F00", "#FF0000")
|
||||
|
||||
/datum/species/ethereal
|
||||
name = "Ethereal"
|
||||
id = "ethereal"
|
||||
attack_verb = "burn"
|
||||
attack_sound = 'sound/weapons/etherealhit.ogg'
|
||||
miss_sound = 'sound/weapons/etherealmiss.ogg'
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ethereal
|
||||
mutantstomach = /obj/item/organ/stomach/ethereal
|
||||
mutanttongue = /obj/item/organ/tongue/ethereal
|
||||
exotic_blood = /datum/reagent/consumable/liquidelectricity //Liquid Electricity. fuck you think of something better gamer
|
||||
siemens_coeff = 0.5 //They thrive on energy
|
||||
brutemod = 1.25 //They're weak to punches
|
||||
attack_type = BURN //burn bish
|
||||
damage_overlay_type = "" //We are too cool for regular damage overlays
|
||||
species_traits = list(MUTCOLORS, HAIR, HAS_FLESH, HAS_BONE) // i mean i guess they have blood so they can have wounds too
|
||||
species_language_holder = /datum/language_holder/ethereal
|
||||
inherent_traits = list(TRAIT_NOHUNGER)
|
||||
sexes = FALSE
|
||||
toxic_food = NONE
|
||||
/*
|
||||
citadel doesn't have per-species temperatures, yet
|
||||
// Body temperature for ethereals is much higher then humans as they like hotter environments
|
||||
bodytemp_normal = (BODYTEMP_NORMAL + 50)
|
||||
bodytemp_heat_damage_limit = FIRE_MINIMUM_TEMPERATURE_TO_SPREAD // about 150C
|
||||
// Cold temperatures hurt faster as it is harder to move with out the heat energy
|
||||
bodytemp_cold_damage_limit = (T20C - 10) // about 10c
|
||||
*/
|
||||
hair_color = "mutcolor"
|
||||
hair_alpha = 140
|
||||
var/current_color
|
||||
var/EMPeffect = FALSE
|
||||
var/emageffect = FALSE
|
||||
var/r1
|
||||
var/g1
|
||||
var/b1
|
||||
var/static/r2 = 237
|
||||
var/static/g2 = 164
|
||||
var/static/b2 = 149
|
||||
//this is shit but how do i fix it? no clue.
|
||||
var/drain_time = 0 //used to keep ethereals from spam draining power sources
|
||||
|
||||
/datum/species/ethereal/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load)
|
||||
.=..()
|
||||
if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
default_color = "#" + H.dna.features["mcolor"]
|
||||
r1 = GETREDPART(default_color)
|
||||
g1 = GETGREENPART(default_color)
|
||||
b1 = GETBLUEPART(default_color)
|
||||
spec_updatehealth(H)
|
||||
RegisterSignal(C, COMSIG_ATOM_EMAG_ACT, .proc/on_emag_act)
|
||||
RegisterSignal(C, COMSIG_ATOM_EMP_ACT, .proc/on_emp_act)
|
||||
|
||||
/datum/species/ethereal/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load)
|
||||
.=..()
|
||||
C.set_light(0)
|
||||
UnregisterSignal(C, COMSIG_ATOM_EMAG_ACT)
|
||||
UnregisterSignal(C, COMSIG_ATOM_EMP_ACT)
|
||||
|
||||
/datum/species/ethereal/random_name(gender,unique,lastname)
|
||||
if(unique)
|
||||
return random_unique_ethereal_name()
|
||||
|
||||
var/randname = ethereal_name()
|
||||
|
||||
return randname
|
||||
|
||||
/datum/species/ethereal/spec_updatehealth(mob/living/carbon/human/H)
|
||||
.=..()
|
||||
if(H.stat != DEAD && !EMPeffect)
|
||||
var/healthpercent = max(H.health, 0) / 100
|
||||
if(!emageffect)
|
||||
current_color = rgb(r2 + ((r1-r2)*healthpercent), g2 + ((g1-g2)*healthpercent), b2 + ((b1-b2)*healthpercent))
|
||||
H.set_light(1 + (2 * healthpercent), 1 + (1 * healthpercent), current_color)
|
||||
fixed_mut_color = copytext_char(current_color, 2)
|
||||
else
|
||||
H.set_light(0)
|
||||
fixed_mut_color = rgb(128,128,128)
|
||||
H.update_body()
|
||||
|
||||
/datum/species/ethereal/proc/on_emp_act(mob/living/carbon/human/H, severity)
|
||||
EMPeffect = TRUE
|
||||
spec_updatehealth(H)
|
||||
to_chat(H, "<span class='notice'>You feel the light of your body leave you.</span>")
|
||||
switch(severity)
|
||||
if(EMP_LIGHT)
|
||||
addtimer(CALLBACK(src, .proc/stop_emp, H), 10 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) //We're out for 10 seconds
|
||||
if(EMP_HEAVY)
|
||||
addtimer(CALLBACK(src, .proc/stop_emp, H), 20 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) //We're out for 20 seconds
|
||||
|
||||
/datum/species/ethereal/proc/on_emag_act(mob/living/carbon/human/H, mob/user)
|
||||
if(emageffect)
|
||||
return
|
||||
emageffect = TRUE
|
||||
if(user)
|
||||
to_chat(user, "<span class='notice'>You tap [H] on the back with your card.</span>")
|
||||
H.visible_message("<span class='danger'>[H] starts flickering in an array of colors!</span>")
|
||||
handle_emag(H)
|
||||
addtimer(CALLBACK(src, .proc/stop_emag, H), 30 SECONDS) //Disco mode for 30 seconds! This doesn't affect the ethereal at all besides either annoying some players, or making someone look badass.
|
||||
|
||||
|
||||
/datum/species/ethereal/spec_life(mob/living/carbon/human/H)
|
||||
.=..()
|
||||
handle_charge(H)
|
||||
|
||||
|
||||
/datum/species/ethereal/proc/stop_emp(mob/living/carbon/human/H)
|
||||
EMPeffect = FALSE
|
||||
spec_updatehealth(H)
|
||||
to_chat(H, "<span class='notice'>You feel more energized as your shine comes back.</span>")
|
||||
|
||||
|
||||
/datum/species/ethereal/proc/handle_emag(mob/living/carbon/human/H)
|
||||
if(!emageffect)
|
||||
return
|
||||
current_color = pick(ETHEREAL_COLORS)
|
||||
spec_updatehealth(H)
|
||||
addtimer(CALLBACK(src, .proc/handle_emag, H), 5) //Call ourselves every 0.5 seconds to change color
|
||||
|
||||
/datum/species/ethereal/proc/stop_emag(mob/living/carbon/human/H)
|
||||
emageffect = FALSE
|
||||
spec_updatehealth(H)
|
||||
H.visible_message("<span class='danger'>[H] stops flickering and goes back to their normal state!</span>")
|
||||
|
||||
/datum/species/ethereal/proc/handle_charge(mob/living/carbon/human/H)
|
||||
brutemod = 1.25
|
||||
switch(get_charge(H))
|
||||
if(ETHEREAL_CHARGE_NONE)
|
||||
H.throw_alert("ethereal_charge", /obj/screen/alert/etherealcharge, 3)
|
||||
if(ETHEREAL_CHARGE_NONE to ETHEREAL_CHARGE_LOWPOWER)
|
||||
H.throw_alert("ethereal_charge", /obj/screen/alert/etherealcharge, 2)
|
||||
if(H.health > 10.5)
|
||||
apply_damage(0.65, TOX, null, null, H)
|
||||
brutemod = 1.75
|
||||
if(ETHEREAL_CHARGE_LOWPOWER to ETHEREAL_CHARGE_NORMAL)
|
||||
H.throw_alert("ethereal_charge", /obj/screen/alert/etherealcharge, 1)
|
||||
brutemod = 1.5
|
||||
if(ETHEREAL_CHARGE_FULL to ETHEREAL_CHARGE_OVERLOAD)
|
||||
H.throw_alert("ethereal_overcharge", /obj/screen/alert/ethereal_overcharge, 1)
|
||||
apply_damage(0.2, TOX, null, null, H)
|
||||
brutemod = 1.5
|
||||
if(ETHEREAL_CHARGE_OVERLOAD to ETHEREAL_CHARGE_DANGEROUS)
|
||||
H.throw_alert("ethereal_overcharge", /obj/screen/alert/ethereal_overcharge, 2)
|
||||
apply_damage(0.65, TOX, null, null, H)
|
||||
brutemod = 1.75
|
||||
if(prob(10)) //10% each tick for ethereals to explosively release excess energy if it reaches dangerous levels
|
||||
discharge_process(H)
|
||||
else
|
||||
H.clear_alert("ethereal_charge")
|
||||
H.clear_alert("ethereal_overcharge")
|
||||
|
||||
/datum/species/ethereal/proc/discharge_process(mob/living/carbon/human/H)
|
||||
to_chat(H, "<span class='warning'>You begin to lose control over your charge!</span>")
|
||||
H.visible_message("<span class='danger'>[H] begins to spark violently!</span>")
|
||||
var/static/mutable_appearance/overcharge //shameless copycode from lightning spell
|
||||
overcharge = overcharge || mutable_appearance('icons/effects/effects.dmi', "electricity", EFFECTS_LAYER)
|
||||
H.add_overlay(overcharge)
|
||||
if(do_mob(H, H, 50, 1))
|
||||
H.flash_lighting_fx(5, 7, current_color)
|
||||
var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH)
|
||||
playsound(H, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5)
|
||||
H.cut_overlay(overcharge)
|
||||
tesla_zap(H, 2, stomach.crystal_charge*50, ZAP_OBJ_DAMAGE | ZAP_ALLOW_DUPLICATES)
|
||||
if(istype(stomach))
|
||||
stomach.adjust_charge(100 - stomach.crystal_charge)
|
||||
to_chat(H, "<span class='warning'>You violently discharge energy!</span>")
|
||||
H.visible_message("<span class='danger'>[H] violently discharges energy!</span>")
|
||||
if(prob(10)) //chance of developing heart disease to dissuade overcharging oneself
|
||||
var/datum/disease/D = new /datum/disease/heart_failure
|
||||
H.ForceContractDisease(D)
|
||||
to_chat(H, "<span class='userdanger'>You're pretty sure you just felt your heart stop for a second there..</span>")
|
||||
H.playsound_local(H, 'sound/effects/singlebeat.ogg', 100, 0)
|
||||
H.Paralyze(100)
|
||||
return
|
||||
|
||||
/datum/species/ethereal/proc/get_charge(mob/living/carbon/H) //this feels like it should be somewhere else. Eh?
|
||||
var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH)
|
||||
if(istype(stomach))
|
||||
return stomach.crystal_charge
|
||||
return ETHEREAL_CHARGE_NONE
|
||||
@@ -9,37 +9,9 @@
|
||||
mutantears = /obj/item/organ/ears/cat
|
||||
mutanttail = /obj/item/organ/tail/cat
|
||||
|
||||
/datum/species/human/felinid/qualifies_for_rank(rank, list/features)
|
||||
return TRUE
|
||||
|
||||
//Curiosity killed the cat's wagging tail.
|
||||
/datum/species/human/felinid/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
|
||||
/datum/species/human/felinid/spec_stun(mob/living/carbon/human/H,amount)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
. = ..()
|
||||
|
||||
|
||||
/datum/species/human/felinid/can_wag_tail(mob/living/carbon/human/H)
|
||||
return mutant_bodyparts["mam_tail"] || mutant_bodyparts["mam_waggingtail"]
|
||||
|
||||
/datum/species/human/felinid/is_wagging_tail(mob/living/carbon/human/H)
|
||||
return mutant_bodyparts["mam_waggingtail"]
|
||||
|
||||
/datum/species/human/felinid/start_wagging_tail(mob/living/carbon/human/H)
|
||||
if(mutant_bodyparts["mam_tail"])
|
||||
mutant_bodyparts["mam_waggingtail"] = mutant_bodyparts["mam_tail"]
|
||||
mutant_bodyparts -= "mam_tail"
|
||||
H.update_body()
|
||||
|
||||
/datum/species/human/felinid/stop_wagging_tail(mob/living/carbon/human/H)
|
||||
if(mutant_bodyparts["mam_waggingtail"])
|
||||
mutant_bodyparts["mam_tail"] = mutant_bodyparts["mam_waggingtail"]
|
||||
mutant_bodyparts -= "mam_waggingtail"
|
||||
H.update_body()
|
||||
tail_type = "mam_tail"
|
||||
wagging_type = "mam_waggingtail"
|
||||
species_type = "furry"
|
||||
|
||||
/datum/species/human/felinid/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load)
|
||||
if(ishuman(C))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "Anthromorphic Fly"
|
||||
id = "fly"
|
||||
say_mod = "buzzes"
|
||||
species_traits = list(NOEYES)
|
||||
species_traits = list(NOEYES,HAS_FLESH,HAS_BONE)
|
||||
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG
|
||||
mutanttongue = /obj/item/organ/tongue/fly
|
||||
mutantliver = /obj/item/organ/liver/fly
|
||||
@@ -11,6 +11,8 @@
|
||||
disliked_food = null
|
||||
liked_food = GROSS
|
||||
exotic_bloodtype = "BUG"
|
||||
exotic_blood_color = BLOOD_COLOR_BUG
|
||||
species_type = "insect"
|
||||
|
||||
/datum/species/fly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
|
||||
if(istype(chem, /datum/reagent/toxin/pestkiller))
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
name = "Anthromorph"
|
||||
id = "mammal"
|
||||
default_color = "4B4B4B"
|
||||
icon_limbs = DEFAULT_BODYPART_ICON_CITADEL
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR,HORNCOLOR,WINGCOLOR)
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR,HORNCOLOR,WINGCOLOR,HAS_FLESH,HAS_BONE)
|
||||
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BEAST
|
||||
mutant_bodyparts = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "deco_wings" = "None",
|
||||
mutant_bodyparts = list("mcolor" = "FFFFFF","mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "deco_wings" = "None",
|
||||
"mam_body_markings" = "Husky", "taur" = "None", "horns" = "None", "legs" = "Plantigrade", "meat_type" = "Mammalian")
|
||||
attack_verb = "claw"
|
||||
attack_sound = 'sound/weapons/slash.ogg'
|
||||
@@ -14,67 +13,8 @@
|
||||
liked_food = MEAT | FRIED
|
||||
disliked_food = TOXIC
|
||||
|
||||
//Curiosity killed the cat's wagging tail.
|
||||
/datum/species/mammal/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
tail_type = "mam_tail"
|
||||
wagging_type = "mam_waggingtail"
|
||||
species_type = "furry"
|
||||
|
||||
/datum/species/mammal/spec_stun(mob/living/carbon/human/H,amount)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
. = ..()
|
||||
|
||||
/datum/species/mammal/can_wag_tail(mob/living/carbon/human/H)
|
||||
return mutant_bodyparts["mam_tail"] || mutant_bodyparts["mam_waggingtail"]
|
||||
|
||||
/datum/species/mammal/is_wagging_tail(mob/living/carbon/human/H)
|
||||
return mutant_bodyparts["mam_waggingtail"]
|
||||
|
||||
/datum/species/mammal/start_wagging_tail(mob/living/carbon/human/H)
|
||||
if(mutant_bodyparts["mam_tail"])
|
||||
mutant_bodyparts["mam_waggingtail"] = mutant_bodyparts["mam_tail"]
|
||||
mutant_bodyparts -= "mam_tail"
|
||||
H.update_body()
|
||||
|
||||
/datum/species/mammal/stop_wagging_tail(mob/living/carbon/human/H)
|
||||
if(mutant_bodyparts["mam_waggingtail"])
|
||||
mutant_bodyparts["mam_tail"] = mutant_bodyparts["mam_waggingtail"]
|
||||
mutant_bodyparts -= "mam_waggingtail"
|
||||
H.update_body()
|
||||
|
||||
|
||||
/datum/species/mammal/qualifies_for_rank(rank, list/features)
|
||||
return TRUE
|
||||
|
||||
|
||||
//Alien//
|
||||
/datum/species/xeno
|
||||
// A cloning mistake, crossing human and xenomorph DNA
|
||||
name = "Xenomorph Hybrid"
|
||||
id = "xeno"
|
||||
say_mod = "hisses"
|
||||
default_color = "00FF00"
|
||||
icon_limbs = DEFAULT_BODYPART_ICON_CITADEL
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,LIPS)
|
||||
mutant_bodyparts = list("xenotail"="Xenomorph Tail","xenohead"="Standard","xenodorsal"="Standard", "mam_body_markings" = "Xeno","mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0","taur" = "None", "legs" = "Digitigrade")
|
||||
attack_verb = "slash"
|
||||
attack_sound = 'sound/weapons/slash.ogg'
|
||||
miss_sound = 'sound/weapons/slashmiss.ogg'
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/xeno
|
||||
gib_types = list(/obj/effect/gibspawner/xeno/xenoperson, /obj/effect/gibspawner/xeno/xenoperson/bodypartless)
|
||||
skinned_type = /obj/item/stack/sheet/animalhide/xeno
|
||||
exotic_bloodtype = "X*"
|
||||
damage_overlay_type = "xeno"
|
||||
liked_food = MEAT
|
||||
|
||||
//Praise the Omnissiah, A challange worthy of my skills - HS
|
||||
|
||||
//EXOTIC//
|
||||
//These races will likely include lots of downsides and upsides. Keep them relatively balanced.//
|
||||
|
||||
//misc
|
||||
/mob/living/carbon/human/dummy
|
||||
vore_flags = NO_VORE
|
||||
|
||||
/mob/living/carbon/human/vore
|
||||
vore_flags = DEVOURABLE | DIGESTABLE | FEEDING
|
||||
allowed_limb_ids = list("mammal","aquatic","avian")
|
||||
@@ -32,6 +32,8 @@
|
||||
var/special_name_chance = 5
|
||||
var/owner //dobby is a free golem
|
||||
|
||||
species_type = "golem"
|
||||
|
||||
/datum/species/golem/random_name(gender,unique,lastname)
|
||||
var/golem_surname = pick(GLOB.golem_names)
|
||||
// 3% chance that our golem has a human surname, because
|
||||
@@ -422,9 +424,9 @@
|
||||
else
|
||||
reactive_teleport(H)
|
||||
|
||||
/datum/species/golem/bluespace/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
|
||||
/datum/species/golem/bluespace/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style, act_intent, unarmed_attack_flags)
|
||||
..()
|
||||
if(world.time > last_teleport + teleport_cooldown && M != H && M.a_intent != INTENT_HELP)
|
||||
if(world.time > last_teleport + teleport_cooldown && M != H && act_intent != INTENT_HELP)
|
||||
reactive_teleport(H)
|
||||
|
||||
/datum/species/golem/bluespace/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
|
||||
@@ -519,9 +521,9 @@
|
||||
var/golem_name = "[uppertext(clown_name)]"
|
||||
return golem_name
|
||||
|
||||
/datum/species/golem/bananium/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
|
||||
/datum/species/golem/bananium/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style, act_intent, unarmed_attack_flags)
|
||||
..()
|
||||
if(world.time > last_banana + banana_cooldown && M != H && M.a_intent != INTENT_HELP)
|
||||
if(world.time > last_banana + banana_cooldown && M != H && act_intent != INTENT_HELP)
|
||||
new/obj/item/grown/bananapeel/specialpeel(get_turf(H))
|
||||
last_banana = world.time
|
||||
|
||||
@@ -830,9 +832,9 @@
|
||||
if(world.time > last_gong_time + gong_cooldown)
|
||||
gong(H)
|
||||
|
||||
/datum/species/golem/bronze/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
|
||||
/datum/species/golem/bronze/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style, act_intent, unarmed_attack_flags)
|
||||
..()
|
||||
if(world.time > last_gong_time + gong_cooldown && M.a_intent != INTENT_HELP)
|
||||
if(world.time > last_gong_time + gong_cooldown && act_intent != INTENT_HELP)
|
||||
gong(H)
|
||||
|
||||
/datum/species/golem/bronze/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
|
||||
|
||||
@@ -3,15 +3,16 @@
|
||||
id = "human"
|
||||
default_color = "FFFFFF"
|
||||
|
||||
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS_PARTSONLY,WINGCOLOR)
|
||||
mutant_bodyparts = list("mcolor" = "FFF", "mcolor2" = "FFF","mcolor3" = "FFF","tail_human" = "None", "ears" = "None", "taur" = "None", "deco_wings" = "None")
|
||||
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS_PARTSONLY,WINGCOLOR,HAS_FLESH,HAS_BONE)
|
||||
mutant_bodyparts = list("mcolor" = "FFFFFF", "mcolor2" = "FFFFFF","mcolor3" = "FFFFFF","tail_human" = "None", "ears" = "None", "taur" = "None", "deco_wings" = "None")
|
||||
use_skintones = USE_SKINTONES_GRAYSCALE_CUSTOM
|
||||
skinned_type = /obj/item/stack/sheet/animalhide/human
|
||||
disliked_food = GROSS | RAW
|
||||
liked_food = JUNKFOOD | FRIED
|
||||
|
||||
/datum/species/human/qualifies_for_rank(rank, list/features)
|
||||
return TRUE //Pure humans are always allowed in all roles.
|
||||
tail_type = "tail_human"
|
||||
wagging_type = "waggingtail_human"
|
||||
species_type = "human"
|
||||
|
||||
/datum/species/human/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
if(H)
|
||||
@@ -21,21 +22,3 @@
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
. = ..()
|
||||
|
||||
/datum/species/human/can_wag_tail(mob/living/carbon/human/H)
|
||||
return mutant_bodyparts["tail_human"] || mutant_bodyparts["waggingtail_human"]
|
||||
|
||||
/datum/species/human/is_wagging_tail(mob/living/carbon/human/H)
|
||||
return mutant_bodyparts["waggingtail_human"]
|
||||
|
||||
/datum/species/human/start_wagging_tail(mob/living/carbon/human/H)
|
||||
if(mutant_bodyparts["tail_human"])
|
||||
mutant_bodyparts["waggingtail_human"] = mutant_bodyparts["tail_human"]
|
||||
mutant_bodyparts -= "tail_human"
|
||||
H.update_body()
|
||||
|
||||
/datum/species/human/stop_wagging_tail(mob/living/carbon/human/H)
|
||||
if(mutant_bodyparts["waggingtail_human"])
|
||||
mutant_bodyparts["tail_human"] = mutant_bodyparts["waggingtail_human"]
|
||||
mutant_bodyparts -= "waggingtail_human"
|
||||
H.update_body()
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
id = "ipc"
|
||||
say_mod = "beeps"
|
||||
default_color = "00FF00"
|
||||
icon_limbs = DEFAULT_BODYPART_ICON_CITADEL
|
||||
blacklisted = 0
|
||||
sexes = 0
|
||||
species_traits = list(MUTCOLORS,NOEYES,NOTRANSSTING,ROBOTIC_LIMBS)
|
||||
species_traits = list(MUTCOLORS,NOEYES,NOTRANSSTING,ROBOTIC_LIMBS,HAS_FLESH,HAS_BONE)
|
||||
inherent_traits = list(TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NO_PROCESS_FOOD)
|
||||
inherent_biotypes = MOB_ROBOTIC|MOB_HUMANOID
|
||||
mutant_bodyparts = list("ipc_screen" = "Blank", "ipc_antenna" = "None")
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ipc
|
||||
gib_types = list(/obj/effect/gibspawner/ipc, /obj/effect/gibspawner/ipc/bodypartless)
|
||||
@@ -26,6 +26,8 @@
|
||||
mutant_organs = list(/obj/item/organ/cyberimp/arm/power_cord)
|
||||
|
||||
exotic_bloodtype = "HF"
|
||||
exotic_blood_color = BLOOD_COLOR_OIL
|
||||
species_type = "robotic"
|
||||
|
||||
var/datum/action/innate/monitor_change/screen
|
||||
|
||||
|
||||
@@ -4,15 +4,16 @@
|
||||
id = "jelly"
|
||||
default_color = "00FF90"
|
||||
say_mod = "chirps"
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,WINGCOLOR)
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,WINGCOLOR,HAS_FLESH)
|
||||
mutantlungs = /obj/item/organ/lungs/slime
|
||||
mutant_heart = /obj/item/organ/heart/slime
|
||||
mutant_bodyparts = list("mcolor" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_snouts" = "None", "taur" = "None", "deco_wings" = "None")
|
||||
mutant_bodyparts = list("mcolor" = "FFFFFF", "mam_tail" = "None", "mam_ears" = "None", "mam_snouts" = "None", "taur" = "None", "deco_wings" = "None")
|
||||
inherent_traits = list(TRAIT_TOXINLOVER)
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/slime
|
||||
gib_types = list(/obj/effect/gibspawner/slime, /obj/effect/gibspawner/slime/bodypartless)
|
||||
exotic_blood = /datum/reagent/blood/jellyblood
|
||||
exotic_bloodtype = "GEL"
|
||||
exotic_blood_color = "BLOOD_COLOR_SLIME"
|
||||
damage_overlay_type = ""
|
||||
var/datum/action/innate/regenerate_limbs/regenerate_limbs
|
||||
var/datum/action/innate/slime_change/slime_change //CIT CHANGE
|
||||
@@ -22,6 +23,17 @@
|
||||
heatmod = 0.5 // = 1/4x heat damage
|
||||
burnmod = 0.5 // = 1/2x generic burn damage
|
||||
species_language_holder = /datum/language_holder/jelly
|
||||
mutant_brain = /obj/item/organ/brain/jelly
|
||||
|
||||
tail_type = "mam_tail"
|
||||
wagging_type = "mam_waggingtail"
|
||||
species_type = "jelly"
|
||||
|
||||
/obj/item/organ/brain/jelly
|
||||
name = "slime nucleus"
|
||||
desc = "A slimey membranous mass from a slime person"
|
||||
icon_state = "brain-slime"
|
||||
|
||||
|
||||
/datum/species/jelly/on_species_loss(mob/living/carbon/C)
|
||||
if(regenerate_limbs)
|
||||
@@ -41,6 +53,11 @@
|
||||
slime_change.Grant(C) //CIT CHANGE
|
||||
C.faction |= "slime"
|
||||
|
||||
/datum/species/jelly/handle_body(mob/living/carbon/human/H)
|
||||
. = ..()
|
||||
//update blood color to body color
|
||||
exotic_blood_color = "#" + H.dna.features["mcolor"]
|
||||
|
||||
/datum/species/jelly/spec_life(mob/living/carbon/human/H)
|
||||
if(H.stat == DEAD || HAS_TRAIT(H, TRAIT_NOMARROW)) //can't farm slime jelly from a dead slime/jelly person indefinitely, and no regeneration for blooduskers
|
||||
return
|
||||
@@ -115,33 +132,6 @@
|
||||
return
|
||||
to_chat(H, "<span class='warning'>...but there is not enough of you to go around! You must attain more mass to heal!</span>")
|
||||
|
||||
/datum/species/jelly/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
|
||||
/datum/species/jelly/spec_stun(mob/living/carbon/human/H,amount)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
. = ..()
|
||||
|
||||
/datum/species/jelly/can_wag_tail(mob/living/carbon/human/H)
|
||||
return mutant_bodyparts["mam_tail"] || mutant_bodyparts["mam_waggingtail"]
|
||||
|
||||
/datum/species/jelly/is_wagging_tail(mob/living/carbon/human/H)
|
||||
return mutant_bodyparts["mam_waggingtail"]
|
||||
|
||||
/datum/species/jelly/start_wagging_tail(mob/living/carbon/human/H)
|
||||
if(mutant_bodyparts["mam_tail"])
|
||||
mutant_bodyparts["mam_waggingtail"] = mutant_bodyparts["mam_tail"]
|
||||
mutant_bodyparts -= "mam_tail"
|
||||
H.update_body()
|
||||
|
||||
/datum/species/jelly/stop_wagging_tail(mob/living/carbon/human/H)
|
||||
if(mutant_bodyparts["mam_waggingtail"])
|
||||
mutant_bodyparts["mam_tail"] = mutant_bodyparts["mam_waggingtail"]
|
||||
mutant_bodyparts -= "mam_waggingtail"
|
||||
H.update_body()
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////SLIMEPEOPLE///////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -239,7 +229,7 @@
|
||||
"<span class='notice'>You focus intently on moving your body while \
|
||||
standing perfectly still...</span>")
|
||||
|
||||
H.notransform = TRUE
|
||||
H.mob_transforming = TRUE
|
||||
|
||||
if(do_after(owner, delay=60, needhand=FALSE, target=owner, progress=TRUE))
|
||||
if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
|
||||
@@ -249,7 +239,7 @@
|
||||
else
|
||||
to_chat(H, "<span class='warning'>...but fail to stand perfectly still!</span>")
|
||||
|
||||
H.notransform = FALSE
|
||||
H.mob_transforming = FALSE
|
||||
|
||||
/datum/action/innate/split_body/proc/make_dupe()
|
||||
var/mob/living/carbon/human/H = owner
|
||||
@@ -267,7 +257,7 @@
|
||||
spare.Move(get_step(H.loc, pick(NORTH,SOUTH,EAST,WEST)))
|
||||
|
||||
H.blood_volume *= 0.45
|
||||
H.notransform = 0
|
||||
H.mob_transforming = 0
|
||||
|
||||
var/datum/species/jelly/slime/origin_datum = H.dna.species
|
||||
origin_datum.bodies |= spare
|
||||
@@ -297,11 +287,16 @@
|
||||
else
|
||||
ui_interact(owner)
|
||||
|
||||
/datum/action/innate/swap_body/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
|
||||
/datum/action/innate/swap_body/ui_host(mob/user)
|
||||
return owner
|
||||
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/datum/action/innate/swap_body/ui_state(mob/user)
|
||||
return GLOB.not_incapacitated_state
|
||||
|
||||
/datum/action/innate/swap_body/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "slime_swap_body", name, 400, 400, master_ui, state)
|
||||
ui = new(user, src, "SlimeBodySwapper", name)
|
||||
ui.open()
|
||||
|
||||
/datum/action/innate/swap_body/ui_data(mob/user)
|
||||
@@ -371,7 +366,8 @@
|
||||
return
|
||||
switch(action)
|
||||
if("swap")
|
||||
var/mob/living/carbon/human/selected = locate(params["ref"])
|
||||
var/datum/species/jelly/slime/SS = H.dna.species
|
||||
var/mob/living/carbon/human/selected = locate(params["ref"]) in SS.bodies
|
||||
if(!can_swap(selected))
|
||||
return
|
||||
SStgui.close_uis(src)
|
||||
@@ -430,7 +426,7 @@
|
||||
default_color = "00FFFF"
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR)
|
||||
inherent_traits = list(TRAIT_TOXINLOVER)
|
||||
mutant_bodyparts = list("mcolor" = "FFF", "mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_body_markings" = "Plain", "mam_snouts" = "None", "taur" = "None")
|
||||
mutant_bodyparts = list("mcolor" = "FFFFFF", "mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_tail" = "None", "mam_ears" = "None", "mam_body_markings" = "Plain", "mam_snouts" = "None", "taur" = "None")
|
||||
say_mod = "says"
|
||||
hair_color = "mutcolor"
|
||||
hair_alpha = 160 //a notch brighter so it blends better.
|
||||
@@ -466,8 +462,9 @@
|
||||
if(new_color)
|
||||
var/temp_hsv = RGBtoHSV(new_color)
|
||||
if(ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright
|
||||
H.dna.features["mcolor"] = sanitize_hexcolor(new_color)
|
||||
H.dna.features["mcolor"] = sanitize_hexcolor(new_color, 6)
|
||||
H.update_body()
|
||||
H.update_hair()
|
||||
else
|
||||
to_chat(H, "<span class='notice'>Invalid color. Your color is not bright enough.</span>")
|
||||
else if(select_alteration == "Hair Style")
|
||||
@@ -507,7 +504,7 @@
|
||||
else if (select_alteration == "Ears")
|
||||
var/list/snowflake_ears_list = list("Normal" = null)
|
||||
for(var/path in GLOB.mam_ears_list)
|
||||
var/datum/sprite_accessory/mam_ears/instance = GLOB.mam_ears_list[path]
|
||||
var/datum/sprite_accessory/ears/mam_ears/instance = GLOB.mam_ears_list[path]
|
||||
if(istype(instance, /datum/sprite_accessory))
|
||||
var/datum/sprite_accessory/S = instance
|
||||
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
|
||||
@@ -521,7 +518,7 @@
|
||||
else if (select_alteration == "Snout")
|
||||
var/list/snowflake_snouts_list = list("Normal" = null)
|
||||
for(var/path in GLOB.mam_snouts_list)
|
||||
var/datum/sprite_accessory/mam_snouts/instance = GLOB.mam_snouts_list[path]
|
||||
var/datum/sprite_accessory/snouts/mam_snouts/instance = GLOB.mam_snouts_list[path]
|
||||
if(istype(instance, /datum/sprite_accessory))
|
||||
var/datum/sprite_accessory/S = instance
|
||||
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
|
||||
@@ -533,7 +530,7 @@
|
||||
H.update_body()
|
||||
|
||||
else if (select_alteration == "Markings")
|
||||
var/list/snowflake_markings_list = list()
|
||||
var/list/snowflake_markings_list = list("None")
|
||||
for(var/path in GLOB.mam_body_markings_list)
|
||||
var/datum/sprite_accessory/mam_body_markings/instance = GLOB.mam_body_markings_list[path]
|
||||
if(istype(instance, /datum/sprite_accessory))
|
||||
@@ -544,8 +541,6 @@
|
||||
new_mam_body_markings = input(H, "Choose your character's body markings:", "Marking Alteration") as null|anything in snowflake_markings_list
|
||||
if(new_mam_body_markings)
|
||||
H.dna.features["mam_body_markings"] = new_mam_body_markings
|
||||
if(new_mam_body_markings == "None")
|
||||
H.dna.features["mam_body_markings"] = "Plain"
|
||||
for(var/X in H.bodyparts) //propagates the markings changes
|
||||
var/obj/item/bodypart/BP = X
|
||||
BP.update_limb(FALSE, H)
|
||||
@@ -554,7 +549,7 @@
|
||||
else if (select_alteration == "Tail")
|
||||
var/list/snowflake_tails_list = list("Normal" = null)
|
||||
for(var/path in GLOB.mam_tails_list)
|
||||
var/datum/sprite_accessory/mam_tails/instance = GLOB.mam_tails_list[path]
|
||||
var/datum/sprite_accessory/tails/mam_tails/instance = GLOB.mam_tails_list[path]
|
||||
if(istype(instance, /datum/sprite_accessory))
|
||||
var/datum/sprite_accessory/S = instance
|
||||
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
|
||||
|
||||
@@ -4,14 +4,13 @@
|
||||
id = "lizard"
|
||||
say_mod = "hisses"
|
||||
default_color = "00FF00"
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS,HORNCOLOR,WINGCOLOR)
|
||||
mutant_bodyparts = list("tail_lizard", "snout", "spines", "horns", "frills", "body_markings", "legs", "taur", "deco_wings")
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS,HORNCOLOR,WINGCOLOR,HAS_FLESH,HAS_BONE)
|
||||
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_REPTILE
|
||||
mutanttongue = /obj/item/organ/tongue/lizard
|
||||
mutanttail = /obj/item/organ/tail/lizard
|
||||
coldmod = 1.5
|
||||
heatmod = 0.67
|
||||
mutant_bodyparts = list("mcolor" = "0F0", "mcolor2" = "0F0", "mcolor3" = "0F0", "tail_lizard" = "Smooth", "snout" = "Round",
|
||||
mutant_bodyparts = list("mcolor" = "0F0", "mcolor2" = "0F0", "mcolor3" = "0F0", "tail_lizard" = "Smooth", "mam_snouts" = "Round",
|
||||
"horns" = "None", "frills" = "None", "spines" = "None", "body_markings" = "None",
|
||||
"legs" = "Digitigrade", "taur" = "None", "deco_wings" = "None")
|
||||
attack_verb = "slash"
|
||||
@@ -21,11 +20,16 @@
|
||||
gib_types = list(/obj/effect/gibspawner/lizard, /obj/effect/gibspawner/lizard/bodypartless)
|
||||
skinned_type = /obj/item/stack/sheet/animalhide/lizard
|
||||
exotic_bloodtype = "L"
|
||||
exotic_blood_color = BLOOD_COLOR_LIZARD
|
||||
disliked_food = GRAIN | DAIRY
|
||||
liked_food = GROSS | MEAT
|
||||
inert_mutation = FIREBREATH
|
||||
species_language_holder = /datum/language_holder/lizard
|
||||
|
||||
tail_type = "tail_lizard"
|
||||
wagging_type = "waggingtail_lizard"
|
||||
species_type = "lizard"
|
||||
|
||||
/datum/species/lizard/random_name(gender,unique,lastname)
|
||||
if(unique)
|
||||
return random_unique_lizard_name(gender)
|
||||
@@ -37,41 +41,6 @@
|
||||
|
||||
return randname
|
||||
|
||||
/datum/species/lizard/qualifies_for_rank(rank, list/features)
|
||||
return TRUE
|
||||
|
||||
//I wag in death
|
||||
/datum/species/lizard/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
|
||||
/datum/species/lizard/spec_stun(mob/living/carbon/human/H,amount)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
. = ..()
|
||||
|
||||
/datum/species/lizard/can_wag_tail(mob/living/carbon/human/H)
|
||||
return mutant_bodyparts["tail_lizard"] || mutant_bodyparts["waggingtail_lizard"]
|
||||
|
||||
/datum/species/lizard/is_wagging_tail(mob/living/carbon/human/H)
|
||||
return mutant_bodyparts["waggingtail_lizard"]
|
||||
|
||||
/datum/species/lizard/start_wagging_tail(mob/living/carbon/human/H)
|
||||
if(mutant_bodyparts["tail_lizard"])
|
||||
mutant_bodyparts["waggingtail_lizard"] = mutant_bodyparts["tail_lizard"]
|
||||
mutant_bodyparts["waggingspines"] = mutant_bodyparts["spines"]
|
||||
mutant_bodyparts -= "tail_lizard"
|
||||
mutant_bodyparts -= "spines"
|
||||
H.update_body()
|
||||
|
||||
/datum/species/lizard/stop_wagging_tail(mob/living/carbon/human/H)
|
||||
if(mutant_bodyparts["waggingtail_lizard"])
|
||||
mutant_bodyparts["tail_lizard"] = mutant_bodyparts["waggingtail_lizard"]
|
||||
mutant_bodyparts["spines"] = mutant_bodyparts["waggingspines"]
|
||||
mutant_bodyparts -= "waggingtail_lizard"
|
||||
mutant_bodyparts -= "waggingspines"
|
||||
H.update_body()
|
||||
|
||||
/*
|
||||
Lizard subspecies: ASHWALKERS
|
||||
*/
|
||||
@@ -82,6 +51,7 @@
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE)
|
||||
inherent_traits = list(TRAIT_CHUNKYFINGERS)
|
||||
mutantlungs = /obj/item/organ/lungs/ashwalker
|
||||
mutanteyes = /obj/item/organ/eyes/night_vision
|
||||
burnmod = 0.9
|
||||
brutemod = 0.9
|
||||
species_language_holder = /datum/language_holder/lizard/ash
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
nojumpsuit = TRUE
|
||||
|
||||
say_mod = "poofs" //what does a mushroom sound like
|
||||
species_traits = list(MUTCOLORS, NOEYES, NO_UNDERWEAR,NOGENITALS,NOAROUSAL)
|
||||
species_traits = list(MUTCOLORS, NOEYES, NO_UNDERWEAR,NOGENITALS,NOAROUSAL,HAS_FLESH,HAS_BONE)
|
||||
inherent_traits = list(TRAIT_NOBREATH)
|
||||
speedmod = 1.5 //faster than golems but not by much
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
burnmod = 1.25
|
||||
heatmod = 1.5
|
||||
|
||||
species_type = "plant"
|
||||
|
||||
mutanteyes = /obj/item/organ/eyes/night_vision/mushroom
|
||||
var/datum/martial_art/mushpunch/mush
|
||||
species_language_holder = /datum/language_holder/mushroom
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
say_mod = "rattles"
|
||||
sexes = 0
|
||||
meat = /obj/item/stack/sheet/mineral/plasma
|
||||
species_traits = list(NOBLOOD,NOTRANSSTING,NOGENITALS)
|
||||
species_traits = list(NOBLOOD,NOTRANSSTING,NOGENITALS,HAS_BONE)
|
||||
inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_RADIMMUNE,TRAIT_NOHUNGER,TRAIT_CALCIUM_HEALER)
|
||||
inherent_biotypes = MOB_HUMANOID|MOB_MINERAL
|
||||
mutantlungs = /obj/item/organ/lungs/plasmaman
|
||||
@@ -22,6 +22,8 @@
|
||||
liked_food = VEGETABLES
|
||||
outfit_important_for_life = /datum/outfit/plasmaman
|
||||
|
||||
species_type = "skeleton"
|
||||
|
||||
/datum/species/plasmaman/spec_life(mob/living/carbon/human/H)
|
||||
var/datum/gas_mixture/environment = H.loc.return_air()
|
||||
var/atmos_sealed = FALSE
|
||||
@@ -33,7 +35,7 @@
|
||||
if((!istype(H.w_uniform, /obj/item/clothing/under/plasmaman) || !istype(H.head, /obj/item/clothing/head/helmet/space/plasmaman)) && !atmos_sealed)
|
||||
if(environment)
|
||||
if(environment.total_moles())
|
||||
if(environment.gases[/datum/gas/oxygen] && (environment.gases[/datum/gas/oxygen]) >= 1) //Same threshhold that extinguishes fire
|
||||
if(environment.get_moles(/datum/gas/oxygen) >= 1) //Same threshhold that extinguishes fire
|
||||
H.adjust_fire_stacks(0.5)
|
||||
if(!H.on_fire && H.fire_stacks > 0)
|
||||
H.visible_message("<span class='danger'>[H]'s body reacts with the atmosphere and bursts into flames!</span>","<span class='userdanger'>Your body reacts with the atmosphere and bursts into flame!</span>")
|
||||
@@ -55,89 +57,10 @@
|
||||
..()
|
||||
|
||||
/datum/species/plasmaman/before_equip_job(datum/job/J, mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
var/current_job = J?.title
|
||||
var/datum/outfit/plasmaman/O = new /datum/outfit/plasmaman
|
||||
switch(current_job)
|
||||
if("Chaplain")
|
||||
O = new /datum/outfit/plasmaman/chaplain
|
||||
|
||||
if("Curator")
|
||||
O = new /datum/outfit/plasmaman/curator
|
||||
|
||||
if("Janitor")
|
||||
O = new /datum/outfit/plasmaman/janitor
|
||||
|
||||
if("Botanist")
|
||||
O = new /datum/outfit/plasmaman/botany
|
||||
|
||||
if("Bartender", "Lawyer")
|
||||
O = new /datum/outfit/plasmaman/bar
|
||||
|
||||
if("Cook")
|
||||
O = new /datum/outfit/plasmaman/chef
|
||||
|
||||
if("Security Officer")
|
||||
O = new /datum/outfit/plasmaman/security
|
||||
|
||||
if("Detective")
|
||||
O = new /datum/outfit/plasmaman/detective
|
||||
|
||||
if("Warden")
|
||||
O = new /datum/outfit/plasmaman/warden
|
||||
|
||||
if("Cargo Technician", "Quartermaster")
|
||||
O = new /datum/outfit/plasmaman/cargo
|
||||
|
||||
if("Shaft Miner")
|
||||
O = new /datum/outfit/plasmaman/mining
|
||||
|
||||
if("Medical Doctor")
|
||||
O = new /datum/outfit/plasmaman/medical
|
||||
|
||||
if("Chemist")
|
||||
O = new /datum/outfit/plasmaman/chemist
|
||||
|
||||
if("Geneticist")
|
||||
O = new /datum/outfit/plasmaman/genetics
|
||||
|
||||
if("Roboticist")
|
||||
O = new /datum/outfit/plasmaman/robotics
|
||||
|
||||
if("Virologist")
|
||||
O = new /datum/outfit/plasmaman/viro
|
||||
|
||||
if("Scientist")
|
||||
O = new /datum/outfit/plasmaman/science
|
||||
|
||||
if("Station Engineer")
|
||||
O = new /datum/outfit/plasmaman/engineering
|
||||
|
||||
if("Atmospheric Technician")
|
||||
O = new /datum/outfit/plasmaman/atmospherics
|
||||
|
||||
if("Captain")
|
||||
O = new /datum/outfit/plasmaman/captain
|
||||
|
||||
if("Head of Personnel")
|
||||
O = new /datum/outfit/plasmaman/hop
|
||||
|
||||
if("Head of Security")
|
||||
O = new /datum/outfit/plasmaman/hos
|
||||
|
||||
if("Chief Engineer")
|
||||
O = new /datum/outfit/plasmaman/ce
|
||||
|
||||
if("Chief Medical Officer")
|
||||
O = new /datum/outfit/plasmaman/cmo
|
||||
|
||||
if("Research Director")
|
||||
O = new /datum/outfit/plasmaman/rd
|
||||
|
||||
if("Mime")
|
||||
O = new /datum/outfit/plasmaman/mime
|
||||
|
||||
if("Clown")
|
||||
O = new /datum/outfit/plasmaman/clown
|
||||
if(J)
|
||||
if(J.plasma_outfit)
|
||||
O = new J.plasma_outfit
|
||||
|
||||
H.equipOutfit(O, visualsOnly)
|
||||
H.internal = H.get_item_for_held_index(2)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
name = "Anthromorphic Plant"
|
||||
id = "pod"
|
||||
default_color = "59CE00"
|
||||
species_traits = list(MUTCOLORS,EYECOLOR)
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,CAN_SCAR,HAS_FLESH,HAS_BONE)
|
||||
attack_verb = "slash"
|
||||
attack_sound = 'sound/weapons/slice.ogg'
|
||||
miss_sound = 'sound/weapons/slashmiss.ogg'
|
||||
@@ -19,6 +19,10 @@
|
||||
var/light_burnheal = -1
|
||||
var/light_bruteheal = -1
|
||||
|
||||
species_type = "plant"
|
||||
|
||||
allowed_limb_ids = list("pod","mush")
|
||||
|
||||
/datum/species/pod/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
. = ..()
|
||||
C.faction |= "plants"
|
||||
@@ -64,36 +68,12 @@
|
||||
name = "Anthromorphic Plant"
|
||||
id = "podweak"
|
||||
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS)
|
||||
mutant_bodyparts = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs")
|
||||
mutant_bodyparts = list("mcolor" = "FFFFFF","mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs")
|
||||
limbs_id = "pod"
|
||||
light_nutrition_gain_factor = 3
|
||||
light_bruteheal = -0.2
|
||||
light_burnheal = -0.2
|
||||
light_toxheal = -0.7
|
||||
|
||||
/datum/species/pod/pseudo_weak/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
|
||||
/datum/species/pod/pseudo_weak/spec_stun(mob/living/carbon/human/H,amount)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
. = ..()
|
||||
|
||||
/datum/species/pod/pseudo_weak/can_wag_tail(mob/living/carbon/human/H)
|
||||
return mutant_bodyparts["mam_tail"] || mutant_bodyparts["mam_waggingtail"]
|
||||
|
||||
/datum/species/pod/pseudo_weak/is_wagging_tail(mob/living/carbon/human/H)
|
||||
return mutant_bodyparts["mam_waggingtail"]
|
||||
|
||||
/datum/species/pod/pseudo_weak/start_wagging_tail(mob/living/carbon/human/H)
|
||||
if(mutant_bodyparts["mam_tail"])
|
||||
mutant_bodyparts["mam_waggingtail"] = mutant_bodyparts["mam_tail"]
|
||||
mutant_bodyparts -= "mam_tail"
|
||||
H.update_body()
|
||||
|
||||
/datum/species/pod/pseudo_weak/stop_wagging_tail(mob/living/carbon/human/H)
|
||||
if(mutant_bodyparts["mam_waggingtail"])
|
||||
mutant_bodyparts["mam_tail"] = mutant_bodyparts["mam_waggingtail"]
|
||||
mutant_bodyparts -= "mam_waggingtail"
|
||||
H.update_body()
|
||||
tail_type = "mam_tail"
|
||||
wagging_type = "mam_waggingtail"
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
blacklisted = 1
|
||||
ignored_by = list(/mob/living/simple_animal/hostile/faithless)
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/shadow
|
||||
species_traits = list(NOBLOOD,NOEYES)
|
||||
species_traits = list(NOBLOOD,NOEYES,HAS_FLESH,HAS_BONE)
|
||||
inherent_traits = list(TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_NOBREATH)
|
||||
|
||||
dangerous_existence = 1
|
||||
mutanteyes = /obj/item/organ/eyes/night_vision
|
||||
|
||||
species_type = "shadow"
|
||||
|
||||
/datum/species/shadow/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
. = ..()
|
||||
C.AddElement(/datum/element/photosynthesis, 1, 1, 0, 0, 0, 0, SHADOW_SPECIES_LIGHT_THRESHOLD, SHADOW_SPECIES_LIGHT_THRESHOLD)
|
||||
@@ -80,13 +82,11 @@
|
||||
M.AddSpell(SW)
|
||||
shadowwalk = SW
|
||||
|
||||
|
||||
/obj/item/organ/brain/nightmare/Remove(special = FALSE)
|
||||
if(shadowwalk && owner)
|
||||
owner.RemoveSpell(shadowwalk)
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/organ/heart/nightmare
|
||||
name = "heart of darkness"
|
||||
desc = "An alien organ that twists and writhes when exposed to light."
|
||||
@@ -164,7 +164,7 @@
|
||||
righthand_file = 'icons/mob/inhands/antag/changeling_righthand.dmi'
|
||||
item_flags = ABSTRACT | DROPDEL
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
sharpness = IS_SHARP
|
||||
sharpness = SHARP_EDGED
|
||||
total_mass = TOTAL_MASS_HAND_REPLACEMENT
|
||||
|
||||
/obj/item/light_eater/Initialize()
|
||||
@@ -183,6 +183,8 @@
|
||||
T.ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
|
||||
else if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
if(isethereal(AM))
|
||||
AM.emp_act(EMP_LIGHT)
|
||||
if(iscyborg(AM))
|
||||
var/mob/living/silicon/robot/borg = AM
|
||||
if(borg.lamp_intensity)
|
||||
|
||||
@@ -1,18 +1,28 @@
|
||||
/datum/species/skeleton
|
||||
// 2spooky
|
||||
name = "Spooky Scary Skeleton"
|
||||
name = "Skeleton"
|
||||
id = "skeleton"
|
||||
say_mod = "rattles"
|
||||
blacklisted = 0
|
||||
sexes = 0
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/skeleton
|
||||
species_traits = list(NOBLOOD,NOGENITALS,NOAROUSAL)
|
||||
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER)
|
||||
species_traits = list(NOBLOOD,NOGENITALS,NOAROUSAL,HAS_BONE,NOTRANSSTING)
|
||||
inherent_traits = list(TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_CALCIUM_HEALER)
|
||||
inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID
|
||||
mutanttongue = /obj/item/organ/tongue/bone
|
||||
damage_overlay_type = ""//let's not show bloody wounds or burns over bones.
|
||||
disliked_food = NONE
|
||||
liked_food = GROSS | MEAT | RAW | DAIRY
|
||||
brutemod = 1.25
|
||||
burnmod = 1.25
|
||||
|
||||
species_type = "skeleton" //they have their own category that's disassociated from undead, paired with plasmapeople
|
||||
|
||||
/datum/species/skeleton/New()
|
||||
if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) //skeletons are stronger during the spooky season!
|
||||
inherent_traits |= list(TRAIT_RESISTHEAT, TRAIT_NOBREATH, TRAIT_PIERCEIMMUNE, TRAIT_FAKEDEATH, TRAIT_RESISTCOLD, TRAIT_RADIMMUNE)
|
||||
brutemod = 1
|
||||
burnmod = 1
|
||||
..()
|
||||
|
||||
/datum/species/skeleton/check_roundstart_eligible()
|
||||
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
|
||||
@@ -27,4 +37,4 @@
|
||||
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT, TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER)
|
||||
|
||||
/datum/species/skeleton/space/check_roundstart_eligible()
|
||||
return FALSE
|
||||
return FALSE
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/datum/species/synthliz
|
||||
name = "Synthetic Lizardperson"
|
||||
id = "synthliz"
|
||||
icon_limbs = DEFAULT_BODYPART_ICON_CITADEL
|
||||
say_mod = "beeps"
|
||||
default_color = "00FF00"
|
||||
species_traits = list(MUTCOLORS,NOTRANSSTING,EYECOLOR,LIPS,HAIR,ROBOTIC_LIMBS)
|
||||
species_traits = list(MUTCOLORS,NOTRANSSTING,EYECOLOR,LIPS,HAIR,ROBOTIC_LIMBS,HAS_FLESH,HAS_BONE)
|
||||
inherent_traits = list(TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NO_PROCESS_FOOD)
|
||||
inherent_biotypes = MOB_ROBOTIC|MOB_HUMANOID
|
||||
mutant_bodyparts = list("ipc_antenna" = "Synthetic Lizard - Antennae","mam_tail" = "Synthetic Lizard", "mam_snouts" = "Synthetic Lizard - Snout", "legs" = "Digitigrade", "mam_body_markings" = "Synthetic Lizard - Plates", "taur" = "None")
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ipc
|
||||
gib_types = list(/obj/effect/gibspawner/ipc, /obj/effect/gibspawner/ipc/bodypartless)
|
||||
@@ -23,35 +23,8 @@
|
||||
mutant_organs = list(/obj/item/organ/cyberimp/arm/power_cord)
|
||||
|
||||
exotic_bloodtype = "S"
|
||||
exotic_blood_color = BLOOD_COLOR_OIL
|
||||
|
||||
|
||||
/datum/species/synthliz/qualifies_for_rank(rank, list/features)
|
||||
return TRUE
|
||||
|
||||
//I wag in death
|
||||
/datum/species/synthliz/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
|
||||
/datum/species/synthliz/spec_stun(mob/living/carbon/human/H,amount)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
. = ..()
|
||||
|
||||
/datum/species/synthliz/can_wag_tail(mob/living/carbon/human/H)
|
||||
return mutant_bodyparts["mam_tail"] || mutant_bodyparts["mam_waggingtail"]
|
||||
|
||||
/datum/species/synthliz/is_wagging_tail(mob/living/carbon/human/H)
|
||||
return mutant_bodyparts["mam_waggingtail"]
|
||||
|
||||
/datum/species/synthliz/start_wagging_tail(mob/living/carbon/human/H)
|
||||
if(mutant_bodyparts["mam_tail"])
|
||||
mutant_bodyparts["mam_waggingtail"] = mutant_bodyparts["mam_tail"]
|
||||
mutant_bodyparts -= "mam_tail"
|
||||
H.update_body()
|
||||
|
||||
/datum/species/synthliz/stop_wagging_tail(mob/living/carbon/human/H)
|
||||
if(mutant_bodyparts["mam_waggingtail"])
|
||||
mutant_bodyparts["mam_tail"] = mutant_bodyparts["mam_waggingtail"]
|
||||
mutant_bodyparts -= "mam_waggingtail"
|
||||
H.update_body()
|
||||
tail_type = "mam_tail"
|
||||
wagging_type = "mam_waggingtail"
|
||||
species_type = "robotic"
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
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
|
||||
species_language_holder = /datum/language_holder/synthetic
|
||||
species_type = "robotic"
|
||||
|
||||
/datum/species/synth/military
|
||||
name = "Military Synth"
|
||||
@@ -43,7 +44,6 @@
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/species/synth/proc/assume_disguise(datum/species/S, mob/living/carbon/human/H)
|
||||
if(S && !istype(S, type))
|
||||
name = S.name
|
||||
@@ -61,7 +61,7 @@
|
||||
mutant_organs = S.mutant_organs.Copy()
|
||||
nojumpsuit = S.nojumpsuit
|
||||
no_equip = S.no_equip.Copy()
|
||||
limbs_id = S.limbs_id
|
||||
limbs_id = S.mutant_bodyparts["limbs_id"]
|
||||
use_skintones = S.use_skintones
|
||||
fixed_mut_color = S.fixed_mut_color
|
||||
hair_color = S.hair_color
|
||||
@@ -100,14 +100,12 @@
|
||||
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)
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
name = "Vampire"
|
||||
id = "vampire"
|
||||
default_color = "FFFFFF"
|
||||
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,DRINKSBLOOD)
|
||||
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,DRINKSBLOOD,HAS_FLESH,HAS_BONE)
|
||||
inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH)
|
||||
inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID
|
||||
mutant_bodyparts = list("mcolor" = "FFF", "tail_human" = "None", "ears" = "None", "deco_wings" = "None")
|
||||
mutant_bodyparts = list("mcolor" = "FFFFFF", "tail_human" = "None", "ears" = "None", "deco_wings" = "None")
|
||||
exotic_bloodtype = "U"
|
||||
use_skintones = USE_SKINTONES_GRAYSCALE_CUSTOM
|
||||
mutant_heart = /obj/item/organ/heart/vampire
|
||||
@@ -14,6 +14,7 @@
|
||||
limbs_id = "human"
|
||||
skinned_type = /obj/item/stack/sheet/animalhide/human
|
||||
var/info_text = "You are a <span class='danger'>Vampire</span>. You will slowly but constantly lose blood if outside of a coffin. If inside a coffin, you will slowly heal. You may gain more blood by grabbing a live victim and using your drain ability."
|
||||
species_type = "undead"
|
||||
|
||||
/datum/species/vampire/check_roundstart_eligible()
|
||||
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/datum/species/xeno
|
||||
// A cloning mistake, crossing human and xenomorph DNA
|
||||
name = "Xenomorph Hybrid"
|
||||
id = "xeno"
|
||||
say_mod = "hisses"
|
||||
default_color = "00FF00"
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,CAN_SCAR)
|
||||
mutant_bodyparts = list("xenotail"="Xenomorph Tail","xenohead"="Standard","xenodorsal"="Standard", "mam_body_markings" = "Xeno","mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0","taur" = "None", "legs" = "Digitigrade")
|
||||
attack_verb = "slash"
|
||||
attack_sound = 'sound/weapons/slash.ogg'
|
||||
miss_sound = 'sound/weapons/slashmiss.ogg'
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/xeno
|
||||
gib_types = list(/obj/effect/gibspawner/xeno/xenoperson, /obj/effect/gibspawner/xeno/xenoperson/bodypartless)
|
||||
skinned_type = /obj/item/stack/sheet/animalhide/xeno
|
||||
exotic_bloodtype = "X*"
|
||||
damage_overlay_type = "xeno"
|
||||
liked_food = MEAT
|
||||
species_type = "alien"
|
||||
@@ -8,13 +8,14 @@
|
||||
sexes = 0
|
||||
blacklisted = 1
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/zombie
|
||||
species_traits = list(NOBLOOD,NOZOMBIE,NOTRANSSTING)
|
||||
species_traits = list(NOBLOOD,NOZOMBIE,NOTRANSSTING,HAS_FLESH,HAS_BONE)
|
||||
inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NOBREATH,TRAIT_NODEATH,TRAIT_FAKEDEATH)
|
||||
inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID
|
||||
mutanttongue = /obj/item/organ/tongue/zombie
|
||||
var/static/list/spooks = list('sound/hallucinations/growl1.ogg','sound/hallucinations/growl2.ogg','sound/hallucinations/growl3.ogg','sound/hallucinations/veryfar_noise.ogg','sound/hallucinations/wail.ogg')
|
||||
disliked_food = NONE
|
||||
liked_food = GROSS | MEAT | RAW
|
||||
species_type = "undead"
|
||||
|
||||
/datum/species/zombie/notspaceproof
|
||||
id = "notspaceproofzombie"
|
||||
@@ -31,9 +32,10 @@
|
||||
name = "Infectious Zombie"
|
||||
id = "memezombies"
|
||||
limbs_id = "zombie"
|
||||
inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NOBREATH,TRAIT_NODEATH,TRAIT_NOSOFTCRIT, TRAIT_FAKEDEATH)
|
||||
mutanthands = /obj/item/zombie_hand
|
||||
armor = 20 // 120 damage to KO a zombie, which kills it
|
||||
speedmod = 1.6
|
||||
speedmod = 1.6 // they're very slow
|
||||
mutanteyes = /obj/item/organ/eyes/night_vision/zombie
|
||||
var/heal_rate = 1
|
||||
var/regen_cooldown = 0
|
||||
@@ -41,11 +43,10 @@
|
||||
/datum/species/zombie/infectious/check_roundstart_eligible()
|
||||
return FALSE
|
||||
|
||||
|
||||
/datum/species/zombie/infectious/spec_stun(mob/living/carbon/human/H,amount)
|
||||
. = min(20, amount)
|
||||
|
||||
/datum/species/zombie/infectious/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, forced = FALSE)
|
||||
/datum/species/zombie/infectious/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, forced = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = SHARP_NONE)
|
||||
. = ..()
|
||||
if(.)
|
||||
regen_cooldown = world.time + REGENERATION_DELAY
|
||||
@@ -62,6 +63,10 @@
|
||||
heal_amt *= 2
|
||||
C.heal_overall_damage(heal_amt,heal_amt)
|
||||
C.adjustToxLoss(-heal_amt)
|
||||
for(var/i in C.all_wounds)
|
||||
var/datum/wound/iter_wound = i
|
||||
if(prob(4-iter_wound.severity))
|
||||
iter_wound.remove_wound()
|
||||
if(!C.InCritical() && prob(4))
|
||||
playsound(C, pick(spooks), 50, TRUE, 10)
|
||||
|
||||
@@ -85,6 +90,11 @@
|
||||
infection = new()
|
||||
infection.Insert(C)
|
||||
|
||||
//make their bodyparts stamina-immune, its a corpse.
|
||||
var/incoming_stam_mult = 0
|
||||
for(var/obj/item/bodypart/part in C.bodyparts)
|
||||
part.incoming_stam_mult = incoming_stam_mult
|
||||
//todo: add negative wound resistance to all parts when wounds is merged (zombies are physically weak in terms of limbs)
|
||||
|
||||
// Your skin falls off
|
||||
/datum/species/krokodil_addict
|
||||
|
||||
@@ -660,7 +660,7 @@ use_mob_overlay_icon: if FALSE, it will always use the default_icon_file even if
|
||||
|
||||
//produces a key based on the human's limbs
|
||||
/mob/living/carbon/human/generate_icon_render_key()
|
||||
. = "[dna.species.limbs_id]"
|
||||
. = "[dna.species.mutant_bodyparts["limbs_id"]]"
|
||||
|
||||
if(dna.check_mutation(HULK))
|
||||
. += "-coloured-hulk"
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
/mob/living/carbon/Life()
|
||||
set invisibility = 0
|
||||
|
||||
if(notransform)
|
||||
return
|
||||
|
||||
if(damageoverlaytemp)
|
||||
damageoverlaytemp = 0
|
||||
update_damage_hud()
|
||||
|
||||
/mob/living/carbon/BiologicalLife(seconds, times_fired)
|
||||
//Updates the number of stored chemicals for powers
|
||||
handle_changeling()
|
||||
//Handles the unique mentabolism of bloodsuckers, look at /datum/antagonist/bloodsucker/proc/LifeTick()
|
||||
handle_bloodsucker()
|
||||
//Reagent processing needs to come before breathing, to prevent edge cases.
|
||||
handle_organs()
|
||||
|
||||
. = ..()
|
||||
|
||||
if (QDELETED(src))
|
||||
. = ..() // if . is false, we are dead.
|
||||
if(stat == DEAD)
|
||||
stop_sound_channel(CHANNEL_HEARTBEAT)
|
||||
handle_death()
|
||||
rot()
|
||||
. = FALSE
|
||||
if(!.)
|
||||
return
|
||||
|
||||
if(.) //not dead
|
||||
handle_blood()
|
||||
|
||||
handle_blood()
|
||||
// handle_blood *could* kill us.
|
||||
// we should probably have a better system for if we need to check for death or something in the future hmw
|
||||
if(stat != DEAD)
|
||||
var/bprv = handle_bodyparts()
|
||||
if(bprv & BODYPART_LIFE_UPDATE_HEALTH)
|
||||
updatehealth()
|
||||
update_stamina()
|
||||
doSprintBufferRegen()
|
||||
|
||||
if(stat != DEAD)
|
||||
handle_brain_damage()
|
||||
@@ -31,16 +29,13 @@
|
||||
if(stat != DEAD)
|
||||
handle_liver()
|
||||
|
||||
if(stat == DEAD)
|
||||
stop_sound_channel(CHANNEL_HEARTBEAT)
|
||||
handle_death()
|
||||
rot()
|
||||
|
||||
//Updates the number of stored chemicals for powers
|
||||
handle_changeling()
|
||||
|
||||
if(stat != DEAD)
|
||||
return 1
|
||||
/mob/living/carbon/PhysicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
if(damageoverlaytemp)
|
||||
damageoverlaytemp = 0
|
||||
update_damage_hud()
|
||||
|
||||
//Procs called while dead
|
||||
/mob/living/carbon/proc/handle_death()
|
||||
@@ -169,12 +164,11 @@
|
||||
var/SA_para_min = 1
|
||||
var/SA_sleep_min = 5
|
||||
var/oxygen_used = 0
|
||||
var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME
|
||||
var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.return_temperature())/BREATH_VOLUME
|
||||
|
||||
var/list/breath_gases = breath.gases
|
||||
var/O2_partialpressure = (breath_gases[/datum/gas/oxygen]/breath.total_moles())*breath_pressure
|
||||
var/Toxins_partialpressure = (breath_gases[/datum/gas/plasma]/breath.total_moles())*breath_pressure
|
||||
var/CO2_partialpressure = (breath_gases[/datum/gas/carbon_dioxide]/breath.total_moles())*breath_pressure
|
||||
var/O2_partialpressure = (breath.get_moles(/datum/gas/oxygen)/breath.total_moles())*breath_pressure
|
||||
var/Toxins_partialpressure = (breath.get_moles(/datum/gas/plasma)/breath.total_moles())*breath_pressure
|
||||
var/CO2_partialpressure = (breath.get_moles(/datum/gas/carbon_dioxide)/breath.total_moles())*breath_pressure
|
||||
|
||||
|
||||
//OXYGEN
|
||||
@@ -198,7 +192,7 @@
|
||||
var/ratio = 1 - O2_partialpressure/safe_oxy_min
|
||||
adjustOxyLoss(min(5*ratio, 3))
|
||||
failed_last_breath = 1
|
||||
oxygen_used = breath_gases[/datum/gas/oxygen]*ratio
|
||||
oxygen_used = breath.get_moles(/datum/gas/oxygen)*ratio
|
||||
else
|
||||
adjustOxyLoss(3)
|
||||
failed_last_breath = 1
|
||||
@@ -210,12 +204,12 @@
|
||||
o2overloadtime = 0 //reset our counter for this too
|
||||
if(health >= crit_threshold)
|
||||
adjustOxyLoss(-5)
|
||||
oxygen_used = breath_gases[/datum/gas/oxygen]
|
||||
oxygen_used = breath.get_moles(/datum/gas/oxygen)
|
||||
clear_alert("not_enough_oxy")
|
||||
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "suffocation")
|
||||
|
||||
breath_gases[/datum/gas/oxygen] -= oxygen_used
|
||||
breath_gases[/datum/gas/carbon_dioxide] += oxygen_used
|
||||
breath.adjust_moles(/datum/gas/oxygen, -oxygen_used)
|
||||
breath.adjust_moles(/datum/gas/carbon_dioxide, oxygen_used)
|
||||
|
||||
//CARBON DIOXIDE
|
||||
if(CO2_partialpressure > safe_co2_max)
|
||||
@@ -234,15 +228,15 @@
|
||||
|
||||
//TOXINS/PLASMA
|
||||
if(Toxins_partialpressure > safe_tox_max)
|
||||
var/ratio = (breath_gases[/datum/gas/plasma]/safe_tox_max) * 10
|
||||
var/ratio = (breath.get_moles(/datum/gas/plasma)/safe_tox_max) * 10
|
||||
adjustToxLoss(clamp(ratio, MIN_TOXIC_GAS_DAMAGE, MAX_TOXIC_GAS_DAMAGE))
|
||||
throw_alert("too_much_tox", /obj/screen/alert/too_much_tox)
|
||||
else
|
||||
clear_alert("too_much_tox")
|
||||
|
||||
//NITROUS OXIDE
|
||||
if(breath_gases[/datum/gas/nitrous_oxide])
|
||||
var/SA_partialpressure = (breath_gases[/datum/gas/nitrous_oxide]/breath.total_moles())*breath_pressure
|
||||
if(breath.get_moles(/datum/gas/nitrous_oxide))
|
||||
var/SA_partialpressure = (breath.get_moles(/datum/gas/nitrous_oxide)/breath.total_moles())*breath_pressure
|
||||
if(SA_partialpressure > SA_para_min)
|
||||
Unconscious(60)
|
||||
if(SA_partialpressure > SA_sleep_min)
|
||||
@@ -255,26 +249,26 @@
|
||||
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "chemical_euphoria")
|
||||
|
||||
//BZ (Facepunch port of their Agent B)
|
||||
if(breath_gases[/datum/gas/bz])
|
||||
var/bz_partialpressure = (breath_gases[/datum/gas/bz]/breath.total_moles())*breath_pressure
|
||||
if(breath.get_moles(/datum/gas/bz))
|
||||
var/bz_partialpressure = (breath.get_moles(/datum/gas/bz)/breath.total_moles())*breath_pressure
|
||||
if(bz_partialpressure > 1)
|
||||
hallucination += 10
|
||||
else if(bz_partialpressure > 0.01)
|
||||
hallucination += 5
|
||||
|
||||
//TRITIUM
|
||||
if(breath_gases[/datum/gas/tritium])
|
||||
var/tritium_partialpressure = (breath_gases[/datum/gas/tritium]/breath.total_moles())*breath_pressure
|
||||
if(breath.get_moles(/datum/gas/tritium))
|
||||
var/tritium_partialpressure = (breath.get_moles(/datum/gas/tritium)/breath.total_moles())*breath_pressure
|
||||
radiation += tritium_partialpressure/10
|
||||
|
||||
//NITRYL
|
||||
if(breath_gases[/datum/gas/nitryl])
|
||||
var/nitryl_partialpressure = (breath_gases[/datum/gas/nitryl]/breath.total_moles())*breath_pressure
|
||||
if(breath.get_moles(/datum/gas/nitryl))
|
||||
var/nitryl_partialpressure = (breath.get_moles(/datum/gas/nitryl)/breath.total_moles())*breath_pressure
|
||||
adjustFireLoss(nitryl_partialpressure/4)
|
||||
|
||||
//MIASMA
|
||||
if(breath_gases[/datum/gas/miasma])
|
||||
var/miasma_partialpressure = (breath_gases[/datum/gas/miasma]/breath.total_moles())*breath_pressure
|
||||
if(breath.get_moles(/datum/gas/miasma))
|
||||
var/miasma_partialpressure = (breath.get_moles(/datum/gas/miasma)/breath.total_moles())*breath_pressure
|
||||
if(miasma_partialpressure > MINIMUM_MOLES_DELTA_TO_MOVE)
|
||||
|
||||
if(prob(0.05 * miasma_partialpressure))
|
||||
@@ -314,11 +308,6 @@
|
||||
else
|
||||
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "smell")
|
||||
|
||||
|
||||
|
||||
|
||||
GAS_GARBAGE_COLLECT(breath.gases)
|
||||
|
||||
//BREATH TEMPERATURE
|
||||
handle_breath_temperature(breath)
|
||||
|
||||
@@ -377,9 +366,9 @@
|
||||
|
||||
var/datum/gas_mixture/stank = new
|
||||
|
||||
stank.gases[/datum/gas/miasma] = 0.1
|
||||
stank.set_moles(/datum/gas/miasma,0.1)
|
||||
|
||||
stank.temperature = BODYTEMP_NORMAL
|
||||
stank.set_temperature(BODYTEMP_NORMAL)
|
||||
|
||||
miasma_turf.assume_air(stank)
|
||||
|
||||
@@ -417,6 +406,12 @@
|
||||
if(stat != DEAD || D.process_dead)
|
||||
D.stage_act()
|
||||
|
||||
/mob/living/carbon/handle_wounds()
|
||||
for(var/thing in all_wounds)
|
||||
var/datum/wound/W = thing
|
||||
if(W.processes) // meh
|
||||
W.handle_process()
|
||||
|
||||
//todo generalize this and move hud out
|
||||
/mob/living/carbon/proc/handle_changeling()
|
||||
if(mind && hud_used && hud_used.lingchemdisplay)
|
||||
@@ -429,6 +424,12 @@
|
||||
hud_used.lingchemdisplay.invisibility = INVISIBILITY_ABSTRACT
|
||||
|
||||
|
||||
/mob/living/carbon/proc/handle_bloodsucker()
|
||||
if(mind && AmBloodsucker(src))
|
||||
var/datum/antagonist/bloodsucker/B = mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
|
||||
B.LifeTick()
|
||||
|
||||
|
||||
/mob/living/carbon/handle_mutations_and_radiation()
|
||||
if(dna && dna.temporary_mutations.len)
|
||||
for(var/mut in dna.temporary_mutations)
|
||||
@@ -524,7 +525,7 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put
|
||||
/mob/living/carbon/handle_status_effects()
|
||||
..()
|
||||
if(getStaminaLoss() && !SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE)) //CIT CHANGE - prevents stamina regen while combat mode is active
|
||||
adjustStaminaLoss(!CHECK_MOBILITY(src, MOBILITY_STAND) ? ((combat_flags & COMBAT_FLAG_HARD_STAMCRIT) ? -7.5 : -6) : -3)//CIT CHANGE - decreases adjuststaminaloss to stop stamina damage from being such a joke
|
||||
adjustStaminaLoss(!CHECK_MOBILITY(src, MOBILITY_STAND) ? ((combat_flags & COMBAT_FLAG_HARD_STAMCRIT) ? STAM_RECOVERY_STAM_CRIT : STAM_RECOVERY_RESTING) : STAM_RECOVERY_NORMAL)
|
||||
|
||||
if(!(combat_flags & COMBAT_FLAG_HARD_STAMCRIT) && incomingstammult != 1)
|
||||
incomingstammult = max(0.01, incomingstammult)
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
/mob/living/carbon/monkey/proc/pickup_and_wear(obj/item/I)
|
||||
if(QDELETED(I) || I.loc != src)
|
||||
return
|
||||
equip_to_appropriate_slot(I)
|
||||
equip_to_appropriate_slot(I, TRUE)
|
||||
|
||||
/mob/living/carbon/monkey/resist_restraints()
|
||||
var/obj/item/I = null
|
||||
@@ -90,8 +90,7 @@
|
||||
else if(legcuffed)
|
||||
I = legcuffed
|
||||
if(I)
|
||||
changeNext_move(CLICK_CD_BREAKOUT)
|
||||
last_special = world.time + CLICK_CD_BREAKOUT
|
||||
MarkResistTime()
|
||||
cuff_resist(I)
|
||||
|
||||
/mob/living/carbon/monkey/proc/should_target(var/mob/living/L)
|
||||
@@ -354,7 +353,7 @@
|
||||
battle_screech()
|
||||
a_intent = INTENT_HARM
|
||||
|
||||
/mob/living/carbon/monkey/attack_hand(mob/living/L)
|
||||
/mob/living/carbon/monkey/on_attack_hand(mob/living/L)
|
||||
if(L.a_intent == INTENT_HARM && prob(MONKEY_RETALIATE_HARM_PROB))
|
||||
retaliate(L)
|
||||
else if(L.a_intent == INTENT_DISARM && prob(MONKEY_RETALIATE_DISARM_PROB))
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
/mob/living/carbon/monkey/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
|
||||
/mob/living/carbon/monkey/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, clothing_check = FALSE, list/return_warning)
|
||||
if(clothing_check && (slot in check_obscured_slots()))
|
||||
if(return_warning)
|
||||
return_warning[1] = "<span class='warning'>You are unable to equip that with your current garments in the way!</span>"
|
||||
return FALSE
|
||||
|
||||
switch(slot)
|
||||
if(SLOT_HANDS)
|
||||
if(get_empty_held_indexes())
|
||||
|
||||
@@ -3,30 +3,26 @@
|
||||
/mob/living/carbon/monkey
|
||||
|
||||
|
||||
/mob/living/carbon/monkey/Life()
|
||||
set invisibility = 0
|
||||
|
||||
if (notransform)
|
||||
/mob/living/carbon/monkey/BiologicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
|
||||
if(..())
|
||||
|
||||
if(!client)
|
||||
if(stat == CONSCIOUS)
|
||||
if(on_fire || buckled || restrained() || (!CHECK_MOBILITY(src, MOBILITY_STAND) && CHECK_MOBILITY(src, MOBILITY_MOVE))) //CIT CHANGE - makes it so monkeys attempt to resist if they're resting)
|
||||
if(!resisting && prob(MONKEY_RESIST_PROB))
|
||||
resisting = TRUE
|
||||
walk_to(src,0)
|
||||
resist()
|
||||
else if(resisting)
|
||||
resisting = FALSE
|
||||
else if((mode == MONKEY_IDLE && !pickupTarget && !prob(MONKEY_SHENANIGAN_PROB)) || !handle_combat())
|
||||
if(prob(25) && CHECK_MOBILITY(src, MOBILITY_MOVE) && isturf(loc) && !pulledby)
|
||||
step(src, pick(GLOB.cardinals))
|
||||
else if(prob(1))
|
||||
emote(pick("scratch","jump","roll","tail"))
|
||||
else
|
||||
if(client)
|
||||
return
|
||||
if(stat == CONSCIOUS)
|
||||
if(on_fire || buckled || restrained() || (!CHECK_MOBILITY(src, MOBILITY_STAND) && CHECK_MOBILITY(src, MOBILITY_MOVE))) //CIT CHANGE - makes it so monkeys attempt to resist if they're resting)
|
||||
if(!resisting && prob(MONKEY_RESIST_PROB))
|
||||
resisting = TRUE
|
||||
walk_to(src,0)
|
||||
resist()
|
||||
else if(resisting)
|
||||
resisting = FALSE
|
||||
else if((mode == MONKEY_IDLE && !pickupTarget && !prob(MONKEY_SHENANIGAN_PROB)) || !handle_combat())
|
||||
if(prob(25) && CHECK_MOBILITY(src, MOBILITY_MOVE) && isturf(loc) && !pulledby)
|
||||
step(src, pick(GLOB.cardinals))
|
||||
else if(prob(1))
|
||||
emote(pick("scratch","jump","roll","tail"))
|
||||
else
|
||||
walk_to(src,0)
|
||||
|
||||
/mob/living/carbon/monkey/handle_mutations_and_radiation()
|
||||
if(radiation)
|
||||
@@ -50,8 +46,8 @@
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/monkey/handle_breath_temperature(datum/gas_mixture/breath)
|
||||
if(abs(BODYTEMP_NORMAL - breath.temperature) > 50)
|
||||
switch(breath.temperature)
|
||||
if(abs(BODYTEMP_NORMAL - breath.return_temperature()) > 50)
|
||||
switch(breath.return_temperature())
|
||||
if(-INFINITY to 120)
|
||||
adjustFireLoss(3)
|
||||
if(120 to 200)
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
adjustBruteLoss(15)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/monkey/attack_hand(mob/living/carbon/human/M)
|
||||
/mob/living/carbon/monkey/on_attack_hand(mob/living/carbon/human/M)
|
||||
. = ..()
|
||||
if(.) //To allow surgery to return properly.
|
||||
return
|
||||
|
||||
@@ -26,16 +26,19 @@
|
||||
//These have to be after the parent new to ensure that the monkey
|
||||
//bodyparts are actually created before we try to equip things to
|
||||
//those slots
|
||||
if(ancestor_chain > 1)
|
||||
generate_fake_scars(rand(ancestor_chain, ancestor_chain * 4))
|
||||
if(relic_hat)
|
||||
equip_to_slot_or_del(new relic_hat, SLOT_HEAD)
|
||||
if(relic_mask)
|
||||
equip_to_slot_or_del(new relic_mask, SLOT_WEAR_MASK)
|
||||
|
||||
/mob/living/carbon/monkey/punpun/Life()
|
||||
/mob/living/carbon/monkey/punpun/BiologicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
if(!stat && SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
|
||||
Write_Memory(FALSE, FALSE)
|
||||
memory_saved = TRUE
|
||||
..()
|
||||
|
||||
/mob/living/carbon/monkey/punpun/death(gibbed)
|
||||
if(!memory_saved)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
overlays_standing[cache_index] = null
|
||||
|
||||
/mob/living/carbon/regenerate_icons()
|
||||
if(notransform)
|
||||
if(mob_transforming)
|
||||
return 1
|
||||
update_inv_hands()
|
||||
update_inv_handcuffed()
|
||||
@@ -68,7 +68,7 @@
|
||||
var/dam_colors = "#E62525"
|
||||
if(ishuman(src))
|
||||
var/mob/living/carbon/human/H = src
|
||||
dam_colors = bloodtype_to_color(H.dna.blood_type)
|
||||
dam_colors = H.dna.species.exotic_blood_color
|
||||
|
||||
var/mutable_appearance/damage_overlay = mutable_appearance('icons/mob/dam_mob.dmi', "blank", -DAMAGE_LAYER, color = dam_colors)
|
||||
overlays_standing[DAMAGE_LAYER] = damage_overlay
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
/mob/living/GetActionCooldownMod()
|
||||
. = ..()
|
||||
for(var/datum/status_effect/S in status_effects)
|
||||
. *= S.action_cooldown_mod()
|
||||
@@ -1,14 +1,20 @@
|
||||
|
||||
/*
|
||||
apply_damage(a,b,c)
|
||||
args
|
||||
a:damage - How much damage to take
|
||||
b:damage_type - What type of damage to take, brute, burn
|
||||
c:def_zone - Where to take the damage if its brute or burn
|
||||
Returns
|
||||
standard 0 if fail
|
||||
*/
|
||||
/mob/living/proc/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE)
|
||||
/**
|
||||
* Applies damage to this mob
|
||||
*
|
||||
* Sends [COMSIG_MOB_APPLY_DAMGE]
|
||||
*
|
||||
* Arguuments:
|
||||
* * damage - amount of damage
|
||||
* * damagetype - one of [BRUTE], [BURN], [TOX], [OXY], [CLONE], [STAMINA]
|
||||
* * def_zone - zone that is being hit if any
|
||||
* * blocked - armor value applied
|
||||
* * forced - bypass hit percentage
|
||||
* * spread_damage - used in overrides
|
||||
*
|
||||
* Returns TRUE if damage applied
|
||||
*/
|
||||
/mob/living/proc/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = SHARP_NONE)
|
||||
var/hit_percent = (100-blocked)/100
|
||||
if(!damage || (hit_percent <= 0))
|
||||
return 0
|
||||
@@ -239,7 +245,7 @@
|
||||
update_stamina()
|
||||
|
||||
// damage ONE external organ, organ gets randomly selected from damaged ones.
|
||||
/mob/living/proc/take_bodypart_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE)
|
||||
/mob/living/proc/take_bodypart_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE, required_status, check_armor = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = SHARP_NONE)
|
||||
adjustBruteLoss(brute, FALSE) //zero as argument for no instant health update
|
||||
adjustFireLoss(burn, FALSE)
|
||||
adjustStaminaLoss(stamina, FALSE)
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
spill_organs(no_brain, no_organs, no_bodyparts)
|
||||
|
||||
release_vore_contents(silent = TRUE) // return of the bomb safe internals.
|
||||
|
||||
if(!no_bodyparts)
|
||||
spread_bodyparts(no_brain, no_organs)
|
||||
|
||||
@@ -46,7 +44,6 @@
|
||||
buckled.unbuckle_mob(src, force = TRUE)
|
||||
|
||||
dust_animation()
|
||||
release_vore_contents(silent = TRUE) //technically grief protection, I guess? if they're SM'd it doesn't matter seconds after anyway.
|
||||
spawn_dust(just_ash)
|
||||
QDEL_IN(src,5) // since this is sometimes called in the middle of movement, allow half a second for movement to finish, ghosting to happen and animation to play. Looks much nicer and doesn't cause multiple runtimes.
|
||||
|
||||
@@ -103,5 +100,5 @@
|
||||
for(var/s in sharedSoullinks)
|
||||
var/datum/soullink/S = s
|
||||
S.sharerDies(gibbed)
|
||||
|
||||
release_vore_contents(silent = TRUE)
|
||||
return TRUE
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
key_third_person = "blushes"
|
||||
message = "blushes."
|
||||
|
||||
/datum/emote/living/blush/run_emote(mob/user, params)
|
||||
. = ..()
|
||||
if(. && isipcperson(user))
|
||||
do_fake_sparks(5,FALSE,user)
|
||||
|
||||
/datum/emote/living/bow
|
||||
key = "bow"
|
||||
key_third_person = "bows"
|
||||
@@ -226,7 +231,7 @@
|
||||
'sound/voice/catpeople/nyahehe.ogg'),
|
||||
50, 1)
|
||||
return
|
||||
else if(ismoth(C))
|
||||
else if(isinsect(C))
|
||||
playsound(C, 'sound/voice/moth/mothlaugh.ogg', 50, 1)
|
||||
else if(ishumanbasic(C))
|
||||
if(user.gender == FEMALE)
|
||||
@@ -244,7 +249,7 @@
|
||||
. = ..()
|
||||
if(. && iscarbon(user)) //Citadel Edit because this is hilarious
|
||||
var/mob/living/carbon/C = user
|
||||
if(ismoth(C))
|
||||
if(isinsect(C))
|
||||
playsound(C, 'sound/voice/moth/mothchitter.ogg', 50, 1)
|
||||
|
||||
/datum/emote/living/look
|
||||
@@ -326,6 +331,11 @@
|
||||
key_third_person = "smiles"
|
||||
message = "smiles."
|
||||
|
||||
/datum/emote/living/smirk
|
||||
key = "smirk"
|
||||
key_third_person = "smirks"
|
||||
message = "smirks."
|
||||
|
||||
/datum/emote/living/sneeze
|
||||
key = "sneeze"
|
||||
key_third_person = "sneezes"
|
||||
@@ -441,7 +451,7 @@
|
||||
to_chat(user, "You cannot send IC messages (muted).")
|
||||
return FALSE
|
||||
else if(!params)
|
||||
var/custom_emote = stripped_multiline_input(user, "Choose an emote to display.", "Custom Emote", null, MAX_MESSAGE_LEN)
|
||||
var/custom_emote = stripped_multiline_input_or_reflect(user, "Choose an emote to display.", "Custom Emote", null, MAX_MESSAGE_LEN)
|
||||
if(custom_emote && !check_invalid(user, custom_emote))
|
||||
var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable")
|
||||
switch(type)
|
||||
@@ -531,3 +541,29 @@
|
||||
to_chat(user, "<span class='notice'>You ready your slapping hand.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You're incapable of slapping in your current state.</span>")
|
||||
|
||||
/datum/emote/living/audio_emote/blorble
|
||||
key = "blorble"
|
||||
key_third_person = "blorbles"
|
||||
message = "blorbles."
|
||||
message_param = "blorbles at %t."
|
||||
|
||||
/datum/emote/living/audio_emote/blorble/run_emote(mob/user, params)
|
||||
. = ..()
|
||||
if(. && iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
if(isjellyperson(C))
|
||||
pick(playsound(C, 'sound/effects/attackblob.ogg', 50, 1),playsound(C, 'sound/effects/blobattack.ogg', 50, 1))
|
||||
|
||||
/datum/emote/living/audio_emote/blurp
|
||||
key = "blurp"
|
||||
key_third_person = "blurps"
|
||||
message = "blurps."
|
||||
message_param = "blurps at %t."
|
||||
|
||||
/datum/emote/living/audio_emote/blurp/run_emote(mob/user, params)
|
||||
. = ..()
|
||||
if(. && iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
if(isjellyperson(C))
|
||||
pick(playsound(C, 'sound/effects/meatslap.ogg', 50, 1),playsound(C, 'sound/effects/gib_step.ogg', 50, 1))
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
/**
|
||||
* Called by SSmobs at (hopefully) an interval of 1 second.
|
||||
* Splits off into PhysicalLife() and BiologicalLife(). Override those instead of this.
|
||||
*/
|
||||
/mob/living/proc/Life(seconds, times_fired)
|
||||
set waitfor = FALSE
|
||||
set invisibility = 0
|
||||
SHOULD_NOT_SLEEP(TRUE)
|
||||
if(mob_transforming)
|
||||
return
|
||||
|
||||
if(digitalinvis)
|
||||
handle_diginvis() //AI becomes unable to see mob
|
||||
. = SEND_SIGNAL(src, COMSIG_LIVING_LIFE, seconds, times_fired)
|
||||
if(!(. & COMPONENT_INTERRUPT_LIFE_PHYSICAL))
|
||||
PhysicalLife(seconds, times_fired)
|
||||
if(!(. & COMPONENT_INTERRUPT_LIFE_BIOLOGICAL))
|
||||
BiologicalLife(seconds, times_fired)
|
||||
|
||||
if((movement_type & FLYING) && !(movement_type & FLOATING)) //TODO: Better floating
|
||||
float(on = TRUE)
|
||||
// CODE BELOW SHOULD ONLY BE THINGS THAT SHOULD HAPPEN NO MATTER WHAT AND CAN NOT BE SUSPENDED!
|
||||
// Otherwise, it goes into one of the two split Life procs!
|
||||
|
||||
if (client)
|
||||
var/turf/T = get_turf(src)
|
||||
@@ -30,28 +38,56 @@
|
||||
log_game("Z-TRACKING: [src] of type [src.type] has a Z-registration despite not having a client.")
|
||||
update_z(null)
|
||||
|
||||
if (notransform)
|
||||
return
|
||||
if(!loc)
|
||||
return
|
||||
var/datum/gas_mixture/environment = loc.return_air()
|
||||
|
||||
if(stat != DEAD)
|
||||
//Mutations and radiation
|
||||
handle_mutations_and_radiation()
|
||||
|
||||
if(stat != DEAD)
|
||||
//Breathing, if applicable
|
||||
handle_breathing(times_fired)
|
||||
|
||||
/**
|
||||
* Handles biological life processes like chemical metabolism, breathing, etc
|
||||
* Returns TRUE or FALSE based on if we were interrupted. This is used by overridden variants to check if they should stop.
|
||||
*/
|
||||
/mob/living/proc/BiologicalLife(seconds, times_fired)
|
||||
handle_diseases()// DEAD check is in the proc itself; we want it to spread even if the mob is dead, but to handle its disease-y properties only if you're not.
|
||||
|
||||
if (QDELETED(src)) // diseases can qdel the mob via transformations
|
||||
return
|
||||
handle_wounds()
|
||||
|
||||
if(stat != DEAD)
|
||||
//Random events (vomiting etc)
|
||||
handle_random_events()
|
||||
// Everything after this shouldn't process while dead (as of the time of writing)
|
||||
if(stat == DEAD)
|
||||
return FALSE
|
||||
|
||||
//Mutations and radiation
|
||||
handle_mutations_and_radiation()
|
||||
|
||||
//Breathing, if applicable
|
||||
handle_breathing(times_fired)
|
||||
|
||||
if (QDELETED(src)) // diseases can qdel the mob via transformations
|
||||
return FALSE
|
||||
|
||||
//Random events (vomiting etc)
|
||||
handle_random_events()
|
||||
|
||||
//stuff in the stomach
|
||||
handle_stomach()
|
||||
|
||||
handle_block_parry(seconds)
|
||||
|
||||
// These two MIGHT need to be moved to base Life() if we get any in the future that's a "physical" effect that needs to fire even while in stasis.
|
||||
handle_traits() // eye, ear, brain damages
|
||||
handle_status_effects() //all special effects, stun, knockdown, jitteryness, hallucination, sleeping, etc
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Handles physical life processes like being on fire. Don't ask why this is considered "Life".
|
||||
* Returns TRUE or FALSE based on if we were interrupted. This is used by overridden variants to check if they should stop.
|
||||
*/
|
||||
/mob/living/proc/PhysicalLife(seconds, times_fired)
|
||||
if(digitalinvis)
|
||||
handle_diginvis() //AI becomes unable to see mob
|
||||
|
||||
if((movement_type & FLYING) && !(movement_type & FLOATING)) //TODO: Better floating
|
||||
INVOKE_ASYNC(src, /atom/movable.proc/float, TRUE)
|
||||
|
||||
if(!loc)
|
||||
return FALSE
|
||||
|
||||
var/datum/gas_mixture/environment = loc.return_air()
|
||||
|
||||
//Handle temperature/pressure differences between body and environment
|
||||
if(environment)
|
||||
@@ -59,23 +95,11 @@
|
||||
|
||||
handle_fire()
|
||||
|
||||
//stuff in the stomach
|
||||
handle_stomach()
|
||||
|
||||
handle_gravity()
|
||||
|
||||
handle_block_parry(seconds)
|
||||
|
||||
if(machine)
|
||||
machine.check_eye(src)
|
||||
|
||||
if(stat != DEAD)
|
||||
handle_traits() // eye, ear, brain damages
|
||||
if(stat != DEAD)
|
||||
handle_status_effects() //all special effects, stun, knockdown, jitteryness, hallucination, sleeping, etc
|
||||
|
||||
if(stat != DEAD)
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/mob/living/proc/handle_breathing(times_fired)
|
||||
return
|
||||
@@ -87,6 +111,9 @@
|
||||
/mob/living/proc/handle_diseases()
|
||||
return
|
||||
|
||||
/mob/living/proc/handle_wounds()
|
||||
return
|
||||
|
||||
/mob/living/proc/handle_diginvis()
|
||||
if(!digitaldisguise)
|
||||
src.digitaldisguise = image(loc = src)
|
||||
@@ -112,7 +139,7 @@
|
||||
ExtinguishMob()
|
||||
return
|
||||
var/datum/gas_mixture/G = loc.return_air() // Check if we're standing in an oxygenless environment
|
||||
if(G.gases[/datum/gas/oxygen] < 1)
|
||||
if(!G.get_moles(/datum/gas/oxygen, 1))
|
||||
ExtinguishMob() //If there's no oxygen in the tile we're on, put out the fire
|
||||
return
|
||||
var/turf/location = get_turf(src)
|
||||
@@ -168,4 +195,4 @@
|
||||
/mob/living/proc/handle_high_gravity(gravity)
|
||||
if(gravity >= GRAVITY_DAMAGE_TRESHOLD) //Aka gravity values of 3 or more
|
||||
var/grav_stregth = gravity - GRAVITY_DAMAGE_TRESHOLD
|
||||
adjustBruteLoss(min(grav_stregth,3))
|
||||
adjustBruteLoss(min(grav_stregth,3))
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
/mob/living/Bump(atom/A)
|
||||
if(..()) //we are thrown onto something
|
||||
return
|
||||
if (buckled || now_pushing)
|
||||
if(buckled || now_pushing)
|
||||
return
|
||||
if(ismob(A))
|
||||
var/mob/M = A
|
||||
@@ -273,7 +273,7 @@
|
||||
return
|
||||
stop_pulling()
|
||||
|
||||
changeNext_move(CLICK_CD_GRABBING)
|
||||
DelayNextAction(CLICK_CD_GRABBING)
|
||||
|
||||
if(AM.pulledby)
|
||||
if(!supress_message)
|
||||
@@ -605,41 +605,55 @@
|
||||
SEND_SIGNAL(item, COMSIG_ITEM_WEARERCROSSED, AM)
|
||||
|
||||
/mob/living/proc/makeTrail(turf/target_turf, turf/start, direction)
|
||||
if(!has_gravity())
|
||||
if(!has_gravity() || !isturf(start) || !blood_volume)
|
||||
return
|
||||
var/blood_exists = FALSE
|
||||
var/blood_exists = locate(/obj/effect/decal/cleanable/trail_holder) in start
|
||||
|
||||
for(var/obj/effect/decal/cleanable/trail_holder/C in start) //checks for blood splatter already on the floor
|
||||
blood_exists = TRUE
|
||||
if(isturf(start))
|
||||
var/trail_type = getTrail()
|
||||
if(trail_type)
|
||||
var/brute_ratio = round(getBruteLoss() / maxHealth, 0.1)
|
||||
if(blood_volume && blood_volume > max((BLOOD_VOLUME_NORMAL*blood_ratio)*(1 - brute_ratio * 0.25), 0))//don't leave trail if blood volume below a threshold
|
||||
blood_volume = max(blood_volume - max(1, brute_ratio * 2), 0) //that depends on our brute damage.
|
||||
var/newdir = get_dir(target_turf, start)
|
||||
if(newdir != direction)
|
||||
newdir = newdir | direction
|
||||
if(newdir == 3) //N + S
|
||||
newdir = NORTH
|
||||
else if(newdir == 12) //E + W
|
||||
newdir = EAST
|
||||
if((newdir in GLOB.cardinals) && (prob(50)))
|
||||
newdir = turn(get_dir(target_turf, start), 180)
|
||||
if(!blood_exists)
|
||||
new /obj/effect/decal/cleanable/trail_holder(start, get_static_viruses())
|
||||
var/trail_type = getTrail()
|
||||
if(!trail_type)
|
||||
return
|
||||
|
||||
for(var/obj/effect/decal/cleanable/trail_holder/TH in start)
|
||||
if((!(newdir in TH.existing_dirs) || trail_type == "trails_1" || trail_type == "trails_2") && TH.existing_dirs.len <= 16) //maximum amount of overlays is 16 (all light & heavy directions filled)
|
||||
TH.existing_dirs += newdir
|
||||
TH.add_overlay(image('icons/effects/blood.dmi', trail_type, dir = newdir))
|
||||
TH.transfer_mob_blood_dna(src)
|
||||
var/brute_ratio = round(getBruteLoss() / maxHealth, 0.1)
|
||||
if(blood_volume < max(BLOOD_VOLUME_NORMAL*(1 - brute_ratio * 0.25), 0))//don't leave trail if blood volume below a threshold
|
||||
return
|
||||
|
||||
var/bleed_amount = bleedDragAmount()
|
||||
blood_volume = max(blood_volume - bleed_amount, 0) //that depends on our brute damage.
|
||||
var/newdir = get_dir(target_turf, start)
|
||||
if(newdir != direction)
|
||||
newdir = newdir | direction
|
||||
if(newdir == (NORTH|SOUTH))
|
||||
newdir = NORTH
|
||||
else if(newdir == (EAST|WEST))
|
||||
newdir = EAST
|
||||
if((newdir in GLOB.cardinals) && (prob(50)))
|
||||
newdir = turn(get_dir(target_turf, start), 180)
|
||||
if(!blood_exists)
|
||||
new /obj/effect/decal/cleanable/trail_holder(start, get_static_viruses())
|
||||
|
||||
for(var/obj/effect/decal/cleanable/trail_holder/TH in start)
|
||||
if((!(newdir in TH.existing_dirs) || trail_type == "trails_1" || trail_type == "trails_2") && TH.existing_dirs.len <= 16) //maximum amount of overlays is 16 (all light & heavy directions filled)
|
||||
TH.existing_dirs += newdir
|
||||
TH.add_overlay(image('icons/effects/blood.dmi', trail_type, dir = newdir))
|
||||
TH.transfer_mob_blood_dna(src)
|
||||
|
||||
/mob/living/carbon/human/makeTrail(turf/T)
|
||||
if((NOBLOOD in dna.species.species_traits) || !bleed_rate || bleedsuppress)
|
||||
if((NOBLOOD in dna.species.species_traits) || !is_bleeding() || bleedsuppress)
|
||||
return
|
||||
..()
|
||||
|
||||
///Returns how much blood we're losing from being dragged a tile, from [mob/living/proc/makeTrail]
|
||||
/mob/living/proc/bleedDragAmount()
|
||||
var/brute_ratio = round(getBruteLoss() / maxHealth, 0.1)
|
||||
return max(1, brute_ratio * 2)
|
||||
|
||||
/mob/living/carbon/bleedDragAmount()
|
||||
var/bleed_amount = 0
|
||||
for(var/i in all_wounds)
|
||||
var/datum/wound/iter_wound = i
|
||||
bleed_amount += iter_wound.drag_bleed_amount()
|
||||
return bleed_amount
|
||||
|
||||
/mob/living/proc/getTrail()
|
||||
if(getBruteLoss() < 300)
|
||||
return pick("ltrails_1", "ltrails_2")
|
||||
@@ -676,7 +690,7 @@
|
||||
..(pressure_difference, direction, pressure_resistance_prob_delta)
|
||||
|
||||
/mob/living/can_resist()
|
||||
return !((next_move > world.time) || !CHECK_MOBILITY(src, MOBILITY_RESIST))
|
||||
return CheckResistCooldown() && CHECK_MOBILITY(src, MOBILITY_RESIST)
|
||||
|
||||
/// Resist verb for attempting to get out of whatever is restraining your motion. Gives you resist clickdelay if do_resist() returns true.
|
||||
/mob/living/verb/resist()
|
||||
@@ -687,10 +701,12 @@
|
||||
return
|
||||
|
||||
if(do_resist())
|
||||
changeNext_move(CLICK_CD_RESIST)
|
||||
MarkResistTime()
|
||||
DelayNextAction(CLICK_CD_RESIST)
|
||||
|
||||
/// The actual proc for resisting. Return TRUE to give clickdelay.
|
||||
/// The actual proc for resisting. Return TRUE to give CLICK_CD_RESIST clickdelay.
|
||||
/mob/living/proc/do_resist()
|
||||
set waitfor = FALSE // some of these sleep.
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_RESIST, src)
|
||||
//resisting grabs (as if it helps anyone...)
|
||||
// only works if you're not cuffed.
|
||||
@@ -701,7 +717,7 @@
|
||||
return old_gs? TRUE : FALSE
|
||||
|
||||
// unbuckling yourself. stops the chain if you try it.
|
||||
if(buckled && last_special <= world.time)
|
||||
if(buckled)
|
||||
log_combat(src, buckled, "resisted buckle")
|
||||
return resist_buckle()
|
||||
|
||||
@@ -730,13 +746,12 @@
|
||||
|
||||
if(CHECK_MOBILITY(src, MOBILITY_USE) && resist_embedded()) //Citadel Change for embedded removal memes - requires being able to use items.
|
||||
// DO NOT GIVE DEFAULT CLICKDELAY - This is a combat action.
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
DelayNextAction(CLICK_CD_MELEE)
|
||||
return FALSE
|
||||
|
||||
if(last_special <= world.time)
|
||||
resist_restraints() //trying to remove cuffs.
|
||||
// DO NOT GIVE CLICKDELAY - last_special handles this.
|
||||
return FALSE
|
||||
resist_restraints() //trying to remove cuffs.
|
||||
// DO NOT GIVE CLICKDELAY
|
||||
return FALSE
|
||||
|
||||
/// Proc to resist a grab. moving_resist is TRUE if this began by someone attempting to move. Return FALSE if still grabbed/failed to break out. Use this instead of resist_grab() directly.
|
||||
/mob/proc/attempt_resist_grab(moving_resist, forced, log = TRUE)
|
||||
@@ -802,7 +817,7 @@
|
||||
else
|
||||
throw_alert("gravity", /obj/screen/alert/weightless)
|
||||
if(!override && !is_flying())
|
||||
float(!has_gravity)
|
||||
INVOKE_ASYNC(src, /atom/movable.proc/float, !has_gravity)
|
||||
|
||||
/mob/living/float(on)
|
||||
if(throwing)
|
||||
@@ -914,7 +929,7 @@
|
||||
floating_need_update = TRUE
|
||||
|
||||
/mob/living/proc/get_temperature(datum/gas_mixture/environment)
|
||||
var/loc_temp = environment ? environment.temperature : T0C
|
||||
var/loc_temp = environment ? environment.return_temperature() : T0C
|
||||
if(isobj(loc))
|
||||
var/obj/oloc = loc
|
||||
var/obj_temp = oloc.return_temperature()
|
||||
@@ -1196,30 +1211,29 @@
|
||||
|
||||
/mob/living/vv_edit_var(var_name, var_value)
|
||||
switch(var_name)
|
||||
if ("maxHealth")
|
||||
if (NAMEOF(src, maxHealth))
|
||||
if (!isnum(var_value) || var_value <= 0)
|
||||
return FALSE
|
||||
if("stat")
|
||||
if(NAMEOF(src, stat))
|
||||
if((stat == DEAD) && (var_value < DEAD))//Bringing the dead back to life
|
||||
GLOB.dead_mob_list -= src
|
||||
GLOB.alive_mob_list += src
|
||||
if((stat < DEAD) && (var_value == DEAD))//Kill he
|
||||
GLOB.alive_mob_list -= src
|
||||
GLOB.dead_mob_list += src
|
||||
if(NAMEOF(src, health)) //this doesn't work. gotta use procs instead.
|
||||
return FALSE
|
||||
. = ..()
|
||||
switch(var_name)
|
||||
if("eye_blind")
|
||||
if(NAMEOF(src, eye_blind))
|
||||
set_blindness(var_value)
|
||||
if("eye_damage")
|
||||
var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
|
||||
E?.setOrganDamage(var_value)
|
||||
if("eye_blurry")
|
||||
if(NAMEOF(src, eye_blurry))
|
||||
set_blurriness(var_value)
|
||||
if("maxHealth")
|
||||
if(NAMEOF(src, maxHealth))
|
||||
updatehealth()
|
||||
if("resize")
|
||||
if(NAMEOF(src, resize))
|
||||
update_transform()
|
||||
if("lighting_alpha")
|
||||
if(NAMEOF(src, lighting_alpha))
|
||||
sync_lighting_plane_alpha()
|
||||
|
||||
/mob/living/proc/do_adrenaline(
|
||||
|
||||
@@ -10,18 +10,17 @@
|
||||
REMOVE_TRAIT(src, TRAIT_SPRINT_LOCKED, ACTIVE_BLOCK_TRAIT)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/active_block)
|
||||
var/datum/block_parry_data/data = I.get_block_parry_data()
|
||||
if(timeToNextMove() < data.block_end_click_cd_add)
|
||||
changeNext_move(data.block_end_click_cd_add)
|
||||
DelayNextAction(data.block_end_click_cd_add)
|
||||
return TRUE
|
||||
|
||||
/mob/living/proc/start_active_blocking(obj/item/I)
|
||||
/mob/living/proc/active_block_start(obj/item/I)
|
||||
if(combat_flags & (COMBAT_FLAG_ACTIVE_BLOCK_STARTING | COMBAT_FLAG_ACTIVE_BLOCKING))
|
||||
return FALSE
|
||||
if(!(I in held_items))
|
||||
return FALSE
|
||||
var/datum/block_parry_data/data = I.get_block_parry_data()
|
||||
if(!istype(data)) //Typecheck because if an admin/coder screws up varediting or something we do not want someone being broken forever, the CRASH logs feedback so we know what happened.
|
||||
CRASH("start_active_blocking called with an item with no valid data: [I] --> [I.block_parry_data]!")
|
||||
CRASH("ACTIVE_BLOCK_START called with an item with no valid data: [I] --> [I.block_parry_data]!")
|
||||
combat_flags |= COMBAT_FLAG_ACTIVE_BLOCKING
|
||||
active_block_item = I
|
||||
if(data.block_lock_attacking)
|
||||
@@ -83,15 +82,21 @@
|
||||
return FALSE
|
||||
// QOL: Instead of trying to just block with held item, grab first available item.
|
||||
var/obj/item/I = find_active_block_item()
|
||||
if(!I)
|
||||
to_chat(src, "<span class='warning'>You can't block with your bare hands!</span>")
|
||||
var/list/other_items = list()
|
||||
if(SEND_SIGNAL(src, COMSIG_LIVING_ACTIVE_BLOCK_START, I, other_items) & COMPONENT_PREVENT_BLOCK_START)
|
||||
to_chat(src, "<span class='warning'>Something is preventing you from blocking!</span>")
|
||||
return
|
||||
if(!I)
|
||||
if(!length(other_items))
|
||||
to_chat(src, "<span class='warning'>You can't block with your bare hands!</span>")
|
||||
return
|
||||
I = other_items[1]
|
||||
if(!I.can_active_block())
|
||||
to_chat(src, "<span class='warning'>[I] is either not capable of being used to actively block, or is not currently in a state that can! (Try wielding it if it's twohanded, for example.)</span>")
|
||||
return
|
||||
// QOL: Attempt to toggle on combat mode if it isn't already
|
||||
SEND_SIGNAL(src, COMSIG_ENABLE_COMBAT_MODE)
|
||||
if(!SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE))
|
||||
if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
|
||||
to_chat(src, "<span class='warning'>You must be in combat mode to actively block!</span>")
|
||||
return FALSE
|
||||
var/datum/block_parry_data/data = I.get_block_parry_data()
|
||||
@@ -104,7 +109,7 @@
|
||||
animate(src, pixel_x = get_standard_pixel_x_offset(), pixel_y = get_standard_pixel_y_offset(), time = 2.5, FALSE, SINE_EASING | EASE_IN, ANIMATION_END_NOW)
|
||||
return
|
||||
combat_flags &= ~(COMBAT_FLAG_ACTIVE_BLOCK_STARTING)
|
||||
start_active_blocking(I)
|
||||
active_block_start(I)
|
||||
|
||||
/**
|
||||
* Gets the first item we can that can block, but if that fails, default to active held item.COMSIG_ENABLE_COMBAT_MODE
|
||||
@@ -115,7 +120,8 @@
|
||||
for(var/obj/item/I in held_items - held)
|
||||
if(I.can_active_block())
|
||||
return I
|
||||
return held
|
||||
else
|
||||
return held
|
||||
|
||||
/**
|
||||
* Proc called by keybindings to stop active blocking.
|
||||
@@ -174,6 +180,12 @@
|
||||
|
||||
/// Apply the stamina damage to our user, notice how damage argument is stamina_amount.
|
||||
/obj/item/proc/active_block_do_stamina_damage(mob/living/owner, atom/object, stamina_amount, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
if(istype(object, /obj/item/projectile))
|
||||
var/obj/item/projectile/P = object
|
||||
if(P.stamina)
|
||||
var/blocked = active_block_calculate_final_damage(owner, object, P.stamina, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return)
|
||||
var/stam = active_block_stamina_cost(owner, object, blocked, attack_text, ATTACK_TYPE_PROJECTILE, armour_penetration, attacker, def_zone, final_block_chance, block_return)
|
||||
stamina_amount += stam
|
||||
var/datum/block_parry_data/data = get_block_parry_data()
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/C = owner
|
||||
|
||||
@@ -24,35 +24,49 @@
|
||||
// yanderedev else if time
|
||||
var/obj/item/using_item = get_active_held_item()
|
||||
var/datum/block_parry_data/data
|
||||
var/datum/tool
|
||||
var/method
|
||||
if(using_item?.can_active_parry())
|
||||
data = using_item.block_parry_data
|
||||
method = ITEM_PARRY
|
||||
tool = using_item
|
||||
else if(mind?.martial_art?.can_martial_parry)
|
||||
data = mind.martial_art.block_parry_data
|
||||
method = MARTIAL_PARRY
|
||||
else if(combat_flags & COMBAT_FLAG_UNARMED_PARRY)
|
||||
tool = mind.martial_art
|
||||
else if((combat_flags & COMBAT_FLAG_UNARMED_PARRY) && check_unarmed_parry_activation_special())
|
||||
data = block_parry_data
|
||||
method = UNARMED_PARRY
|
||||
tool = src
|
||||
else
|
||||
// QOL: If none of the above work, try to find another item.
|
||||
var/obj/item/backup = find_backup_parry_item()
|
||||
if(!backup)
|
||||
to_chat(src, "<span class='warning'>You have nothing to parry with!</span>")
|
||||
return FALSE
|
||||
data = backup.block_parry_data
|
||||
using_item = backup
|
||||
if(backup)
|
||||
tool = backup
|
||||
data = backup.block_parry_data
|
||||
using_item = backup
|
||||
method = ITEM_PARRY
|
||||
var/list/other_items = list()
|
||||
if(SEND_SIGNAL(src, COMSIG_LIVING_ACTIVE_PARRY_START, method, tool, other_items) & COMPONENT_PREVENT_PARRY_START)
|
||||
to_chat(src, "<span class='warning'>Something is preventing you from parrying!</span>")
|
||||
return
|
||||
if(!using_item && !method && length(other_items))
|
||||
using_item = other_items[1]
|
||||
method = ITEM_PARRY
|
||||
data = using_item.block_parry_data
|
||||
if(!method)
|
||||
to_chat(src, "<span class='warning'>You have nothing to parry with!</span>")
|
||||
return FALSE
|
||||
//QOL: Try to enable combat mode if it isn't already
|
||||
SEND_SIGNAL(src, COMSIG_ENABLE_COMBAT_MODE)
|
||||
if(!SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE))
|
||||
if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
|
||||
to_chat(src, "<span class='warning'>You must be in combat mode to parry!</span>")
|
||||
return FALSE
|
||||
data = return_block_parry_datum(data)
|
||||
var/full_parry_duration = data.parry_time_windup + data.parry_time_active + data.parry_time_spindown
|
||||
// no system in place to "fallback" if out of the 3 the top priority one can't parry due to constraints but something else can.
|
||||
// can always implement it later, whatever.
|
||||
if((data.parry_respect_clickdelay && (next_move > world.time)) || ((parry_end_time_last + data.parry_cooldown) > world.time))
|
||||
if((data.parry_respect_clickdelay && !CheckActionCooldown()) || ((parry_end_time_last + data.parry_cooldown) > world.time))
|
||||
to_chat(src, "<span class='warning'>You are not ready to parry (again)!</span>")
|
||||
return
|
||||
// Point of no return, make sure everything is set.
|
||||
@@ -79,6 +93,12 @@
|
||||
if(I.can_active_parry())
|
||||
return I
|
||||
|
||||
/**
|
||||
* Check if we can unarmed parry
|
||||
*/
|
||||
/mob/living/proc/check_unarmed_parry_activation_special()
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Called via timer when the parry sequence ends.
|
||||
*/
|
||||
@@ -101,7 +121,7 @@
|
||||
Stagger(data.parry_failed_stagger_duration)
|
||||
effect_text += "staggering themselves"
|
||||
if(data.parry_failed_clickcd_duration)
|
||||
changeNext_move(data.parry_failed_clickcd_duration)
|
||||
DelayNextAction(data.parry_failed_clickcd_duration, flush = TRUE)
|
||||
effect_text += "throwing themselves off balance"
|
||||
handle_parry_ending_effects(data, effect_text)
|
||||
parrying = NOT_PARRYING
|
||||
@@ -140,17 +160,17 @@
|
||||
/**
|
||||
* Called when an attack is parried using this, whether or not the parry was successful.
|
||||
*/
|
||||
/obj/item/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, parry_efficiency, parry_time)
|
||||
/obj/item/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time)
|
||||
|
||||
/**
|
||||
* Called when an attack is parried innately, whether or not the parry was successful.
|
||||
*/
|
||||
/mob/living/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, parry_efficiency, parry_time)
|
||||
/mob/living/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time)
|
||||
|
||||
/**
|
||||
* Called when an attack is parried using this, whether or not the parry was successful.
|
||||
*/
|
||||
/datum/martial_art/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, parry_efficiency, parry_time)
|
||||
/datum/martial_art/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time)
|
||||
|
||||
/**
|
||||
* Called when an attack is parried and block_parra_data indicates to use a proc to handle counterattack.
|
||||
@@ -225,7 +245,7 @@
|
||||
. |= BLOCK_SUCCESS
|
||||
var/list/effect_text
|
||||
if(efficiency >= data.parry_efficiency_to_counterattack)
|
||||
run_parry_countereffects(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency)
|
||||
effect_text = run_parry_countereffects(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency)
|
||||
if(data.parry_flags & PARRY_DEFAULT_HANDLE_FEEDBACK)
|
||||
handle_parry_feedback(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, effect_text)
|
||||
successful_parries += efficiency
|
||||
@@ -234,9 +254,12 @@
|
||||
|
||||
/mob/living/proc/handle_parry_feedback(atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list(), parry_efficiency, list/effect_text)
|
||||
var/datum/block_parry_data/data = get_parry_data()
|
||||
var/knockdown_check = FALSE
|
||||
if(data.parry_data[PARRY_KNOCKDOWN_ATTACKER] && parry_efficiency >= data.parry_efficiency_to_counterattack)
|
||||
knockdown_check = TRUE
|
||||
if(data.parry_sounds)
|
||||
playsound(src, pick(data.parry_sounds), 75)
|
||||
visible_message("<span class='danger'>[src] parries \the [attack_text][length(effect_text)? ", [english_list(effect_text)] [attacker]" : ""]!</span>")
|
||||
visible_message("<span class='danger'>[src] parries [attack_text][length(effect_text)? ", [english_list(effect_text)] [attacker]" : ""][length(effect_text) && knockdown_check? " and" : ""][knockdown_check? " knocking them to the ground" : ""]!</span>")
|
||||
|
||||
/// Run counterattack if any
|
||||
/mob/living/proc/run_parry_countereffects(atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list(), parry_efficiency)
|
||||
@@ -257,7 +280,7 @@
|
||||
if(data.parry_data[PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN])
|
||||
switch(parrying)
|
||||
if(ITEM_PARRY)
|
||||
active_parry_item.melee_attack_chain(src, attacker, null, ATTACKCHAIN_PARRY_COUNTERATTACK, data.parry_data[PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN])
|
||||
active_parry_item.melee_attack_chain(src, attacker, null, ATTACK_IS_PARRY_COUNTERATTACK | ATTACK_IGNORE_CLICKDELAY | ATTACK_IGNORE_ACTION | NO_AUTO_CLICKDELAY_HANDLING, data.parry_data[PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN])
|
||||
effect_text += "reflexively counterattacking with [active_parry_item]"
|
||||
if(UNARMED_PARRY) // WARNING: If you are using these two, the attackchain parry counterattack flags and damage multipliers are unimplemented. Be careful with how you handle this.
|
||||
UnarmedAttack(attacker)
|
||||
@@ -268,15 +291,15 @@
|
||||
if(data.parry_data[PARRY_DISARM_ATTACKER])
|
||||
L.drop_all_held_items()
|
||||
effect_text += "disarming"
|
||||
if(data.parry_data[PARRY_KNOCKDOWN_ATTACKER])
|
||||
L.DefaultCombatKnockdown(data.parry_data[PARRY_KNOCKDOWN_ATTACKER])
|
||||
effect_text += "knocking them to the ground"
|
||||
if(data.parry_data[PARRY_STAGGER_ATTACKER])
|
||||
L.Stagger(data.parry_data[PARRY_STAGGER_ATTACKER])
|
||||
effect_text += "staggering"
|
||||
if(data.parry_data[PARRY_DAZE_ATTACKER])
|
||||
L.Daze(data.parry_data[PARRY_DAZE_ATTACKER])
|
||||
effect_text += "dazing"
|
||||
if(data.parry_data[PARRY_KNOCKDOWN_ATTACKER])
|
||||
L.DefaultCombatKnockdown(data.parry_data[PARRY_KNOCKDOWN_ATTACKER])
|
||||
// effect_text += "knocking them to the ground" - snowflaked above
|
||||
return effect_text
|
||||
|
||||
/// Gets the datum/block_parry_data we're going to use to parry.
|
||||
|
||||
@@ -126,6 +126,8 @@ GLOBAL_LIST_EMPTY(block_parry_data)
|
||||
var/list/parry_imperfect_falloff_percent_override
|
||||
/// Efficiency in percent on perfect parry.
|
||||
var/parry_efficiency_perfect = 120
|
||||
/// Override for attack types, list("[ATTACK_TYPE_DEFINE]" = perecntage) for perfect efficiency.
|
||||
var/parry_efficiency_perfect_override
|
||||
/// Parry effect data.
|
||||
var/list/parry_data = list(
|
||||
PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 1
|
||||
@@ -180,7 +182,11 @@ GLOBAL_LIST_EMPTY(block_parry_data)
|
||||
if(isnull(leeway))
|
||||
leeway = parry_time_perfect_leeway
|
||||
difference -= leeway
|
||||
. = parry_efficiency_perfect
|
||||
var/perfect = attack_type_list_scan(parry_efficiency_perfect_override, attack_type)
|
||||
if(isnull(perfect))
|
||||
. = parry_efficiency_perfect
|
||||
else
|
||||
. = perfect
|
||||
if(difference <= 0)
|
||||
return
|
||||
var/falloff = attack_type_list_scan(parry_imperfect_falloff_percent_override, attack_type)
|
||||
@@ -276,6 +282,7 @@ GLOBAL_LIST_EMPTY(block_parry_data)
|
||||
RENDER_VARIABLE_SIMPLE(parry_imperfect_falloff_percent, "Linear falloff in percent per decisecond for attacks parried outside of perfect window.")
|
||||
RENDER_OVERRIDE_LIST(parry_imperfect_falloff_percent_override, "Override for the above for each attack type")
|
||||
RENDER_VARIABLE_SIMPLE(parry_efficiency_perfect, "Efficiency in percentage a parry in the perfect window is considered.")
|
||||
RENDER_OVERRIDE_LIST(parry_efficiency_perfect_override, "Override for the above for each attack type")
|
||||
// parry_data
|
||||
dat += ""
|
||||
RENDER_VARIABLE_SIMPLE(parry_efficiency_considered_successful, "Minimum parry efficiency to be considered a successful parry.")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
/mob/living/proc/run_armor_check(def_zone = null, attack_flag = "melee", absorb_text = "Your armor absorbs the blow!", soften_text = "Your armor softens the blow!", armour_penetration, penetrated_text = "Your armor was penetrated!", silent=FALSE)
|
||||
var/armor = getarmor(def_zone, attack_flag)
|
||||
|
||||
|
||||
if(silent)
|
||||
return max(0, armor - armour_penetration)
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
final_percent = returnlist[BLOCK_RETURN_PROJECTILE_BLOCK_PERCENTAGE]
|
||||
if(returned & BLOCK_SHOULD_REDIRECT)
|
||||
handle_projectile_attack_redirection(P, returnlist[BLOCK_RETURN_REDIRECT_METHOD])
|
||||
return BULLET_ACT_FORCE_PIERCE
|
||||
if(returned & BLOCK_REDIRECTED)
|
||||
return BULLET_ACT_FORCE_PIERCE
|
||||
if(returned & BLOCK_SUCCESS)
|
||||
@@ -85,7 +86,7 @@
|
||||
totaldamage = block_calculate_resultant_damage(totaldamage, returnlist)
|
||||
var/armor = run_armor_check(def_zone, P.flag, null, null, P.armour_penetration, null)
|
||||
if(!P.nodamage)
|
||||
apply_damage(totaldamage, P.damage_type, def_zone, armor)
|
||||
apply_damage(totaldamage, P.damage_type, def_zone, armor, wound_bonus = P.wound_bonus, bare_wound_bonus = P.bare_wound_bonus, sharpness = P.sharpness)
|
||||
if(P.dismemberment)
|
||||
check_projectile_dismemberment(P, def_zone)
|
||||
var/missing = 100 - final_percent
|
||||
@@ -108,12 +109,6 @@
|
||||
/mob/living/proc/catch_item(obj/item/I, skip_throw_mode_check = FALSE)
|
||||
return FALSE
|
||||
|
||||
/mob/living/proc/embed_item(obj/item/I)
|
||||
return
|
||||
|
||||
/mob/living/proc/can_embed(obj/item/I)
|
||||
return FALSE
|
||||
|
||||
/mob/living/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
|
||||
// Throwingdatum can be null if someone had an accident() while slipping with an item in hand.
|
||||
var/obj/item/I
|
||||
@@ -129,37 +124,25 @@
|
||||
skipcatch = TRUE
|
||||
blocked = TRUE
|
||||
total_damage = block_calculate_resultant_damage(total_damage, block_return)
|
||||
else if(I && I.throw_speed >= EMBED_THROWSPEED_THRESHOLD && can_embed(I, src) && prob(I.embedding["embed_chance"]) && !HAS_TRAIT(src, TRAIT_PIERCEIMMUNE) && (!HAS_TRAIT(src, TRAIT_AUTO_CATCH_ITEM) || incapacitated() || get_active_held_item()))
|
||||
embed_item(I)
|
||||
hitpush = FALSE
|
||||
skipcatch = TRUE //can't catch the now embedded item
|
||||
if(I)
|
||||
var/nosell_hit = SEND_SIGNAL(I, COMSIG_MOVABLE_IMPACT_ZONE, src, impacting_zone, throwingdatum, FALSE, blocked)
|
||||
if(nosell_hit)
|
||||
skipcatch = TRUE
|
||||
hitpush = FALSE
|
||||
if(!skipcatch && isturf(I.loc) && catch_item(I))
|
||||
return TRUE
|
||||
var/dtype = BRUTE
|
||||
var/volume = I.get_volume_by_throwforce_and_or_w_class()
|
||||
SEND_SIGNAL(I, COMSIG_MOVABLE_IMPACT_ZONE, src, impacting_zone)
|
||||
|
||||
dtype = I.damtype
|
||||
|
||||
if (I.throwforce > 0) //If the weapon's throwforce is greater than zero...
|
||||
if (I.throwhitsound) //...and throwhitsound is defined...
|
||||
playsound(loc, I.throwhitsound, volume, 1, -1) //...play the weapon's throwhitsound.
|
||||
else if(I.hitsound) //Otherwise, if the weapon's hitsound is defined...
|
||||
playsound(loc, I.hitsound, volume, 1, -1) //...play the weapon's hitsound.
|
||||
else if(!I.throwhitsound) //Otherwise, if throwhitsound isn't defined...
|
||||
playsound(loc, 'sound/weapons/genhit.ogg',volume, 1, -1) //...play genhit.ogg.
|
||||
|
||||
else if(!I.throwhitsound && I.throwforce > 0) //Otherwise, if the item doesn't have a throwhitsound and has a throwforce greater than zero...
|
||||
playsound(loc, 'sound/weapons/genhit.ogg', volume, 1, -1)//...play genhit.ogg
|
||||
if(!I.throwforce)// Otherwise, if the item's throwforce is 0...
|
||||
playsound(loc, 'sound/weapons/throwtap.ogg', 1, volume, -1)//...play throwtap.ogg.
|
||||
if(!blocked)
|
||||
visible_message("<span class='danger'>[src] has been hit by [I].</span>", \
|
||||
"<span class='userdanger'>You have been hit by [I].</span>")
|
||||
var/armor = run_armor_check(impacting_zone, "melee", "Your armor has protected your [parse_zone(impacting_zone)].", "Your armor has softened hit to your [parse_zone(impacting_zone)].",I.armour_penetration)
|
||||
apply_damage(total_damage, dtype, impacting_zone, armor)
|
||||
if(I.thrownby)
|
||||
log_combat(I.thrownby, src, "threw and hit", I)
|
||||
if(!nosell_hit)
|
||||
visible_message("<span class='danger'>[src] is hit by [I]!</span>", \
|
||||
"<span class='userdanger'>You're hit by [I]!</span>")
|
||||
if(!I.throwforce)
|
||||
return
|
||||
var/armor = run_armor_check(impacting_zone, "melee", "Your armor has protected your [parse_zone(impacting_zone)].", "Your armor has softened hit to your [parse_zone(impacting_zone)].",I.armour_penetration)
|
||||
apply_damage(I.throwforce, dtype, impacting_zone, armor, sharpness=I.get_sharpness(), wound_bonus=(nosell_hit * CANT_WOUND))
|
||||
else
|
||||
return 1
|
||||
else
|
||||
@@ -234,8 +217,8 @@
|
||||
//proc to upgrade a simple pull into a more aggressive grab.
|
||||
/mob/living/proc/grippedby(mob/living/carbon/user, instant = FALSE)
|
||||
if(user.grab_state < GRAB_KILL)
|
||||
user.changeNext_move(CLICK_CD_GRABBING)
|
||||
playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
user.DelayNextAction(CLICK_CD_GRABBING, flush = TRUE)
|
||||
playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
|
||||
if(user.grab_state) //only the first upgrade is instantaneous
|
||||
var/old_grab_state = user.grab_state
|
||||
@@ -289,10 +272,10 @@
|
||||
user.set_pull_offsets(src, grab_state)
|
||||
return 1
|
||||
|
||||
/mob/living/attack_hand(mob/user)
|
||||
/mob/living/on_attack_hand(mob/user, act_intent = user.a_intent, attackchain_flags)
|
||||
..() //Ignoring parent return value here.
|
||||
SEND_SIGNAL(src, COMSIG_MOB_ATTACK_HAND, user)
|
||||
if((user != src) && user.a_intent != INTENT_HELP && (mob_run_block(user, 0, user.name, ATTACK_TYPE_UNARMED | ATTACK_TYPE_MELEE, null, user, check_zone(user.zone_selected), null) & BLOCK_SUCCESS))
|
||||
if((user != src) && act_intent != INTENT_HELP && (mob_run_block(user, 0, user.name, ATTACK_TYPE_UNARMED | ATTACK_TYPE_MELEE | ((attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE), null, user, check_zone(user.zone_selected), null) & BLOCK_SUCCESS))
|
||||
log_combat(user, src, "attempted to touch")
|
||||
visible_message("<span class='warning'>[user] attempted to touch [src]!</span>",
|
||||
"<span class='warning'>[user] attempted to touch you!</span>", target = user,
|
||||
@@ -342,6 +325,9 @@
|
||||
|
||||
/mob/living/attack_animal(mob/living/simple_animal/M)
|
||||
M.face_atom(src)
|
||||
if(!M.CheckActionCooldown(CLICK_CD_MELEE))
|
||||
return
|
||||
M.DelayNextAction()
|
||||
if(M.melee_damage_upper == 0)
|
||||
M.visible_message("<span class='notice'>\The [M] [M.friendly_verb_continuous] [src]!</span>",
|
||||
"<span class='notice'>You [M.friendly_verb_simple] [src]!</span>", target = src,
|
||||
@@ -357,7 +343,7 @@
|
||||
return 0
|
||||
damage = block_calculate_resultant_damage(damage, return_list)
|
||||
if(M.attack_sound)
|
||||
playsound(loc, M.attack_sound, 50, 1, 1)
|
||||
playsound(src, M.attack_sound, 50, 1, 1)
|
||||
M.do_attack_animation(src)
|
||||
visible_message("<span class='danger'>\The [M] [M.attack_verb_continuous] [src]!</span>", \
|
||||
"<span class='userdanger'>\The [M] [M.attack_verb_continuous] you!</span>", null, COMBAT_MESSAGE_RANGE, null,
|
||||
@@ -366,6 +352,9 @@
|
||||
return damage
|
||||
|
||||
/mob/living/attack_paw(mob/living/carbon/monkey/M)
|
||||
if(!M.CheckActionCooldown(CLICK_CD_MELEE))
|
||||
return
|
||||
M.DelayNextAction()
|
||||
if (M.a_intent == INTENT_HARM)
|
||||
if(HAS_TRAIT(M, TRAIT_PACIFISM))
|
||||
to_chat(M, "<span class='notice'>You don't want to hurt anyone!</span>")
|
||||
@@ -387,6 +376,7 @@
|
||||
visible_message("<span class='danger'>[M.name] has attempted to bite [src]!</span>", \
|
||||
"<span class='userdanger'>[M.name] has attempted to bite [src]!</span>", null, COMBAT_MESSAGE_RANGE, null,
|
||||
M, "<span class='danger'>You have attempted to bite [src]!</span>")
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/attack_larva(mob/living/carbon/alien/larva/L)
|
||||
|
||||
@@ -53,7 +53,6 @@
|
||||
|
||||
var/hallucination = 0 //Directly affects how long a mob will hallucinate for
|
||||
|
||||
var/last_special = 0 //Used by the resist verb, likely used to prevent players from bypassing next_move by logging in/out.
|
||||
var/timeofdeath = 0
|
||||
|
||||
//Allows mobs to move through dense areas without restriction. For instance, in space or out of holder objects.
|
||||
|
||||
@@ -96,7 +96,13 @@
|
||||
mobility_flags &= ~MOBILITY_STAND
|
||||
setMovetype(movement_type | CRAWLING)
|
||||
if(!lying) //force them on the ground
|
||||
lying = pick(90, 270)
|
||||
switch(dir)
|
||||
if(NORTH, SOUTH)
|
||||
lying = pick(90, 270)
|
||||
if(EAST)
|
||||
lying = 90
|
||||
else //West
|
||||
lying = 270
|
||||
if(has_gravity() && !buckled)
|
||||
playsound(src, "bodyfall", 20, 1)
|
||||
else
|
||||
|
||||
@@ -88,11 +88,22 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
|
||||
var/static/list/one_character_prefix = list(MODE_HEADSET = TRUE, MODE_ROBOT = TRUE, MODE_WHISPER = TRUE)
|
||||
|
||||
var/ic_blocked = FALSE
|
||||
/*
|
||||
if(client && !forced && config.ic_filter_regex && findtext(message, config.ic_filter_regex))
|
||||
//The filter doesn't act on the sanitized message, but the raw message.
|
||||
ic_blocked = TRUE
|
||||
*/
|
||||
if(sanitize)
|
||||
message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN))
|
||||
if(!message || message == "")
|
||||
return
|
||||
|
||||
if(ic_blocked)
|
||||
//The filter warning message shows the sanitized message though.
|
||||
to_chat(src, "<span class='warning'>That message contained a word prohibited in IC chat! Consider reviewing the server rules.\n<span replaceRegex='show_filtered_ic_chat'>\"[message]\"</span></span>")
|
||||
return
|
||||
|
||||
var/datum/saymode/saymode = SSradio.saymodes[talk_key]
|
||||
var/message_mode = get_message_mode(message)
|
||||
var/original_message = message
|
||||
|
||||
@@ -3,48 +3,48 @@
|
||||
#define POWER_RESTORATION_SEARCH_APC 2
|
||||
#define POWER_RESTORATION_APC_FOUND 3
|
||||
|
||||
/mob/living/silicon/ai/Life()
|
||||
if (stat == DEAD)
|
||||
/mob/living/silicon/ai/BiologicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
else //I'm not removing that shitton of tabs, unneeded as they are. -- Urist
|
||||
//I'm not removing that shitton of tabs, unneeded as they are. -- Urist
|
||||
//Being dead doesn't mean your temperature never changes
|
||||
|
||||
update_gravity(mob_has_gravity())
|
||||
update_gravity(mob_has_gravity())
|
||||
|
||||
handle_status_effects()
|
||||
handle_status_effects()
|
||||
|
||||
if(malfhack && malfhack.aidisabled)
|
||||
deltimer(malfhacking)
|
||||
// This proc handles cleanup of screen notifications and
|
||||
// messenging the client
|
||||
malfhacked(malfhack)
|
||||
if(malfhack && malfhack.aidisabled)
|
||||
deltimer(malfhacking)
|
||||
// This proc handles cleanup of screen notifications and
|
||||
// messenging the client
|
||||
malfhacked(malfhack)
|
||||
|
||||
if(isturf(loc) && (QDELETED(eyeobj) || !eyeobj.loc))
|
||||
view_core()
|
||||
if(isturf(loc) && (QDELETED(eyeobj) || !eyeobj.loc))
|
||||
view_core()
|
||||
|
||||
if(machine)
|
||||
machine.check_eye(src)
|
||||
if(machine)
|
||||
machine.check_eye(src)
|
||||
|
||||
// Handle power damage (oxy)
|
||||
if(aiRestorePowerRoutine)
|
||||
// Lost power
|
||||
adjustOxyLoss(1)
|
||||
else
|
||||
// Gain Power
|
||||
if(getOxyLoss())
|
||||
adjustOxyLoss(-1)
|
||||
// Handle power damage (oxy)
|
||||
if(aiRestorePowerRoutine)
|
||||
// Lost power
|
||||
adjustOxyLoss(1)
|
||||
else
|
||||
// Gain Power
|
||||
if(getOxyLoss())
|
||||
adjustOxyLoss(-1)
|
||||
|
||||
if(!lacks_power())
|
||||
var/area/home = get_area(src)
|
||||
if(home.powered(EQUIP))
|
||||
home.use_power(1000, EQUIP)
|
||||
if(!lacks_power())
|
||||
var/area/home = get_area(src)
|
||||
if(home.powered(EQUIP))
|
||||
home.use_power(1000, EQUIP)
|
||||
|
||||
if(aiRestorePowerRoutine >= POWER_RESTORATION_SEARCH_APC)
|
||||
ai_restore_power()
|
||||
return
|
||||
if(aiRestorePowerRoutine >= POWER_RESTORATION_SEARCH_APC)
|
||||
ai_restore_power()
|
||||
return
|
||||
|
||||
else if(!aiRestorePowerRoutine)
|
||||
ai_lose_power()
|
||||
else if(!aiRestorePowerRoutine)
|
||||
ai_lose_power()
|
||||
|
||||
/mob/living/silicon/ai/proc/lacks_power()
|
||||
var/turf/T = get_turf(src)
|
||||
@@ -151,7 +151,7 @@
|
||||
to_chat(src, "Receiving control information from APC.")
|
||||
sleep(2)
|
||||
apc_override = 1
|
||||
theAPC.ui_interact(src, state = GLOB.conscious_state)
|
||||
theAPC.ui_interact(src)
|
||||
apc_override = 0
|
||||
aiRestorePowerRoutine = POWER_RESTORATION_APC_FOUND
|
||||
sleep(50)
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/datum/robot_control
|
||||
var/mob/living/silicon/ai/owner
|
||||
|
||||
/datum/robot_control/New(mob/living/silicon/ai/new_owner)
|
||||
if(!istype(new_owner))
|
||||
qdel(src)
|
||||
owner = new_owner
|
||||
|
||||
/datum/robot_control/proc/is_interactable(mob/user)
|
||||
if(user != owner || owner.incapacitated())
|
||||
return FALSE
|
||||
if(owner.control_disabled)
|
||||
to_chat(user, "<span class='warning'>Wireless control is disabled.</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/robot_control/ui_status(mob/user)
|
||||
if(is_interactable(user))
|
||||
return ..()
|
||||
return UI_CLOSE
|
||||
|
||||
/datum/robot_control/ui_state(mob/user)
|
||||
return GLOB.always_state
|
||||
|
||||
/datum/robot_control/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "RemoteRobotControl")
|
||||
ui.open()
|
||||
|
||||
/datum/robot_control/ui_data(mob/user)
|
||||
if(!owner || user != owner)
|
||||
return
|
||||
var/list/data = list()
|
||||
var/turf/ai_current_turf = get_turf(owner)
|
||||
var/ai_zlevel = ai_current_turf.z
|
||||
|
||||
data["robots"] = list()
|
||||
for(var/mob/living/simple_animal/bot/B in GLOB.bots_list)
|
||||
if(B.z != ai_zlevel || B.remote_disabled) //Only non-emagged bots on the same Z-level are detected!
|
||||
continue
|
||||
var/list/robot_data = list(
|
||||
name = B.name,
|
||||
model = B.model,
|
||||
mode = B.get_mode(),
|
||||
hacked = B.hacked,
|
||||
location = get_area_name(B, TRUE),
|
||||
ref = REF(B)
|
||||
)
|
||||
data["robots"] += list(robot_data)
|
||||
|
||||
return data
|
||||
|
||||
/datum/robot_control/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
if(!is_interactable(usr))
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("callbot") //Command a bot to move to a selected location.
|
||||
if(owner.call_bot_cooldown > world.time)
|
||||
to_chat(usr, "<span class='danger'>Error: Your last call bot command is still processing, please wait for the bot to finish calculating a route.</span>")
|
||||
return
|
||||
owner.Bot = locate(params["ref"]) in GLOB.bots_list
|
||||
if(!owner.Bot || owner.Bot.remote_disabled || owner.control_disabled)
|
||||
return
|
||||
owner.waypoint_mode = TRUE
|
||||
to_chat(usr, "<span class='notice'>Set your waypoint by clicking on a valid location free of obstructions.</span>")
|
||||
. = TRUE
|
||||
if("interface") //Remotely connect to a bot!
|
||||
owner.Bot = locate(params["ref"]) in GLOB.bots_list
|
||||
if(!owner.Bot || owner.Bot.remote_disabled || owner.control_disabled)
|
||||
return
|
||||
owner.Bot.attack_ai(usr)
|
||||
. = TRUE
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
/mob/living/silicon/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE)
|
||||
/mob/living/silicon/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = SHARP_NONE)
|
||||
var/hit_percent = (100-blocked)/100
|
||||
if(!damage || (!forced && hit_percent <= 0))
|
||||
return 0
|
||||
|
||||
@@ -146,10 +146,11 @@
|
||||
if(possible_chassis[chassis])
|
||||
AddElement(/datum/element/mob_holder, chassis, 'icons/mob/pai_item_head.dmi', 'icons/mob/pai_item_rh.dmi', 'icons/mob/pai_item_lh.dmi', ITEM_SLOT_HEAD)
|
||||
|
||||
/mob/living/silicon/pai/Life()
|
||||
/mob/living/silicon/pai/BiologicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
if(hacking)
|
||||
process_hack()
|
||||
return ..()
|
||||
|
||||
/mob/living/silicon/pai/proc/process_hack()
|
||||
|
||||
@@ -282,17 +283,19 @@
|
||||
. = ..()
|
||||
. += "A personal AI in holochassis mode. Its master ID string seems to be [master]."
|
||||
|
||||
/mob/living/silicon/pai/Life()
|
||||
if(stat == DEAD)
|
||||
return
|
||||
/mob/living/silicon/pai/PhysicalLife()
|
||||
. = ..()
|
||||
if(cable)
|
||||
if(get_dist(src, cable) > 1)
|
||||
var/turf/T = get_turf(src.loc)
|
||||
T.visible_message("<span class='warning'>[src.cable] rapidly retracts back into its spool.</span>", "<span class='italics'>You hear a click and the sound of wire spooling rapidly.</span>")
|
||||
qdel(src.cable)
|
||||
cable = null
|
||||
|
||||
/mob/living/silicon/pai/BiologicalLife()
|
||||
if(!(. = ..()))
|
||||
return
|
||||
silent = max(silent - 1, 0)
|
||||
. = ..()
|
||||
|
||||
/mob/living/silicon/pai/updatehealth()
|
||||
if(status_flags & GODMODE)
|
||||
|
||||
@@ -28,8 +28,7 @@
|
||||
fold_in(force = 1)
|
||||
DefaultCombatKnockdown(200)
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/mob/living/silicon/pai/attack_hand(mob/living/carbon/human/user)
|
||||
/mob/living/silicon/pai/on_attack_hand(mob/living/carbon/human/user)
|
||||
switch(user.a_intent)
|
||||
if(INTENT_HELP)
|
||||
visible_message("<span class='notice'>[user] gently pats [src] on the head, eliciting an off-putting buzzing from its holographic field.</span>",
|
||||
|
||||
@@ -565,7 +565,6 @@
|
||||
dat += "Unable to obtain a reading.<br>"
|
||||
else
|
||||
var/datum/gas_mixture/environment = T.return_air()
|
||||
var/list/env_gases = environment.gases
|
||||
|
||||
var/pressure = environment.return_pressure()
|
||||
var/total_moles = environment.total_moles()
|
||||
@@ -573,11 +572,11 @@
|
||||
dat += "Air Pressure: [round(pressure,0.1)] kPa<br>"
|
||||
|
||||
if (total_moles)
|
||||
for(var/id in env_gases)
|
||||
var/gas_level = env_gases[id]/total_moles
|
||||
for(var/id in environment.get_gases())
|
||||
var/gas_level = environment.get_moles(id)/total_moles
|
||||
if(gas_level > 0.01)
|
||||
dat += "[GLOB.meta_gas_names[id]]: [round(gas_level*100)]%<br>"
|
||||
dat += "Temperature: [round(environment.temperature-T0C)]°C<br>"
|
||||
dat += "Temperature: [round(environment.return_temperature()-T0C)]°C<br>"
|
||||
dat += "<a href='byond://?src=[REF(src)];software=atmosensor;sub=0'>Refresh Reading</a> <br>"
|
||||
dat += "<br>"
|
||||
return dat
|
||||
|
||||
@@ -3,8 +3,14 @@
|
||||
emote_type = EMOTE_AUDIBLE
|
||||
|
||||
/datum/emote/sound/silicon
|
||||
mob_type_allowed_typecache = list(/mob/living/silicon)
|
||||
mob_type_allowed_typecache = list(/mob/living/silicon, /mob/living/carbon/human)
|
||||
emote_type = EMOTE_AUDIBLE
|
||||
var/unrestricted = FALSE
|
||||
|
||||
/datum/emote/sound/silicon/run_emote(mob/user, params)
|
||||
if(!unrestricted && !(issilicon(user) || isipcperson(user)))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/datum/emote/silicon/boop
|
||||
key = "boop"
|
||||
|
||||
@@ -2,11 +2,20 @@
|
||||
//as they handle all relevant stuff like adding it to the player's screen and such
|
||||
|
||||
//Returns the thing in our active hand (whatever is in our active module-slot, in this case)
|
||||
//This proc has been butchered into a proc that overrides borg item holding for the sake of making grippers work.
|
||||
//I'd be immensely thankful if anyone can figure out a less obtuse way of making grippers work without breaking functionality.
|
||||
/mob/living/silicon/robot/get_active_held_item()
|
||||
var/item = module_active
|
||||
if(istype(item, /obj/item/weapon/gripper))
|
||||
var/obj/item/weapon/gripper/G = item
|
||||
if(G.wrapped)
|
||||
if(G.wrapped.loc != G)
|
||||
G.wrapped = null
|
||||
return module_active
|
||||
item = G.wrapped
|
||||
return item
|
||||
return module_active
|
||||
|
||||
|
||||
|
||||
/mob/living/silicon/robot/proc/uneq_module(obj/item/O)
|
||||
if(!O)
|
||||
return 0
|
||||
@@ -70,15 +79,15 @@
|
||||
if(activated(O))
|
||||
to_chat(src, "<span class='warning'>That module is already activated.</span>")
|
||||
return
|
||||
if(!held_items[1])
|
||||
if(!held_items[1] && health >= -maxHealth*0.5)
|
||||
held_items[1] = O
|
||||
O.screen_loc = inv1.screen_loc
|
||||
. = TRUE
|
||||
else if(!held_items[2])
|
||||
else if(!held_items[2] && health >= 0)
|
||||
held_items[2] = O
|
||||
O.screen_loc = inv2.screen_loc
|
||||
. = TRUE
|
||||
else if(!held_items[3])
|
||||
else if(!held_items[3] && health >= maxHealth*0.5)
|
||||
held_items[3] = O
|
||||
O.screen_loc = inv3.screen_loc
|
||||
. = TRUE
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
/mob/living/silicon/robot/Life()
|
||||
set invisibility = 0
|
||||
if (src.notransform)
|
||||
/mob/living/silicon/robot/BiologicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
|
||||
..()
|
||||
adjustOxyLoss(-10) //we're a robot!
|
||||
handle_robot_hud_updates()
|
||||
handle_robot_cell()
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
wires = new /datum/wires/robot(src)
|
||||
AddElement(/datum/element/empprotection, EMP_PROTECT_WIRES)
|
||||
|
||||
RegisterSignal(src, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, .proc/charge)
|
||||
|
||||
robot_modules_background = new()
|
||||
robot_modules_background.icon_state = "block"
|
||||
robot_modules_background.layer = HUD_LAYER //Objects that appear on screen are on layer ABOVE_HUD_LAYER, UI should be just below it.
|
||||
@@ -287,50 +289,57 @@
|
||||
return FALSE
|
||||
return ISINRANGE(T1.x, T0.x - interaction_range, T0.x + interaction_range) && ISINRANGE(T1.y, T0.y - interaction_range, T0.y + interaction_range)
|
||||
|
||||
/mob/living/silicon/robot/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/weldingtool) && (user.a_intent != INTENT_HARM || user == src))
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
if (!getBruteLoss())
|
||||
to_chat(user, "<span class='warning'>[src] is already in good condition!</span>")
|
||||
/mob/living/silicon/robot/proc/attempt_welder_repair(obj/item/weldingtool/W, mob/user)
|
||||
if (!getBruteLoss())
|
||||
to_chat(user, "<span class='warning'>[src] is already in good condition!</span>")
|
||||
return
|
||||
if (!W.tool_start_check(user, amount=0)) //The welder has 1u of fuel consumed by it's afterattack, so we don't need to worry about taking any away.
|
||||
return
|
||||
user.DelayNextAction(CLICK_CD_MELEE)
|
||||
if(src == user)
|
||||
to_chat(user, "<span class='notice'>You start fixing yourself...</span>")
|
||||
if(!W.use_tool(src, user, 50))
|
||||
return
|
||||
if (!W.tool_start_check(user, amount=0)) //The welder has 1u of fuel consumed by it's afterattack, so we don't need to worry about taking any away.
|
||||
adjustBruteLoss(-10)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You start fixing [src]...</span>")
|
||||
if(!do_after(user, 30, target = src))
|
||||
return
|
||||
adjustBruteLoss(-30)
|
||||
updatehealth()
|
||||
add_fingerprint(user)
|
||||
visible_message("<span class='notice'>[user] has fixed some of the dents on [src].</span>")
|
||||
|
||||
/mob/living/silicon/robot/proc/attempt_cable_repair(obj/item/stack/cable_coil/W, mob/user)
|
||||
if (getFireLoss() > 0 || getToxLoss() > 0)
|
||||
user.DelayNextAction(CLICK_CD_MELEE)
|
||||
if(src == user)
|
||||
to_chat(user, "<span class='notice'>You start fixing yourself...</span>")
|
||||
if(!W.use_tool(src, user, 50))
|
||||
if(!W.use_tool(src, user, 50, 1, skill_gain_mult = TRIVIAL_USE_TOOL_MULT))
|
||||
to_chat(user, "<span class='warning'>You need more cable to repair [src]!</span>")
|
||||
return
|
||||
adjustBruteLoss(-10)
|
||||
adjustFireLoss(-10)
|
||||
adjustToxLoss(-10)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You start fixing [src]...</span>")
|
||||
if(!do_after(user, 30, target = src))
|
||||
if(!W.use_tool(src, user, 30, 1))
|
||||
to_chat(user, "<span class='warning'>You need more cable to repair [src]!</span>")
|
||||
return
|
||||
adjustBruteLoss(-30)
|
||||
updatehealth()
|
||||
add_fingerprint(user)
|
||||
visible_message("<span class='notice'>[user] has fixed some of the dents on [src].</span>")
|
||||
adjustFireLoss(-30)
|
||||
adjustToxLoss(-30)
|
||||
updatehealth()
|
||||
user.visible_message("[user] has fixed some of the burnt wires on [src].", "<span class='notice'>You fix some of the burnt wires on [src].</span>")
|
||||
else
|
||||
to_chat(user, "The wires seem fine, there's no need to fix them.")
|
||||
|
||||
/mob/living/silicon/robot/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/weldingtool) && (user.a_intent != INTENT_HARM || user == src))
|
||||
INVOKE_ASYNC(src, .proc/attempt_welder_repair, W, user)
|
||||
return
|
||||
|
||||
else if(istype(W, /obj/item/stack/cable_coil) && wiresexposed)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
if (getFireLoss() > 0 || getToxLoss() > 0)
|
||||
if(src == user)
|
||||
to_chat(user, "<span class='notice'>You start fixing yourself...</span>")
|
||||
if(!W.use_tool(src, user, 50, 1, max_level = JOB_SKILL_TRAINED))
|
||||
to_chat(user, "<span class='warning'>You need more cable to repair [src]!</span>")
|
||||
return
|
||||
adjustFireLoss(-10)
|
||||
adjustToxLoss(-10)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You start fixing [src]...</span>")
|
||||
if(!W.use_tool(src, user, 30, 1))
|
||||
to_chat(user, "<span class='warning'>You need more cable to repair [src]!</span>")
|
||||
return
|
||||
adjustFireLoss(-30)
|
||||
adjustToxLoss(-30)
|
||||
updatehealth()
|
||||
user.visible_message("[user] has fixed some of the burnt wires on [src].", "<span class='notice'>You fix some of the burnt wires on [src].</span>")
|
||||
else
|
||||
to_chat(user, "The wires seem fine, there's no need to fix them.")
|
||||
INVOKE_ASYNC(src, .proc/attempt_cable_repair, W, user)
|
||||
return
|
||||
|
||||
else if(istype(W, /obj/item/crowbar)) // crowbar means open or close the cover
|
||||
if(opened)
|
||||
@@ -1097,6 +1106,15 @@
|
||||
for(var/i in connected_ai.aicamera.stored)
|
||||
aicamera.stored[i] = TRUE
|
||||
|
||||
/mob/living/silicon/robot/proc/charge(datum/source, amount, repairs)
|
||||
if(module)
|
||||
var/coeff = amount * 0.005
|
||||
module.respawn_consumable(src, coeff)
|
||||
if(repairs)
|
||||
heal_bodypart_damage(repairs, repairs - 1)
|
||||
if(cell)
|
||||
cell.charge = min(cell.charge + amount, cell.maxcharge)
|
||||
|
||||
/mob/living/silicon/robot/proc/rest_style()
|
||||
set name = "Switch Rest Style"
|
||||
set category = "Robot Commands"
|
||||
|
||||
@@ -62,8 +62,7 @@
|
||||
|
||||
return
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/mob/living/silicon/robot/attack_hand(mob/living/carbon/human/user)
|
||||
/mob/living/silicon/robot/on_attack_hand(mob/living/carbon/human/user)
|
||||
add_fingerprint(user)
|
||||
if(opened && !wiresexposed && cell && !issilicon(user))
|
||||
cell.update_icon()
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
S.source = get_or_create_estorage(/datum/robot_energy_storage/wrapping_paper)
|
||||
|
||||
if(S && S.source)
|
||||
S.custom_materials = null
|
||||
S.set_custom_materials(null)
|
||||
S.is_cyborg = 1
|
||||
|
||||
if(I.loc != src)
|
||||
@@ -259,7 +259,7 @@
|
||||
var/prev_locked_down = R.locked_down
|
||||
sleep(1)
|
||||
flick("[cyborg_base_icon]_transform", R)
|
||||
R.notransform = TRUE
|
||||
R.mob_transforming = TRUE
|
||||
R.SetLockdown(1)
|
||||
R.anchored = TRUE
|
||||
sleep(1)
|
||||
@@ -270,7 +270,7 @@
|
||||
R.SetLockdown(0)
|
||||
R.setDir(SOUTH)
|
||||
R.anchored = FALSE
|
||||
R.notransform = FALSE
|
||||
R.mob_transforming = FALSE
|
||||
R.update_headlamp()
|
||||
R.notify_ai(NEW_MODULE)
|
||||
if(R.hud_used)
|
||||
@@ -324,7 +324,7 @@
|
||||
/obj/item/crowbar/cyborg,
|
||||
/obj/item/healthanalyzer,
|
||||
/obj/item/reagent_containers/borghypo,
|
||||
/obj/item/reagent_containers/glass/beaker/large,
|
||||
/obj/item/weapon/gripper/medical,
|
||||
/obj/item/reagent_containers/dropper,
|
||||
/obj/item/reagent_containers/syringe,
|
||||
/obj/item/surgical_drapes,
|
||||
@@ -334,13 +334,15 @@
|
||||
/obj/item/surgicaldrill,
|
||||
/obj/item/scalpel,
|
||||
/obj/item/circular_saw,
|
||||
/obj/item/bonesetter,
|
||||
/obj/item/roller/robo,
|
||||
/obj/item/borg/cyborghug/medical,
|
||||
/obj/item/stack/medical/gauze/cyborg,
|
||||
/obj/item/stack/medical/bone_gel/cyborg,
|
||||
/obj/item/organ_storage,
|
||||
/obj/item/borg/lollipop,
|
||||
/obj/item/sensor_device,
|
||||
/obj/item/twohanded/shockpaddles/cyborg)
|
||||
/obj/item/shockpaddles/cyborg)
|
||||
emag_modules = list(/obj/item/reagent_containers/borghypo/hacked)
|
||||
ratvar_modules = list(
|
||||
/obj/item/clockwork/slab/cyborg/medical,
|
||||
@@ -360,7 +362,7 @@
|
||||
"Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinamed"),
|
||||
"Eyebot" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "eyebotmed"),
|
||||
"Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavymed"),
|
||||
"Zoomba" = image(icon = 'icons/mob/robots.dmi', icon_state = "zoomba_med")
|
||||
"Drake" = image(icon = 'icons/mob/cyborg/drakemech.dmi', icon_state = "drakemedbox")
|
||||
)
|
||||
var/list/L = list("Medihound" = "medihound", "Medihound Dark" = "medihounddark", "Vale" = "valemed")
|
||||
for(var/a in L)
|
||||
@@ -376,8 +378,6 @@
|
||||
switch(med_borg_icon)
|
||||
if("Default")
|
||||
cyborg_base_icon = "medical"
|
||||
if("Zoomba")
|
||||
cyborg_base_icon = "zoomba_med"
|
||||
if("Droid")
|
||||
cyborg_base_icon = "medical"
|
||||
cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
|
||||
@@ -423,6 +423,13 @@
|
||||
moduleselect_icon = "medihound"
|
||||
moduleselect_alternate_icon = 'modular_citadel/icons/ui/screen_cyborg.dmi'
|
||||
dogborg = TRUE
|
||||
if("Drake")
|
||||
cyborg_base_icon = "drakemed"
|
||||
cyborg_icon_override = 'icons/mob/cyborg/drakemech.dmi'
|
||||
sleeper_overlay = "drakemedsleeper"
|
||||
moduleselect_icon = "medihound"
|
||||
moduleselect_alternate_icon = 'modular_citadel/icons/ui/screen_cyborg.dmi'
|
||||
dogborg = TRUE
|
||||
else
|
||||
return FALSE
|
||||
return ..()
|
||||
@@ -444,7 +451,7 @@
|
||||
/obj/item/t_scanner,
|
||||
/obj/item/analyzer,
|
||||
/obj/item/storage/part_replacer/cyborg,
|
||||
/obj/item/holosign_creator/atmos,
|
||||
/obj/item/holosign_creator/combifan,
|
||||
/obj/item/weapon/gripper,
|
||||
/obj/item/lightreplacer/cyborg,
|
||||
/obj/item/geiger_counter/cyborg,
|
||||
@@ -480,7 +487,7 @@
|
||||
"Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinaeng"),
|
||||
"Spider" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "spidereng"),
|
||||
"Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavyeng"),
|
||||
"Zoomba" = image(icon = 'icons/mob/robots.dmi', icon_state = "zoomba_engi")
|
||||
"Drake" = image(icon = 'icons/mob/cyborg/drakemech.dmi', icon_state = "drakeengbox")
|
||||
)
|
||||
var/list/L = list("Pup Dozer" = "pupdozer", "Vale" = "valeeng")
|
||||
for(var/a in L)
|
||||
@@ -496,8 +503,6 @@
|
||||
switch(engi_borg_icon)
|
||||
if("Default")
|
||||
cyborg_base_icon = "engineer"
|
||||
if("Zoomba")
|
||||
cyborg_base_icon = "zoomba_engi"
|
||||
if("Default - Treads")
|
||||
cyborg_base_icon = "engi-tread"
|
||||
special_light_key = "engineer"
|
||||
@@ -540,6 +545,11 @@
|
||||
cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
|
||||
sleeper_overlay = "alinasleeper"
|
||||
dogborg = TRUE
|
||||
if("Drake")
|
||||
cyborg_base_icon = "drakeeng"
|
||||
cyborg_icon_override = 'icons/mob/cyborg/drakemech.dmi'
|
||||
sleeper_overlay = "drakesecsleeper"
|
||||
dogborg = TRUE
|
||||
else
|
||||
return FALSE
|
||||
return ..()
|
||||
@@ -579,7 +589,7 @@
|
||||
"Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinasec"),
|
||||
"Spider" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "spidersec"),
|
||||
"Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavysec"),
|
||||
"Zoomba" = image(icon = 'icons/mob/robots.dmi', icon_state = "zoomba_sec")
|
||||
"Drake" = image(icon = 'icons/mob/cyborg/drakemech.dmi', icon_state = "drakesecbox")
|
||||
)
|
||||
var/list/L = list("K9" = "k9", "Vale" = "valesec", "K9 Dark" = "k9dark")
|
||||
for(var/a in L)
|
||||
@@ -595,8 +605,6 @@
|
||||
switch(sec_borg_icon)
|
||||
if("Default")
|
||||
cyborg_base_icon = "sec"
|
||||
if("Zoomba")
|
||||
cyborg_base_icon = "zoomba_sec"
|
||||
if("Default - Treads")
|
||||
cyborg_base_icon = "sec-tread"
|
||||
special_light_key = "sec"
|
||||
@@ -637,6 +645,11 @@
|
||||
sleeper_overlay = "valesecsleeper"
|
||||
cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
|
||||
dogborg = TRUE
|
||||
if("Drake")
|
||||
cyborg_base_icon = "drakesec"
|
||||
cyborg_icon_override = 'icons/mob/cyborg/drakemech.dmi'
|
||||
sleeper_overlay = "drakesecsleeper"
|
||||
dogborg = TRUE
|
||||
else
|
||||
return FALSE
|
||||
return ..()
|
||||
@@ -680,7 +693,8 @@
|
||||
var/static/list/peace_icons = sortList(list(
|
||||
"Default" = image(icon = 'icons/mob/robots.dmi', icon_state = "peace"),
|
||||
"Borgi" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "borgi"),
|
||||
"Spider" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "whitespider")
|
||||
"Spider" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "whitespider"),
|
||||
"Drake" = image(icon = 'icons/mob/cyborg/drakemech.dmi', icon_state = "drakepeacebox")
|
||||
))
|
||||
var/peace_borg_icon = show_radial_menu(R, R , peace_icons, custom_check = CALLBACK(src, .proc/check_menu, R), radius = 42, require_near = TRUE)
|
||||
switch(peace_borg_icon)
|
||||
@@ -696,6 +710,11 @@
|
||||
hat_offset = INFINITY
|
||||
cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
|
||||
has_snowflake_deadsprite = TRUE
|
||||
if("Drake")
|
||||
cyborg_base_icon = "drakepeace"
|
||||
cyborg_icon_override = 'icons/mob/cyborg/drakemech.dmi'
|
||||
sleeper_overlay = "drakepeacesleeper"
|
||||
dogborg = TRUE
|
||||
else
|
||||
return FALSE
|
||||
return ..()
|
||||
@@ -779,9 +798,8 @@
|
||||
/obj/item/toy/crayon/spraycan/borg,
|
||||
/obj/item/hand_labeler/borg,
|
||||
/obj/item/razor,
|
||||
/obj/item/rsf,
|
||||
/obj/item/instrument/violin,
|
||||
/obj/item/instrument/guitar,
|
||||
/obj/item/rsf/cyborg,
|
||||
/obj/item/instrument/piano_synth,
|
||||
/obj/item/reagent_containers/dropper,
|
||||
/obj/item/lighter,
|
||||
/obj/item/storage/bag/tray,
|
||||
@@ -836,7 +854,7 @@
|
||||
"(Janitor) Sleek" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "sleekjan"),
|
||||
"(Janitor) Can" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "canjan"),
|
||||
"(Janitor) Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavyjan"),
|
||||
"Zoomba" = image(icon = 'icons/mob/robots.dmi', icon_state = "zoomba_jani")
|
||||
"(Janitor) Drake" = image(icon = 'icons/mob/cyborg/drakemech.dmi', icon_state = "drakejanitbox")
|
||||
)
|
||||
var/list/L = list("(Service) DarkK9" = "k50", "(Service) Vale" = "valeserv", "(Service) ValeDark" = "valeservdark",
|
||||
"(Janitor) Scrubpuppy" = "scrubpup")
|
||||
@@ -851,8 +869,6 @@
|
||||
service_icons = sortList(service_icons)
|
||||
var/service_robot_icon = show_radial_menu(R, R , service_icons, custom_check = CALLBACK(src, .proc/check_menu, R), radius = 42, require_near = TRUE)
|
||||
switch(service_robot_icon)
|
||||
if("Zoomba")
|
||||
cyborg_base_icon = "zoomba_jani"
|
||||
if("(Service) Waitress")
|
||||
cyborg_base_icon = "service_f"
|
||||
special_light_key = "service"
|
||||
@@ -910,6 +926,11 @@
|
||||
cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
|
||||
sleeper_overlay = "jsleeper"
|
||||
dogborg = TRUE
|
||||
if("(Janitor) Drake")
|
||||
cyborg_base_icon = "drakejanit"
|
||||
cyborg_icon_override = 'icons/mob/cyborg/drakemech.dmi'
|
||||
sleeper_overlay = "drakesecsleeper"
|
||||
dogborg = TRUE
|
||||
else
|
||||
return FALSE
|
||||
return ..()
|
||||
@@ -923,7 +944,7 @@
|
||||
/obj/item/borg/sight/meson,
|
||||
/obj/item/storage/bag/ore/cyborg,
|
||||
/obj/item/pickaxe/drill/cyborg,
|
||||
/obj/item/twohanded/kinetic_crusher/cyborg,
|
||||
/obj/item/kinetic_crusher/cyborg,
|
||||
/obj/item/weldingtool/mini,
|
||||
/obj/item/storage/bag/sheetsnatcher/borg,
|
||||
/obj/item/t_scanner/adv_mining_scanner,
|
||||
@@ -956,7 +977,7 @@
|
||||
"Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinamin"),
|
||||
"Can" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "canmin"),
|
||||
"Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavymin"),
|
||||
"Zoomba" = image(icon = 'icons/mob/robots.dmi', icon_state = "zoomba_miner")
|
||||
"Drake" = image(icon = 'icons/mob/cyborg/drakemech.dmi', icon_state = "drakeminebox")
|
||||
)
|
||||
var/list/L = list("Blade" = "blade", "Vale" = "valemine")
|
||||
for(var/a in L)
|
||||
@@ -1000,8 +1021,11 @@
|
||||
cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
|
||||
sleeper_overlay = "valeminesleeper"
|
||||
dogborg = TRUE
|
||||
if("Zoomba")
|
||||
cyborg_base_icon = "zoomba_miner"
|
||||
if("Drake")
|
||||
cyborg_base_icon = "drakemine"
|
||||
cyborg_icon_override = 'icons/mob/cyborg/drakemech.dmi'
|
||||
sleeper_overlay = "drakeminesleeper"
|
||||
dogborg = TRUE
|
||||
else
|
||||
return FALSE
|
||||
return ..()
|
||||
@@ -1043,7 +1067,7 @@
|
||||
/obj/item/extinguisher/mini,
|
||||
/obj/item/crowbar/cyborg,
|
||||
/obj/item/reagent_containers/borghypo/syndicate,
|
||||
/obj/item/twohanded/shockpaddles/syndicate,
|
||||
/obj/item/shockpaddles/syndicate,
|
||||
/obj/item/healthanalyzer/advanced,
|
||||
/obj/item/surgical_drapes/advanced,
|
||||
/obj/item/retractor,
|
||||
@@ -1051,6 +1075,8 @@
|
||||
/obj/item/cautery,
|
||||
/obj/item/surgicaldrill,
|
||||
/obj/item/scalpel,
|
||||
/obj/item/bonesetter,
|
||||
/obj/item/stack/medical/bone_gel,
|
||||
/obj/item/melee/transforming/energy/sword/cyborg/saw,
|
||||
/obj/item/roller/robo,
|
||||
/obj/item/card/emag,
|
||||
|
||||
@@ -430,3 +430,6 @@
|
||||
|
||||
/mob/living/silicon/handle_high_gravity(gravity)
|
||||
return
|
||||
|
||||
/mob/living/silicon/rust_heretic_act()
|
||||
adjustBruteLoss(500)
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/silicon/attack_hand(mob/living/carbon/human/M)
|
||||
/mob/living/silicon/on_attack_hand(mob/living/carbon/human/M)
|
||||
. = ..()
|
||||
if(.) //the attack was blocked
|
||||
return
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
|
||||
/mob/living/simple_animal/attack_hand(mob/living/carbon/human/M)
|
||||
/mob/living/simple_animal/on_attack_hand(mob/living/carbon/human/M)
|
||||
. = ..()
|
||||
if(.) //the attack was blocked
|
||||
return
|
||||
|
||||
@@ -41,7 +41,11 @@
|
||||
to_chat(src, "<span class='notice'>Your astral projection is interrupted and your mind is sent back to your body with a shock!</span>")
|
||||
|
||||
/mob/living/simple_animal/astral/ClickOn(var/atom/A, var/params)
|
||||
..()
|
||||
. = ..()
|
||||
attempt_possess(A)
|
||||
|
||||
/mob/living/simple_animal/astral/proc/attempt_possess(atom/A)
|
||||
set waitfor = FALSE
|
||||
if(pseudo_death == FALSE)
|
||||
if(isliving(A))
|
||||
if(ishuman(A))
|
||||
@@ -62,7 +66,7 @@
|
||||
log_reagent("FERMICHEM: [src] has astrally transmitted [message] into [A]")
|
||||
|
||||
//Delete the mob if there's no mind! Pay that mob no mind.
|
||||
/mob/living/simple_animal/astral/Life()
|
||||
if(!mind)
|
||||
qdel(src)
|
||||
/mob/living/simple_animal/astral/PhysicalLife(seconds, times_fired)
|
||||
. = ..()
|
||||
if(!mind && !QDELETED(src))
|
||||
qdel(src)
|
||||
|
||||
@@ -102,6 +102,10 @@
|
||||
var/can_salute = TRUE
|
||||
var/salute_delay = 60 SECONDS
|
||||
|
||||
//emotes/speech stuff
|
||||
var/patrol_emote = "Engaging patrol mode."
|
||||
var/patrol_fail_emote = "Unable to start patrol."
|
||||
|
||||
/mob/living/simple_animal/bot/proc/get_mode()
|
||||
if(client) //Player bots do not have modes, thus the override. Also an easy way for PDA users/AI to know when a bot is a player.
|
||||
if(paicard)
|
||||
@@ -115,6 +119,19 @@
|
||||
else
|
||||
return "<span class='average'>[mode_name[mode]]</span>"
|
||||
|
||||
/**
|
||||
* Returns a status string about the bot's current status, if it's moving, manually controlled, or idle.
|
||||
*/
|
||||
/mob/living/simple_animal/bot/proc/get_mode_ui()
|
||||
if(client) //Player bots do not have modes, thus the override. Also an easy way for PDA users/AI to know when a bot is a player.
|
||||
return paicard ? "pAI Controlled" : "Autonomous"
|
||||
else if(!on)
|
||||
return "Inactive"
|
||||
else if(!mode)
|
||||
return "Idle"
|
||||
else
|
||||
return "[mode_name[mode]]"
|
||||
|
||||
/mob/living/simple_animal/bot/proc/turn_on()
|
||||
if(stat)
|
||||
return FALSE
|
||||
@@ -273,7 +290,7 @@
|
||||
return TRUE //Successful completion. Used to prevent child process() continuing if this one is ended early.
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/attack_hand(mob/living/carbon/human/H)
|
||||
/mob/living/simple_animal/bot/on_attack_hand(mob/living/carbon/human/H)
|
||||
if(H.a_intent == INTENT_HELP)
|
||||
interact(H)
|
||||
else
|
||||
@@ -318,7 +335,6 @@
|
||||
user.visible_message("<span class='notice'>[user] uses [W] to pull [paicard] out of [bot_name]!</span>","<span class='notice'>You pull [paicard] out of [bot_name] with [W].</span>")
|
||||
ejectpai(user)
|
||||
else
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM)
|
||||
if(health >= maxHealth)
|
||||
to_chat(user, "<span class='warning'>[src] does not need a repair!</span>")
|
||||
@@ -599,7 +615,7 @@ Pass a positive integer as an argument to override a bot's default speed.
|
||||
if(tries >= BOT_STEP_MAX_RETRIES) //Bot is trapped, so stop trying to patrol.
|
||||
auto_patrol = 0
|
||||
tries = 0
|
||||
speak("Unable to start patrol.")
|
||||
speak(patrol_fail_emote)
|
||||
|
||||
return
|
||||
|
||||
@@ -615,7 +631,7 @@ Pass a positive integer as an argument to override a bot's default speed.
|
||||
return
|
||||
mode = BOT_PATROL
|
||||
else // no patrol target, so need a new one
|
||||
speak("Engaging patrol mode.")
|
||||
speak(patrol_emote)
|
||||
find_patrol_target()
|
||||
tries++
|
||||
return
|
||||
@@ -1042,3 +1058,6 @@ Pass a positive integer as an argument to override a bot's default speed.
|
||||
if(I)
|
||||
I.icon_state = null
|
||||
path.Cut(1, 2)
|
||||
|
||||
/mob/living/silicon/rust_heretic_act()
|
||||
adjustBruteLoss(500)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user