Merge branch 'master' into cool-ipcs

This commit is contained in:
Timothy Teakettle
2020-09-16 05:09:02 +01:00
2723 changed files with 184768 additions and 215036 deletions
+36 -47
View File
@@ -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()
+5 -5
View File
@@ -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>")
+3 -1
View File
@@ -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)
+6
View File
@@ -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
+4 -5
View File
@@ -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)
+2 -6
View File
@@ -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()
+9 -11
View File
@@ -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)
+3 -12
View File
@@ -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
+112 -40
View File
@@ -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
+26 -59
View File
@@ -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
+41
View File
@@ -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)
+67 -13
View File
@@ -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>"
+58 -38
View File
@@ -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>&nbsp;</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 += "&nbsp;<A href='?src=[REF(src)];toggle_helmet=[SLOT_WEAR_SUIT]'>[hardsuit_head ? "Retract Helmet" : "Extend Helmet"]</A>"
dat += "</td></tr>"
dat += "<tr><td>&nbsp;&#8627;<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 += "&nbsp;<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 += "&nbsp;<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)))
+10 -21
View File
@@ -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")
+171 -248
View File
@@ -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"
+56 -55
View File
@@ -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())
+20 -24
View File
@@ -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
+4
View File
@@ -0,0 +1,4 @@
/mob/living/GetActionCooldownMod()
. = ..()
for(var/datum/status_effect/S in status_effects)
. *= S.action_cooldown_mod()
+17 -11
View File
@@ -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)
+1 -4
View File
@@ -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
+39 -3
View File
@@ -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))
+67 -40
View File
@@ -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))
+64 -50
View File
@@ -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(
+21 -9
View File
@@ -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
+41 -18
View File
@@ -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.")
+27 -37
View File
@@ -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.
+7 -1
View File
@@ -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
+11
View File
@@ -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
+32 -32
View File
@@ -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
+9 -6
View File
@@ -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)]&deg;C<br>"
dat += "Temperature: [round(environment.return_temperature()-T0C)]&deg;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()
+51 -33
View File
@@ -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