Merge remote-tracking branch 'origin/master' into TGUI-4

This commit is contained in:
Letter N
2020-07-30 14:43:52 +08:00
662 changed files with 13844 additions and 6845 deletions
+200
View File
@@ -0,0 +1,200 @@
/**
* CLICKDELAY HANDLING SYSTEM
* How this works is mobs can never do actions until their next_action is at or below world.time, but things can specify extra cooldown
* to check for either from the time of last_action or from the end of next_action.
*
* Clickdelay should always be checked via [CheckActionCooldown()], never manually!
*/
/mob
// CLICKDELAY AND RELATED
// Generic clickdelay - Hybrid time-since-last-attack and time-to-next-attack system.
// next_action is a hard cooldown, as Click()s will not pass unless it is passed.
// last_action is not a hard cooldown and different items can check for different delays.
/// Generic clickdelay variable. Marks down the last world.time we did something that should cause or impact generic clickdelay. This should be directly set or set using [DelayNextAction()]. This should only be checked using [CheckActionCooldown()].
var/last_action = 0
/**
* The difference between the above and this is this is set immediately before even the pre-attack begins to ensure clickdelay is respected.
* Then, it is flushed or discarded using [FlushLastAttack()] or [DiscardLastAttack()] respectively.
*/
var/last_action_immediate = 0
/// Generic clickdelay variable. Next world.time we should be able to do something that respects generic clickdelay. This should be set using [DelayNextAction()] This should only be checked using [CheckActionCooldown()].
var/next_action = 0
/// Ditto
var/next_action_immediate = 0
/// Default clickdelay for an UnarmedAttack() that successfully passes. Respects action_cooldown_mod.
var/unarmed_attack_speed = CLICK_CD_MELEE
/// Simple modification variable multiplied to next action modifier on adjust and on checking time since last action using [CheckActionCooldown()].
/// This should only be manually modified using multipliers.
var/action_cooldown_mod = 1
/// Simple modification variable added to amount on adjust and on checking time since last action using [CheckActionCooldown()].
/// This should only be manually modified via addition.
var/action_cooldown_adjust = 0
// Resisting - While resisting will give generic clickdelay, it is also on its own resist delay system. However, resisting does not check generic movedelay.
// Resist cooldown should only be set at the start of a resist chain - whether this is clicking an alert button, pressing or hotkeying the resist button, or moving to resist out of a locker.
/*
* Special clickdelay variable for resisting. Last time we did a special action like resisting. This should only be set using [MarkResistTime()].
* Use [CheckResistCooldown()] to check cooldowns, this should only be used for the resist action bar visual.
*/
var/last_resist = 0
/// How long we should wait before allowing another resist. This should only be manually modified using multipliers.
var/resist_cooldown = CLICK_CD_RESIST
/// Minimum world time for another resist. This should only be checked using [CheckResistCooldown()].
var/next_resist = 0
/**
* Applies a delay to next_action before we can do our next action.
*
* @params
* * amount - Amount to delay by
* * ignore_mod - ignores next action adjust and mult
* * considered_action - Defaults to TRUE - If TRUE, sets last_action to world.time.
* * immediate - defaults to TRUE - if TRUE, writes to cached/last_attack_immediate instead of last_attack. This ensures it can't collide with any delay checks in the actual attack.
* * flush - defaults to FALSE - Use this while using this proc outside of clickcode to ensure everything is set properly. This should never be set to TRUE if this is called from clickcode.
*/
/mob/proc/DelayNextAction(amount = 0, ignore_mod = FALSE, considered_action = TRUE, immediate = TRUE, flush = FALSE)
if(immediate)
if(considered_action)
last_action_immediate = world.time
next_action_immediate = max(next_action, world.time + (ignore_mod? amount : (amount * GetActionCooldownMod() + GetActionCooldownAdjust())))
else
if(considered_action)
last_action = world.time
next_action = max(next_action, world.time + (ignore_mod? amount : (amount * GetActionCooldownMod() + GetActionCooldownAdjust())))
if(flush)
FlushCurrentAction()
else
hud_used?.clickdelay?.mark_dirty()
/**
* Get estimated time of next attack.
*/
/mob/proc/EstimatedNextActionTime()
var/attack_speed = unarmed_attack_speed * GetActionCooldownMod() + GetActionCooldownAdjust()
var/obj/item/I = get_active_held_item()
if(I)
attack_speed = I.GetEstimatedAttackSpeed()
if(!I.clickdelay_mod_bypass)
attack_speed = attack_speed * GetActionCooldownMod() + GetActionCooldownAdjust()
return max(next_action, next_action_immediate, max(last_action, last_action_immediate) + attack_speed)
/**
* Sets our next action to. The difference is DelayNextAction cannot reduce next_action under any circumstances while this can.
*/
/mob/proc/SetNextAction(amount = 0, ignore_mod = FALSE, considered_action = TRUE, immediate = TRUE, flush = FALSE)
if(immediate)
if(considered_action)
last_action_immediate = world.time
next_action_immediate = world.time + (ignore_mod? amount : (amount * GetActionCooldownMod() + GetActionCooldownAdjust()))
else
if(considered_action)
last_action = world.time
next_action = world.time + (ignore_mod? amount : (amount * GetActionCooldownMod() + GetActionCooldownAdjust()))
if(flush)
FlushCurrentAction()
else
hud_used?.clickdelay?.mark_dirty()
/**
* Checks if we can do another action.
* Returns TRUE if we can and FALSE if we cannot.
*
* @params
* * cooldown - Time required since last action. Defaults to 0.5
* * from_next_action - Defaults to FALSE. Should we check from the tail end of next_action instead of last_action?
* * ignore_mod - Defaults to FALSE. Ignore all adjusts and multipliers. Do not use this unless you know what you are doing and have a good reason.
* * ignore_next_action - Defaults to FALSE. Ignore next_action and only care about cooldown param and everything else. Generally unused.
* * immediate - Defaults to FALSE. Checks last action using immediate, used on the head end of an attack. This is to prevent colliding attacks in case of sleep. Not that you should sleep() in an attack but.. y'know.
*/
/mob/proc/CheckActionCooldown(cooldown = 0.5, from_next_action = FALSE, ignore_mod = FALSE, ignore_next_action = FALSE, immediate = FALSE)
return (ignore_next_action || (world.time >= (immediate? next_action_immediate : next_action))) && \
(world.time >= ((from_next_action? (immediate? next_action_immediate : next_action) : (immediate? last_action_immediate : last_action)) + max(0, ignore_mod? cooldown : (cooldown * GetActionCooldownMod() + GetActionCooldownAdjust()))))
/**
* Gets action_cooldown_mod.
*/
/mob/proc/GetActionCooldownMod()
return action_cooldown_mod
/**
* Gets action_cooldown_adjust
*/
/mob/proc/GetActionCooldownAdjust()
return action_cooldown_adjust
/**
* Flushes last_action and next_action
*/
/mob/proc/FlushCurrentAction()
last_action = last_action_immediate
next_action = next_action_immediate
hud_used?.clickdelay?.mark_dirty()
/**
* Discards last_action and next_action
*/
/mob/proc/DiscardCurrentAction()
last_action_immediate = last_action
next_action_immediate = next_action
hud_used?.clickdelay?.mark_dirty()
/**
* Checks if we can resist again.
*/
/mob/proc/CheckResistCooldown()
return (world.time >= next_resist)
/**
* Mark the last resist as now.
*
* @params
* * extra_cooldown - Extra cooldown to apply to next_resist. Defaults to this mob's resist_cooldown.
* * override - Defaults to FALSE - if TRUE, extra_cooldown will replace the old next_resist even if the old is longer.
*/
/mob/proc/MarkResistTime(extra_cooldown = resist_cooldown, override = FALSE)
last_resist = world.time
next_resist = override? (world.time + extra_cooldown) : max(next_resist, world.time + extra_cooldown)
hud_used?.resistdelay?.mark_dirty()
/atom
// Standard clickdelay variables
// These 3 are all handled at base of atom/attack_hand so uh.. yeah. Make sure that's called.
/// Amount of time to check for from a mob's last attack to allow an attack_hand().
var/attack_hand_speed = CLICK_CD_MELEE
/// Amount of time to hard stagger (no clicking at all) the mob post attack_hand(). Lower = better
var/attack_hand_unwieldlyness = 0
/// Should we set last action for attack hand? This implies that attack_hands to this atom should flush to clickdelay buffers instead of discarding.
var/attack_hand_is_action = FALSE
/obj/item
// Standard clickdelay variables
/// Amount of time to check for from a mob's last attack, checked before an attack happens. Lower = faster attacks
var/attack_speed = CLICK_CD_MELEE
/// Amount of time to hard-stagger (no clicking at all) the mob when attacking. Lower = better
var/attack_unwieldlyness = 0
/// This item bypasses any click delay mods
var/clickdelay_mod_bypass = FALSE
/// This item checks clickdelay from a user's delayed next action variable rather than the last time they attacked.
var/clickdelay_from_next_action = FALSE
/// This item ignores next action delays.
var/clickdelay_ignores_next_action = FALSE
/**
* Checks if a user's clickdelay is met for a standard attack, this is called before an attack happens.
*/
/obj/item/proc/CheckAttackCooldown(mob/user, atom/target)
return user.CheckActionCooldown(attack_speed, clickdelay_from_next_action, clickdelay_mod_bypass, clickdelay_ignores_next_action)
/**
* Called after a successful attack to set a mob's clickdelay.
*/
/obj/item/proc/ApplyAttackCooldown(mob/user, atom/target, attackchain_flags)
user.DelayNextAction(attack_unwieldlyness, clickdelay_mod_bypass, !(attackchain_flags & ATTACK_IGNORE_ACTION))
/**
* Get estimated time that a user has to not attack for to use us
*/
/obj/item/proc/GetEstimatedAttackSpeed()
return attack_speed
@@ -558,12 +558,25 @@
client.prefs.random_character()
client.prefs.real_name = client.prefs.pref_species.random_name(gender,1)
client.prefs.copy_to(H)
var/cur_scar_index = client.prefs.scars_index
if(client.prefs.persistent_scars && client.prefs.scars_list["[cur_scar_index]"])
var/scar_string = client.prefs.scars_list["[cur_scar_index]"]
var/valid_scars = ""
for(var/scar_line in splittext(scar_string, ";"))
if(H.load_scar(scar_line))
valid_scars += "[scar_line];"
client.prefs.scars_list["[cur_scar_index]"] = valid_scars
client.prefs.save_character()
client.prefs.copy_to(H)
H.dna.update_dna_identity()
if(mind)
if(transfer_after)
mind.late_joiner = TRUE
mind.active = 0 //we wish to transfer the key manually
mind.transfer_to(H) //won't transfer key since the mind is not active
mind.original_character = H
H.name = real_name
-8
View File
@@ -5,13 +5,11 @@
/mob/proc/get_active_held_item()
return get_item_for_held_index(active_hand_index)
//Finds the opposite limb for the active one (eg: upper left arm will find the item in upper right arm)
//So we're treating each "pair" of limbs as a team, so "both" refers to them
/mob/proc/get_inactive_held_item()
return get_item_for_held_index(get_inactive_hand_index())
//Finds the opposite index for the active one (eg: upper left arm will find the item in upper right arm)
//So we're treating each "pair" of limbs as a team, so "both" refers to them
/mob/proc/get_inactive_hand_index()
@@ -24,12 +22,9 @@
other_hand = 0
return other_hand
/mob/proc/get_item_for_held_index(i)
if(i > 0 && i <= held_items.len)
return held_items[i]
return FALSE
//Odd = left. Even = right
/mob/proc/held_index_to_dir(i)
@@ -37,17 +32,14 @@
return "r"
return "l"
//Check we have an organ for this hand slot (Dismemberment), Only relevant for humans
/mob/proc/has_hand_for_held_index(i)
return TRUE
//Check we have an organ for our active hand slot (Dismemberment),Only relevant for humans
/mob/proc/has_active_hand()
return has_hand_for_held_index(active_hand_index)
//Finds the first available (null) index OR all available (null) indexes in held_items based on a side.
//Lefts: 1, 3, 5, 7...
//Rights:2, 4, 6, 8...
+38 -46
View File
@@ -5,44 +5,42 @@
#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)
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 +53,27 @@
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_EXCESS to BLOOD_VOLUME_MAX_LETHAL)
if(prob(15))
to_chat(src, "<span class='userdanger'>Blood starts to tear your skin apart. You're going to burst!</span>")
gib()
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 +90,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 +118,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
+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)
+4 -2
View File
@@ -102,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
@@ -331,6 +331,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)
@@ -389,7 +391,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)
@@ -45,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
@@ -74,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,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
@@ -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, act_intent = user.a_intent, unarmed_attack_flags)
/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
+93 -30
View File
@@ -88,11 +88,32 @@
for(var/datum/surgery/S in surgeries)
if(S.next_step(user,user.a_intent))
return 1
if(!all_wounds || !(user.a_intent == INTENT_HELP || user == src))
return ..()
// The following priority/nonpriority searching is so that if we have two wounds on a limb that use the same item for treatment (gauze can bandage cuts AND splint broken bones),
// we prefer whichever wound is not already treated (ignore the splinted broken bone for the open cut). If there's no priority wounds that this can treat, go through the
// non-priority ones randomly.
var/list/nonpriority_wounds = list()
for(var/datum/wound/W in shuffle(all_wounds))
if(!W.treat_priority)
nonpriority_wounds += W
else if(W.treat_priority && W.try_treating(I, user))
return 1
for(var/datum/wound/W in shuffle(nonpriority_wounds))
if(W.try_treating(I, user))
return 1
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))
@@ -102,18 +123,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)
@@ -153,6 +174,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
@@ -196,12 +218,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))
@@ -292,14 +320,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))
@@ -313,39 +338,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)
@@ -390,7 +402,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
@@ -403,7 +415,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)
@@ -892,6 +904,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()
@@ -982,6 +997,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)
@@ -1170,3 +1189,47 @@
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_CUT 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_BONE, WOUND_LIST_CUT, 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/S = new
var/obj/item/bodypart/BP = 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(WOUND_LIST_BONE + WOUND_LIST_CUT + WOUND_LIST_BURN)
var/datum/wound/W = new wound_type
S.generate(BP, W)
S.fake = TRUE
QDEL_NULL(W)
@@ -69,7 +69,7 @@
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)
@@ -79,7 +79,7 @@
send_item_attack_message(I, user, affecting.name, 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,8 +111,7 @@
/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, act_intent, unarmed_attack_flags)
/mob/living/carbon/on_attack_hand(mob/living/carbon/human/user, act_intent, unarmed_attack_flags)
. = ..()
if(.) //was the attack blocked?
return
@@ -132,6 +131,9 @@
if(S.next_step(user, act_intent))
return TRUE
for(var/datum/wound/W in all_wounds)
if(W.try_handling(user))
return 1
/mob/living/carbon/attack_paw(mob/living/carbon/monkey/M)
@@ -148,15 +150,13 @@
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
/mob/living/carbon/attack_slime(mob/living/simple_animal/slime/M)
. = ..()
@@ -467,3 +467,8 @@
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
@@ -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.
@@ -65,6 +65,11 @@
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
@@ -72,3 +77,4 @@
/// Timer id of any transformation
var/transformation_timer
+18 -9
View File
@@ -1,6 +1,6 @@
/mob/living/carbon/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = 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 = FALSE)
SEND_SIGNAL(src, COMSIG_MOB_APPLY_DAMGE, damage, damagetype, def_zone)
var/hit_percent = (100-blocked)/100
if(!forced && hit_percent <= 0)
@@ -21,13 +21,13 @@
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)
@@ -202,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 = FALSE)
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
@@ -235,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)
@@ -253,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,3 +265,12 @@
if(update)
update_damage_overlays()
update_stamina()
///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
+40
View File
@@ -44,6 +44,8 @@
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/datum/wound/W in BP.wounds)
msg += "[W.get_examine_description(user)]\n"
for(var/X in disabled)
var/obj/item/bodypart/BP = X
@@ -99,6 +101,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='smallnotice'>[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 +153,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 = FALSE)
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, spread_damage)
// 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, spread_damage)
@@ -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)
+55 -14
View File
@@ -163,16 +163,18 @@
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/datum/wound/W in BP.wounds)
msg += "[W.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 +248,40 @@
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"
else
msg += "<B>[t_He] [t_is] bleeding!</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/bleed_text = "<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]"
bleed_text += "!</B>\n"
msg += bleed_text
if(reagents.has_reagent(/datum/reagent/teslium))
msg += "[t_He] [t_is] emitting a gentle blue glow!\n"
@@ -331,6 +357,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='smallnotice'>[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>"
+24 -4
View File
@@ -170,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>"
@@ -294,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
@@ -390,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)
@@ -735,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
..()
@@ -1057,10 +1066,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
@@ -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)
@@ -93,22 +106,23 @@
return dna.species.spec_attacked_by(I, user, affecting, a_intent, src, attackchain_flags, damage_multiplier)
/mob/living/carbon/human/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
. = ..(user, TRUE)
if(.)
return
var/hulk_verb_continous = "smashes"
var/hulk_verb_simple = "smash"
if(prob(50))
hulk_verb_continous = "pummels"
hulk_verb_simple = "pummel"
playsound(loc, user.dna.species.attack_sound, 25, 1, -1)
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)
return 1
if(user.a_intent == INTENT_HARM)
. = ..(user, TRUE)
if(.)
return
var/hulk_verb_continous = "smashes"
var/hulk_verb_simple = "smash"
if(prob(50))
hulk_verb_continous = "pummels"
hulk_verb_simple = "pummel"
playsound(loc, user.dna.species.attack_sound, 25, 1, -1)
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>")
apply_damage(15, BRUTE, wound_bonus=10)
return 1
/mob/living/carbon/human/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
/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
@@ -117,6 +131,9 @@
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)
@@ -216,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
@@ -235,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)
@@ -613,6 +631,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>")
@@ -622,8 +654,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"
@@ -716,6 +765,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)
@@ -51,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
@@ -103,7 +102,7 @@
"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, final_block_chance, list/block_return, parry_efficiency, parry_time)
/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 ..()
@@ -111,7 +110,7 @@
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, UNARMED_ATTACK_PARRY)
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,22 @@
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()
if(!all_scars)
return
var/scars = ""
for(var/i in all_scars)
var/datum/scar/S = i
scars += "[S.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) != 4)
return // invalid, should delete
var/obj/item/bodypart/BP = get_bodypart("[scar_data[SCAR_SAVE_ZONE]]")
var/datum/scar/S = new
return S.load(BP, scar_data[SCAR_SAVE_DESC], scar_data[SCAR_SAVE_PRECISE_LOCATION], text2num(scar_data[SCAR_SAVE_SEVERITY]))
@@ -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")
+59 -27
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
@@ -73,7 +73,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(CAN_SCAR) //by default they can scar unless set to something else
// generic traits tied to having the species
var/list/inherent_traits = list()
var/inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID
@@ -105,6 +105,10 @@ 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
@@ -113,14 +117,12 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
// PROCS //
///////////
/datum/species/New()
if(!limbs_id) //if we havent set a limbs id to use, just use our own id
limbs_id = id
..()
/proc/generate_selectable_species(clear = FALSE)
if(clear)
GLOB.roundstart_races = list()
@@ -854,10 +856,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
@@ -1031,7 +1033,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.
*/
@@ -1062,7 +1063,8 @@ 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
@@ -1285,9 +1287,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))
@@ -1446,7 +1448,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, unarmed_attack_flags = NONE)
/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
@@ -1458,7 +1460,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
target_message = "<span class='warning'>[target] blocks your attack!</span>")
return FALSE
if(!(unarmed_attack_flags & UNARMED_ATTACK_PARRY))
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
@@ -1500,7 +1502,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
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(unarmed_attack_flags & UNARMED_ATTACK_PARRY)
if(attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)
miss_chance = 0
else
if(user.dna.species.punchdamagelow)
@@ -1687,7 +1689,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, act_intent, unarmed_attack_flags)
/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)
@@ -1707,7 +1709,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
grab(M, H, attacker_style)
if("harm")
harm(M, H, attacker_style, unarmed_attack_flags)
harm(M, H, attacker_style, attackchain_flags)
if("disarm")
disarm(M, H, attacker_style)
@@ -1717,7 +1719,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())
@@ -1734,9 +1736,15 @@ 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, totitemdamage)
@@ -1822,6 +1830,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
@@ -1951,8 +1962,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
append_message += ", causing them to drop [target_held_item]"
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, spread_damage = 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 = FALSE)
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)
@@ -1979,7 +1990,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
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)
@@ -1990,7 +2001,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)
@@ -2220,12 +2231,14 @@ 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
//////////////
@@ -2243,11 +2256,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,CAN_SCAR)
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,6 +11,7 @@
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)
. = ..()
@@ -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,CAN_SCAR)
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,CAN_SCAR)
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'
@@ -17,32 +17,6 @@
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)
/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
tail_type = "mam_tail"
wagging_type = "mam_waggingtail"
species_type = "insect"
@@ -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"
@@ -3,7 +3,7 @@
id = "dullahan"
default_color = "FFFFFF"
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS)
inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH)
inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH,CAN_SCAR)
mutant_bodyparts = list("tail_human" = "None", "ears" = "None", "deco_wings" = "None")
use_skintones = USE_SKINTONES_GRAYSCALE_CUSTOM
mutant_brain = /obj/item/organ/brain/dullahan
@@ -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,CAN_SCAR)
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.
@@ -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,CAN_SCAR)
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG
mutanttongue = /obj/item/organ/tongue/fly
mutantliver = /obj/item/organ/liver/fly
@@ -12,6 +12,7 @@
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))
@@ -3,9 +3,9 @@
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,CAN_SCAR)
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 +14,6 @@
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)
/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
tail_type = "mam_tail"
wagging_type = "mam_waggingtail"
species_type = "furry"
@@ -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
@@ -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,CAN_SCAR)
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()
@@ -21,6 +21,7 @@
exotic_bloodtype = "HF"
exotic_blood_color = BLOOD_COLOR_OIL
species_type = "robotic"
var/datum/action/innate/monitor_change/screen
@@ -7,7 +7,7 @@
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,WINGCOLOR)
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)
@@ -25,6 +25,10 @@
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"
@@ -128,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///////////////////////////////////////////////////////////////////
@@ -449,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.
@@ -4,7 +4,7 @@
id = "lizard"
say_mod = "hisses"
default_color = "00FF00"
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS,HORNCOLOR,WINGCOLOR)
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS,HORNCOLOR,WINGCOLOR,CAN_SCAR)
mutant_bodyparts = list("tail_lizard", "snout", "spines", "horns", "frills", "body_markings", "legs", "taur", "deco_wings")
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_REPTILE
mutanttongue = /obj/item/organ/tongue/lizard
@@ -27,6 +27,10 @@
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)
@@ -38,41 +42,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
*/
@@ -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,CAN_SCAR)
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
@@ -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
@@ -3,7 +3,7 @@
name = "Anthromorphic Plant"
id = "pod"
default_color = "59CE00"
species_traits = list(MUTCOLORS,EYECOLOR)
species_traits = list(MUTCOLORS,EYECOLOR,CAN_SCAR)
attack_verb = "slash"
attack_sound = 'sound/weapons/slice.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
@@ -19,6 +19,8 @@
var/light_burnheal = -1
var/light_bruteheal = -1
species_type = "plant"
/datum/species/pod/on_species_gain(mob/living/carbon/C, datum/species/old_species)
. = ..()
C.faction |= "plants"
@@ -64,36 +66,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)
inherent_traits = list(TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_NOBREATH)
species_traits = list(NOBLOOD,NOEYES,CAN_SCAR)
inherent_traits = list(TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_NOBREATH,CAN_SCAR)
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)
@@ -15,6 +15,8 @@
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_RESISTCOLD)
@@ -20,33 +20,6 @@
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
@@ -5,7 +5,7 @@
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,DRINKSBLOOD)
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,19 @@
/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,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,CAN_SCAR)
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"
@@ -33,7 +34,7 @@
limbs_id = "zombie"
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 +42,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 = FALSE)
. = ..()
if(.)
regen_cooldown = world.time + REGENERATION_DELAY
@@ -62,6 +62,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/W = i
if(prob(4-W.severity))
W.remove_wound()
if(!C.InCritical() && prob(4))
playsound(C, pick(spooks), 50, TRUE, 10)
@@ -85,6 +89,11 @@
infection = new()
infection.Insert(C)
//make their bodyparts stamina-resistant
var/incoming_stam_mult = 0.7
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
+14
View File
@@ -1,6 +1,8 @@
/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 . is false, we are dead.
@@ -404,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)
@@ -416,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)
@@ -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))
@@ -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,6 +26,8 @@
//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)
+4
View File
@@ -0,0 +1,4 @@
/mob/living/GetActionCooldownMod()
. = ..()
for(var/datum/status_effect/S in status_effects)
. *= S.action_cooldown_mod()
+2 -2
View File
@@ -14,7 +14,7 @@
*
* Returns TRUE if damage applied
*/
/mob/living/proc/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE)
/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 = FALSE)
var/hit_percent = (100-blocked)/100
if(!damage || (hit_percent <= 0))
return 0
@@ -245,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 = FALSE)
adjustBruteLoss(brute, FALSE) //zero as argument for no instant health update
adjustFireLoss(burn, FALSE)
adjustStaminaLoss(stamina, FALSE)
+2 -2
View File
@@ -226,7 +226,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 +244,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
+7 -2
View File
@@ -3,7 +3,7 @@
* Splits off into PhysicalLife() and BiologicalLife(). Override those instead of this.
*/
/mob/living/proc/Life(seconds, times_fired)
set waitfor = FALSE // yeah hey we're kind of on a subsystem, no sleeping will be tolerated here!
SHOULD_NOT_SLEEP(TRUE)
if(mob_transforming)
return
@@ -45,6 +45,8 @@
/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.
handle_wounds()
// Everything after this shouldn't process while dead (as of the time of writing)
if(stat == DEAD)
return FALSE
@@ -80,7 +82,7 @@
handle_diginvis() //AI becomes unable to see mob
if((movement_type & FLYING) && !(movement_type & FLOATING)) //TODO: Better floating
float(on = TRUE)
INVOKE_ASYNC(src, /atom/movable.proc/float, TRUE)
if(!loc)
return FALSE
@@ -109,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)
+13 -12
View File
@@ -273,7 +273,7 @@
return
stop_pulling()
changeNext_move(CLICK_CD_GRABBING)
DelayNextAction(CLICK_CD_GRABBING)
if(AM.pulledby)
if(!supress_message)
@@ -636,7 +636,7 @@
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
..()
@@ -676,7 +676,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 +687,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 +703,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 +732,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 +803,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)
@@ -10,8 +10,7 @@
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/ACTIVE_BLOCK_START(obj/item/I)
@@ -97,7 +96,7 @@
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()
@@ -59,14 +59,14 @@
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.
@@ -121,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
@@ -160,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.
@@ -256,7 +256,7 @@
var/datum/block_parry_data/data = get_parry_data()
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]" : ""]!</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)
@@ -277,7 +277,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)
@@ -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.")
+15 -7
View File
@@ -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
@@ -138,7 +139,7 @@
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)
apply_damage(total_damage, dtype, impacting_zone, armor, sharpness=I.sharpness)
if(I.thrownby)
log_combat(I.thrownby, src, "threw and hit", I)
else
@@ -215,8 +216,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
@@ -270,10 +271,10 @@
user.set_pull_offsets(src, grab_state)
return 1
/mob/living/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
/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) && act_intent != INTENT_HELP && (mob_run_block(user, 0, user.name, ATTACK_TYPE_UNARMED | ATTACK_TYPE_MELEE | ((unarmed_attack_flags & UNARMED_ATTACK_PARRY)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE), 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,
@@ -323,6 +324,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,
@@ -338,7 +342,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,
@@ -347,6 +351,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>")
@@ -368,6 +375,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.
@@ -1,5 +1,5 @@
/mob/living/silicon/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = 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 = FALSE)
var/hit_percent = (100-blocked)/100
if(!damage || (!forced && hit_percent <= 0))
return 0
@@ -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>",
@@ -16,8 +16,6 @@
return item
return module_active
/mob/living/silicon/robot/proc/uneq_module(obj/item/O)
if(!O)
return 0
@@ -289,7 +289,7 @@
/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)
user.DelayNextAction(CLICK_CD_MELEE)
if (!getBruteLoss())
to_chat(user, "<span class='warning'>[src] is already in good condition!</span>")
return
@@ -311,7 +311,7 @@
return
else if(istype(W, /obj/item/stack/cable_coil) && wiresexposed)
user.changeNext_move(CLICK_CD_MELEE)
user.DelayNextAction(CLICK_CD_MELEE)
if (getFireLoss() > 0 || getToxLoss() > 0)
if(src == user)
to_chat(user, "<span class='notice'>You start fixing yourself...</span>")
@@ -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()
@@ -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,9 +334,11 @@
/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,
@@ -359,8 +361,7 @@
"Sleek" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "sleekmed"),
"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")
"Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavymed")
)
var/list/L = list("Medihound" = "medihound", "Medihound Dark" = "medihounddark", "Vale" = "valemed")
for(var/a in L)
@@ -376,8 +377,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'
@@ -479,8 +478,7 @@
"Can" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "caneng"),
"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")
"Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavyeng")
)
var/list/L = list("Pup Dozer" = "pupdozer", "Vale" = "valeeng")
for(var/a in L)
@@ -496,8 +494,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"
@@ -578,8 +574,7 @@
"Can" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "cansec"),
"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")
"Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavysec")
)
var/list/L = list("K9" = "k9", "Vale" = "valesec", "K9 Dark" = "k9dark")
for(var/a in L)
@@ -595,8 +590,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"
@@ -834,8 +827,7 @@
"(Janitor) Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinajan"),
"(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) Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavyjan")
)
var/list/L = list("(Service) DarkK9" = "k50", "(Service) Vale" = "valeserv", "(Service) ValeDark" = "valeservdark",
"(Janitor) Scrubpuppy" = "scrubpup")
@@ -850,8 +842,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"
@@ -954,8 +944,7 @@
"Sleek" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "sleekmin"),
"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")
"Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavymin")
)
var/list/L = list("Blade" = "blade", "Vale" = "valemine")
for(var/a in L)
@@ -999,8 +988,6 @@
cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
sleeper_overlay = "valeminesleeper"
dogborg = TRUE
if("Zoomba")
cyborg_base_icon = "zoomba_miner"
else
return FALSE
return ..()
@@ -1050,6 +1037,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,
@@ -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))
@@ -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)
@@ -286,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
@@ -331,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>")
@@ -612,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
@@ -628,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
@@ -177,7 +177,7 @@ Auto Patrol[]"},
target = H
mode = BOT_HUNT
/mob/living/simple_animal/bot/ed209/attack_hand(mob/living/carbon/human/H)
/mob/living/simple_animal/bot/ed209/on_attack_hand(mob/living/carbon/human/H)
if(H.a_intent == INTENT_HARM)
retaliate(H)
return ..()
@@ -532,8 +532,10 @@ Auto Patrol[]"},
/mob/living/simple_animal/bot/ed209/RangedAttack(atom/A)
if(!on)
return
return ..()
shootAt(A)
DelayNextAction()
return TRUE
/mob/living/simple_animal/bot/ed209/proc/stun_attack(mob/living/carbon/C)
playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
@@ -112,7 +112,7 @@ Maintenance panel panel is [open ? "opened" : "closed"]"},
target = H
mode = BOT_HUNT
/mob/living/simple_animal/bot/honkbot/attack_hand(mob/living/carbon/human/H)
/mob/living/simple_animal/bot/honkbot/on_attack_hand(mob/living/carbon/human/H)
if(H.a_intent == INTENT_HARM)
retaliate(H)
addtimer(CALLBACK(src, .proc/react_buzz), 5)
@@ -604,7 +604,7 @@
/mob/living/simple_animal/bot/medbot/proc/get_healchem_toxin(mob/M)
return HAS_TRAIT(M, TRAIT_TOXINLOVER)? treatment_tox_toxlover : treatment_tox
/mob/living/simple_animal/bot/medbot/attack_hand(mob/living/carbon/human/H)
/mob/living/simple_animal/bot/medbot/on_attack_hand(mob/living/carbon/human/H)
if(H.a_intent == INTENT_DISARM && mode != BOT_TIPPED)
H.visible_message("<span class='danger'>[H] begins tipping over [src].</span>", "<span class='warning'>You begin tipping over [src]...</span>")
@@ -33,6 +33,20 @@
var/check_records = TRUE //Does it check security records?
var/arrest_type = FALSE //If true, don't handcuff
var/obj/item/clothing/head/bot_accessory
var/datum/beepsky_fashion/stored_fashion
//emotes (BOT is replaced with bot name, CRIMINAL with criminal name, THREAT_LEVEL with threat level)
var/death_emote = "BOT blows apart!"
var/capture_one = "BOT is trying to put zipties on CRIMINAL!"
var/capture_two = "BOT is trying to put zipties on you!"
var/infraction = "Level THREAT_LEVEL infraction alert!"
var/taunt = "<b>BOT</b> points at CRIMINAL!"
var/attack_one = "BOT has stunned CRIMINAL!"
var/attack_two = "BOT has stunned you!"
var/list/arrest_texts = list("Detaining", "Arresting")
var/arrest_emote = "ARREST_TYPE level THREAT_LEVEL scumbag CRIMINAL in LOCATION."
/mob/living/simple_animal/bot/secbot/beepsky
name = "Officer Beep O'sky"
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
@@ -49,6 +63,103 @@
resize = 0.8
update_transform()
/mob/living/simple_animal/bot/secbot/proc/process_emote(var/emote_type, var/atom/criminal, var/threat, var/arrest = -1, var/location)
var/emote = "The continuity of space itself collapses around [src]. You should probably report that to someone higher up."
switch(emote_type)
if("DEATH")
emote = death_emote
if("CAPTURE_ONE")
emote = capture_one
if("CAPTURE_TWO")
emote = capture_two
if("INFRACTION")
emote = infraction
if("TAUNT")
emote = taunt
if("ATTACK_ONE")
emote = attack_one
if("ATTACK_TWO")
emote = attack_two
if("ARREST")
emote = arrest_emote
//now replace pieces of the text with the information we have
if(emote_type != "TAUNT" && emote_type != "ARREST")
emote = replacetext(emote, "BOT", name)
else
emote = replacetext(emote, "BOT", "<b>[name]</b>") //needs to be bold if its a taunt or an arrest text
if(criminal)
emote = replacetext(emote, "CRIMINAL", criminal.name)
if(num2text(threat)) //because a threat of 0 will be false
emote = replacetext(emote, "THREAT_LEVEL", threat)
if(arrest > -1)
emote = replacetext(emote, "ARREST_TYPE", arrest_texts[arrest + 1])
if(location)
emote = replacetext(emote, "LOCATION", location)
return emote
/mob/living/simple_animal/bot/secbot/proc/apply_fashion(var/datum/beepsky_fashion/fashion)
stored_fashion = new fashion
if(stored_fashion.name)
name = stored_fashion.name
if(stored_fashion.desc)
desc = stored_fashion.desc
if(stored_fashion.death_emote)
death_emote = stored_fashion.death_emote
if(stored_fashion.capture_one)
capture_one = stored_fashion.capture_one
if(stored_fashion.capture_two)
capture_two = stored_fashion.capture_two
if(stored_fashion.infraction)
infraction = stored_fashion.infraction
if(stored_fashion.taunt)
taunt = stored_fashion.taunt
if(stored_fashion.attack_one)
attack_one = stored_fashion.attack_one
if(stored_fashion.attack_two)
attack_two = stored_fashion.attack_two
if(stored_fashion.patrol_emote)
patrol_emote = stored_fashion.patrol_emote
if(stored_fashion.patrol_fail_emote)
patrol_fail_emote = stored_fashion.patrol_fail_emote
if(stored_fashion.arrest_texts)
arrest_texts = stored_fashion.arrest_texts
if(stored_fashion.arrest_emote)
arrest_emote = stored_fashion.arrest_emote
regenerate_icons()
/mob/living/simple_animal/bot/secbot/proc/reset_fashion()
bot_accessory.forceMove(get_turf(src))
//reset all emotes/sounds and name/desc
name = initial(name)
desc = initial(desc)
death_emote = initial(death_emote)
capture_one = initial(capture_one)
capture_two = initial(capture_two)
infraction = initial(infraction)
taunt = initial(taunt)
attack_one = initial(attack_one)
attack_two = initial(attack_two)
arrest_texts = initial(arrest_texts)
arrest_emote = initial(arrest_emote)
patrol_emote = initial(patrol_emote)
arrest_texts = initial(arrest_texts)
arrest_emote = initial(arrest_emote)
bot_accessory = null
regenerate_icons()
/mob/living/simple_animal/bot/secbot/beepsky/explode()
var/atom/Tsec = drop_location()
@@ -173,11 +284,16 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/proc/special_retaliate_after_attack(mob/user) //allows special actions to take place after being attacked.
return
/mob/living/simple_animal/bot/secbot/attack_hand(mob/living/carbon/human/H)
/mob/living/simple_animal/bot/secbot/on_attack_hand(mob/living/carbon/human/H)
if((H.a_intent == INTENT_HARM) || (H.a_intent == INTENT_DISARM))
retaliate(H)
if(special_retaliate_after_attack(H))
return
if(H.a_intent == INTENT_HELP && bot_accessory)
to_chat(H, "<span class='warning'>You knock [bot_accessory] off of [src]'s head!</span>")
reset_fashion()
return
return ..()
@@ -185,11 +301,48 @@ Auto Patrol: []"},
..()
if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry.
return
if(istype(W, /obj/item/clothing/head))
attempt_place_on_head(user, W)
return
if(!istype(W, /obj/item/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
retaliate(user)
if(special_retaliate_after_attack(user))
return
/mob/living/simple_animal/bot/secbot/proc/attempt_place_on_head(mob/user, obj/item/clothing/head/H)
if(user && !user.temporarilyRemoveItemFromInventory(H))
to_chat(user, "<span class='warning'>\The [H] is stuck to your hand, you cannot put it on [src]'s head!</span>")
return
if(bot_accessory)
to_chat("<span class='warning'>\[src] already has an accessory, and the laws of physics disallow him from wearing a second!</span>")
return
if(H.beepsky_fashion)
to_chat(user, "<span class='warning'>You set [H] on [src].</span>")
bot_accessory = H
H.forceMove(src)
apply_fashion(H.beepsky_fashion)
else
to_chat(user, "<span class='warning'>You set [H] on [src]'s head, but it falls off!</span>")
H.forceMove(drop_location())
/mob/living/simple_animal/bot/secbot/regenerate_icons()
..()
if(bot_accessory)
if(!stored_fashion)
stored_fashion = new bot_accessory.beepsky_fashion
if(!stored_fashion.obj_icon_state)
stored_fashion.obj_icon_state = bot_accessory.icon_state
if(!stored_fashion.obj_alpha)
stored_fashion.obj_alpha = bot_accessory.alpha
if(!stored_fashion.obj_color)
stored_fashion.obj_color = bot_accessory.color
add_overlay(stored_fashion.get_overlay())
else
if(stored_fashion)
cut_overlay(stored_fashion.get_overlay())
stored_fashion = null
/mob/living/simple_animal/bot/secbot/emag_act(mob/user)
. = ..()
if(emagged == 2)
@@ -233,8 +386,8 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/proc/cuff(mob/living/carbon/C)
mode = BOT_ARREST
playsound(src, 'sound/weapons/cablecuff.ogg', 30, TRUE, -2)
C.visible_message("<span class='danger'>[src] is trying to put zipties on [C]!</span>",\
"<span class='userdanger'>[src] is trying to put zipties on you!</span>")
C.visible_message("<span class='danger'>[process_emote("CAPTURE_ONE", C)]</span>",\
"<span class='userdanger'>[process_emote("CAPTURE_TWO", C)]</span>")
if(do_after(src, 60, FALSE, C))
attempt_handcuff(C)
@@ -249,16 +402,22 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C)
var/judgement_criteria = judgement_criteria()
playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
icon_state = "secbot-c"
addtimer(CALLBACK(src, /atom/.proc/update_icon), 2)
var/threat = 5
if(ishuman(C))
if(stored_fashion)
stored_fashion.stun_attack(C)
if(stored_fashion.stun_sounds && !stored_fashion.ignore_sound)
playsound(src, pick(stored_fashion.stun_sounds), 50, TRUE, -1)
else
playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
C.stuttering = 5
C.DefaultCombatKnockdown(100)
var/mob/living/carbon/human/H = C
threat = H.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
else
playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
C.DefaultCombatKnockdown(100)
C.stuttering = 5
threat = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
@@ -266,9 +425,9 @@ Auto Patrol: []"},
log_combat(src,C,"stunned")
if(declare_arrests)
var/area/location = get_area(src)
speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag <b>[C]</b> in [location].", radio_channel)
C.visible_message("<span class='danger'>[src] has stunned [C]!</span>",\
"<span class='userdanger'>[src] has stunned you!</span>")
speak(process_emote("ARREST", C, threat, arrest_type, location), radio_channel)
C.visible_message("<span class='danger'>[process_emote("ATTACK_ONE", C)]</span>",\
"<span class='userdanger'>[process_emote("ATTACK_TWO", C)]</span>")
/mob/living/simple_animal/bot/secbot/handle_automated_action()
if(!..())
@@ -355,7 +514,6 @@ Auto Patrol: []"},
look_for_perp()
bot_patrol()
return
/mob/living/simple_animal/bot/secbot/proc/back_to_idle()
@@ -391,9 +549,9 @@ Auto Patrol: []"},
else if(threatlevel >= 4)
target = C
oldtarget_name = C.name
speak("Level [threatlevel] infraction alert!")
speak(process_emote("INFRACTION", target, threatlevel))
playsound(loc, pick('sound/voice/beepsky/criminal.ogg', 'sound/voice/beepsky/justice.ogg', 'sound/voice/beepsky/freeze.ogg'), 50, FALSE)
visible_message("<b>[src]</b> points at [C.name]!")
visible_message(process_emote("TAUNT", target, threatlevel))
mode = BOT_HUNT
INVOKE_ASYNC(src, .proc/handle_automated_action)
break
@@ -408,7 +566,7 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/explode()
walk_to(src,0)
visible_message("<span class='boldannounce'>[src] blows apart!</span>")
visible_message("<span class='boldannounce'>[process_emote("DEATH")]</span>")
var/atom/Tsec = drop_location()
var/obj/item/bot_assembly/secbot/Sa = new (Tsec)
@@ -283,7 +283,7 @@
if(!D.is_decorated)
D.decorate_donut()
/mob/living/simple_animal/pet/cat/cak/attack_hand(mob/living/L)
/mob/living/simple_animal/pet/cat/cak/on_attack_hand(mob/living/L)
. = ..()
if(.) //the attack was blocked
return
@@ -166,7 +166,7 @@
if(stat == CONSCIOUS)
udder.generateMilk(milk_reagent)
/mob/living/simple_animal/cow/attack_hand(mob/living/carbon/M)
/mob/living/simple_animal/cow/on_attack_hand(mob/living/carbon/M)
if(!stat && M.a_intent == INTENT_DISARM && icon_state != icon_dead)
M.visible_message("<span class='warning'>[M] tips over [src].</span>",
"<span class='notice'>You tip over [src].</span>")
@@ -86,8 +86,7 @@
/obj/guardian_bomb/attackby(mob/living/user)
detonate(user)
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/guardian_bomb/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
/obj/guardian_bomb/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
detonate(user)
/obj/guardian_bomb/examine(mob/user)
@@ -3,7 +3,7 @@
melee_damage_lower = 20
melee_damage_upper = 20
obj_damage = 80
next_move_modifier = 0.5 //attacks 50% faster
action_cooldown_mod = 0.5 //attacks 50% faster
environment_smash = ENVIRONMENT_SMASH_WALLS
playstyle_string = "<span class='holoparasite'>As a <b>standard</b> type you have no special abilities, but take half damage and have powerful attack capable of smashing through walls.</span>"
magic_fluff_string = "<span class='holoparasite'>..And draw the Assistant, faceless and generic, but never to be underestimated.</span>"
@@ -29,8 +29,11 @@
var/armored = FALSE
obj_damage = 60
melee_damage_lower = 20
melee_damage_upper = 30
melee_damage_lower = 15 // i know it's like half what it used to be, but bears cause bleeding like crazy now so it works out
melee_damage_upper = 15
wound_bonus = -5
bare_wound_bonus = 10 // BEAR wound bonus am i right
sharpness = TRUE
attack_verb_continuous = "claws"
attack_verb_simple = "claw"
attack_sound = 'sound/weapons/bladeslice.ogg'
@@ -69,8 +72,9 @@
icon_dead = "combatbear_dead"
faction = list("russian")
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/bear = 5, /obj/item/clothing/head/bearpelt = 1, /obj/item/bear_armor = 1)
melee_damage_lower = 25
melee_damage_upper = 35
melee_damage_lower = 18
melee_damage_upper = 20
wound_bonus = 0
armour_penetration = 20
health = 120
maxHealth = 120
@@ -99,8 +103,9 @@
A.maxHealth += 60
A.health += 60
A.armour_penetration += 20
A.melee_damage_lower += 5
A.melee_damage_lower += 3
A.melee_damage_upper += 5
A.wound_bonus += 5
A.update_icons()
to_chat(user, "<span class='info'>You strap the armor plating to [A] and sharpen [A.p_their()] claws with the nail filer. This was a great idea.</span>")
qdel(src)
@@ -131,7 +136,7 @@ mob/living/simple_animal/hostile/bear/butter //The mighty companion to Cak. Seve
if(health < maxHealth)
heal_overall_damage(10) //Fast life regen, makes it hard for you to get eaten to death.
/mob/living/simple_animal/hostile/bear/butter/attack_hand(mob/living/L) //Borrowed code from Cak, feeds people if they hit you. More nutriment but less vitamin to represent BUTTER.
/mob/living/simple_animal/hostile/bear/butter/on_attack_hand(mob/living/L) //Borrowed code from Cak, feeds people if they hit you. More nutriment but less vitamin to represent BUTTER.
..()
if(L.a_intent == INTENT_HARM && L.reagents && !stat)
L.reagents.add_reagent(/datum/reagent/consumable/nutriment, 1)
@@ -523,9 +523,9 @@ mob/living/simple_animal/hostile/proc/DestroySurroundings() // for use with mega
if(ranged && ranged_cooldown <= world.time)
target = A
OpenFire(A)
..()
DelayNextAction()
. = ..()
return TRUE
////// AI Status ///////
/mob/living/simple_animal/hostile/proc/AICanContinue(var/list/possible_targets)
@@ -81,7 +81,7 @@
/obj/structure/leaper_bubble/Initialize()
. = ..()
float(on = TRUE)
INVOKE_ASYNC(src, /atom/movable.proc/float, TRUE)
QDEL_IN(src, 100)
/obj/structure/leaper_bubble/Destroy()
@@ -136,7 +136,7 @@
target = A
if(!isturf(loc))
return
if(next_move > world.time)
if(!CheckActionCooldown())
return
if(hopping)
return
@@ -70,7 +70,7 @@ Difficulty: Medium
/obj/item/melee/transforming/cleaving_saw/miner/attack(mob/living/target, mob/living/carbon/human/user)
target.add_stun_absorption("miner", 10, INFINITY)
..()
. = ..()
target.stun_absorption -= "miner"
/obj/item/projectile/kinetic/miner
@@ -86,8 +86,8 @@ Difficulty: Medium
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
var/adjustment_amount = amount * 0.1
if(world.time + adjustment_amount > next_move)
changeNext_move(adjustment_amount) //attacking it interrupts it attacking, but only briefly
if(world.time + adjustment_amount > next_action)
DelayNextAction(adjustment_amount, considered_action = FALSE, flush = TRUE) //attacking it interrupts it attacking, but only briefly
. = ..()
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/death()
@@ -109,7 +109,7 @@ Difficulty: Medium
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/AttackingTarget()
if(QDELETED(target))
return
if(next_move > world.time || !Adjacent(target)) //some cheating
if(!CheckActionCooldown() || !Adjacent(target)) //some cheating
INVOKE_ASYNC(src, .proc/quick_attack_loop)
return
face_atom(target)
@@ -125,8 +125,8 @@ Difficulty: Medium
adjustHealth(-(L.maxHealth * 0.5))
L.gib()
return TRUE
changeNext_move(CLICK_CD_MELEE)
miner_saw.melee_attack_chain(src, target)
miner_saw.melee_attack_chain(src, target, null, ATTACK_IGNORE_CLICKDELAY)
FlushCurrentAction()
if(guidance)
adjustHealth(-2)
transform_weapon()
@@ -161,19 +161,19 @@ Difficulty: Medium
face_atom(target)
new /obj/effect/temp_visual/dir_setting/firing_effect(loc, dir)
Shoot(target)
changeNext_move(CLICK_CD_RANGE)
DelayNextAction(CLICK_CD_RANGE, flush = TRUE)
//I'm still of the belief that this entire proc needs to be wiped from existence.
// do not take my touching of it to be endorsement of it. ~mso
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/quick_attack_loop()
while(!QDELETED(target) && next_move <= world.time) //this is done this way because next_move can change to be sooner while we sleep.
while(!QDELETED(target) && !CheckActionCooldown()) //this is done this way because next_move can change to be sooner while we sleep.
stoplag(1)
sleep((next_move - world.time) * 1.5) //but don't ask me what the fuck this is about
sleep((next_action - world.time) * 1.5) //but don't ask me what the fuck this is about
if(QDELETED(target))
return
if(dashing || next_move > world.time || !Adjacent(target))
if(dashing && next_move <= world.time)
next_move = world.time + 1
if(dashing || !CheckActionCooldown() || !Adjacent(target))
if(dashing && next_action <= world.time)
SetNextAction(1, considered_action = FALSE, immediate = FALSE, flush = TRUE)
INVOKE_ASYNC(src, .proc/quick_attack_loop) //lets try that again.
return
AttackingTarget()
@@ -385,10 +385,7 @@ Difficulty: Very Hard
if(isliving(speaker))
ActivationReaction(speaker, ACTIVATE_SPEECH)
/obj/machinery/anomalous_crystal/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.)
return
/obj/machinery/anomalous_crystal/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
ActivationReaction(user, ACTIVATE_TOUCH)
/obj/machinery/anomalous_crystal/attackby(obj/item/I, mob/user, params)
@@ -4,6 +4,11 @@
#define SWOOP_DAMAGEABLE 1
#define SWOOP_INVULNERABLE 2
///used whenever the drake generates a hotspot
#define DRAKE_FIRE_TEMP 500
///used whenever the drake generates a hotspot
#define DRAKE_FIRE_EXPOSURE 50
/*
ASH DRAKE
@@ -148,7 +153,7 @@ Difficulty: Medium
break
range--
new /obj/effect/hotspot(J)
J.hotspot_expose(700,50,1)
J.hotspot_expose(DRAKE_FIRE_TEMP, DRAKE_FIRE_EXPOSURE, 1)
for(var/mob/living/L in J.contents - hit_things)
if(istype(L, /mob/living/simple_animal/hostile/megafauna/dragon))
continue
@@ -404,7 +409,7 @@ Difficulty: Medium
if(istype(T, /turf/closed))
break
new /obj/effect/hotspot(T)
T.hotspot_expose(700,50,1)
T.hotspot_expose(DRAKE_FIRE_TEMP,DRAKE_FIRE_EXPOSURE,1)
for(var/mob/living/L in T.contents)
if(L in hit_list || L == source)
continue
@@ -643,7 +643,7 @@ Difficulty: Normal
to_chat(L, "<span class='userdanger'>You're struck by a [name]!</span>")
var/limb_to_hit = L.get_bodypart(pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG))
var/armor = L.run_armor_check(limb_to_hit, "melee", "Your armor absorbs [src]!", "Your armor blocks part of [src]!", 50, "Your armor was penetrated by [src]!")
L.apply_damage(damage, BURN, limb_to_hit, armor)
L.apply_damage(damage, BURN, limb_to_hit, armor, wound_bonus=CANT_WOUND)
if(ishostile(L))
var/mob/living/simple_animal/hostile/H = L //mobs find and damage you...
if(H.stat == CONSCIOUS && !H.target && H.AIStatus != AI_OFF && !H.client)
@@ -52,6 +52,8 @@ Difficulty: Medium
elimination = 1
appearance_flags = 0
mouse_opacity = MOUSE_OPACITY_ICON
wound_bonus = -40
bare_wound_bonus = 20
/mob/living/simple_animal/hostile/megafauna/legion/Initialize()
. = ..()
@@ -129,7 +129,7 @@ Difficulty: Hard
to_chat(L, "<span class='userdanger'>[src]'s ground slam shockwave sends you flying!</span>")
var/turf/thrownat = get_ranged_target_turf_direct(src, L, 8, rand(-10, 10))
L.throw_at(thrownat, 8, 2, src, TRUE) //, force = MOVE_FORCE_OVERPOWERING, gentle = TRUE)
L.apply_damage(20, BRUTE)
L.apply_damage(20, BRUTE, wound_bonus=CANT_WOUND)
shake_camera(L, 2, 1)
all_turfs -= T
sleep(delay)
@@ -105,7 +105,7 @@ IGNORE_PROC_IF_NOT_TARGET(attack_slime)
/mob/living/simple_animal/hostile/asteroid/curseblob/attacked_by(obj/item/I, mob/living/L, attackchain_flags = NONE, damage_multiplier = 1)
if(L != set_target)
L.changeNext_move(I.click_delay) //pre_attacked_by not called
I.ApplyAttackCooldown(L, src)
return
return ..()
@@ -148,7 +148,7 @@ While using this makes the system rely on OnFire, it still gives options for tim
desc = "You're not quite sure how a signal can be menacing."
invisibility = 100
/obj/structure/elite_tumor/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
/obj/structure/elite_tumor/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(ishuman(user))
switch(activity)
@@ -170,7 +170,7 @@
Bruise()
..()
/mob/living/simple_animal/hostile/mushroom/attack_hand(mob/living/carbon/human/M)
/mob/living/simple_animal/hostile/mushroom/on_attack_hand(mob/living/carbon/human/M)
. = ..()
if(.) // the attack was blocked
return
@@ -86,7 +86,7 @@
.=..()
START_PROCESSING(SSprocessing, src)
/obj/structure/spawner/nether/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
/obj/structure/spawner/nether/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
user.visible_message("<span class='warning'>[user] is violently pulled into the link!</span>", \
"<span class='userdanger'>Touching the portal, you are quickly pulled through into a world of unimaginable horror!</span>")
contents.Add(user)
@@ -37,6 +37,10 @@
var/banana_type = /obj/item/grown/bananapeel
var/attack_reagent
/mob/living/simple_animal/hostile/retaliate/clown/Initialize(mapload)
. = ..()
faction |= "clown"
/mob/living/simple_animal/hostile/retaliate/clown/handle_temperature_damage()
if(bodytemperature < minbodytemp)
adjustBruteLoss(10)
@@ -47,7 +51,7 @@
else
clear_alert("temp")
/mob/living/simple_animal/hostile/retaliate/clown/attack_hand(mob/living/carbon/human/M)
/mob/living/simple_animal/hostile/retaliate/clown/on_attack_hand(mob/living/carbon/human/M)
..()
playsound(src.loc, 'sound/items/bikehorn.ogg', 50, TRUE)
@@ -77,6 +77,9 @@
/mob/living/simple_animal/hostile/syndicate/melee
melee_damage_lower = 15
melee_damage_upper = 15
wound_bonus = -10
bare_wound_bonus = 20
sharpness = TRUE
icon_state = "syndicate_knife"
icon_living = "syndicate_knife"
loot = list(/obj/effect/gibspawner/human)
@@ -271,7 +271,7 @@
* Attack responces
*/
//Humans, monkeys, aliens
/mob/living/simple_animal/parrot/attack_hand(mob/living/carbon/M)
/mob/living/simple_animal/parrot/on_attack_hand(mob/living/carbon/M)
..()
if(client)
return
@@ -20,12 +20,12 @@
laugher.emote("laugh")
/mob/living/simple_animal/pickle/death()
..()
if(original_body)
original_body.adjustOrganLoss(ORGAN_SLOT_BRAIN, 200) //to be fair, you have to have a very high iq to understand-
original_body.forceMove(get_turf(src))
if(mind)
mind.transfer_to(original_body)
..()
/mob/living/simple_animal/pickle/wabbajack_act() //restore users name before its used on the new mob
if(original_body)
@@ -140,6 +140,13 @@
///What kind of footstep this mob should have. Null if it shouldn't have any.
var/footstep_type
//How much wounding power it has
var/wound_bonus = CANT_WOUND
//How much bare wounding power it has
var/bare_wound_bonus = 0
//If the attacks from this are sharp
var/sharpness = FALSE
/mob/living/simple_animal/Initialize()
. = ..()
GLOB.simple_animals[AIStatus] += src

Some files were not shown because too many files have changed in this diff Show More