Merge branch 'master' into spike-loot-differentces

This commit is contained in:
Trilbyspaceclone
2020-08-03 10:53:08 -04:00
committed by GitHub
2245 changed files with 150873 additions and 463893 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
+3 -3
View File
@@ -68,7 +68,7 @@ INITIALIZE_IMMEDIATE(/mob/dead)
set category = "OOC"
set name = "Server Hop!"
set desc= "Jump to the other server"
if(notransform)
if(mob_transforming)
return
var/list/csa = CONFIG_GET(keyed_list/cross_server)
var/pick
@@ -93,9 +93,9 @@ INITIALIZE_IMMEDIATE(/mob/dead)
to_chat(C, "<span class='notice'>Sending you to [pick].</span>")
new /obj/screen/splash(C)
notransform = TRUE
mob_transforming = TRUE
sleep(29) //let the animation play
notransform = FALSE
mob_transforming = FALSE
if(!C)
return
+16 -1
View File
@@ -398,7 +398,7 @@
humanc = character //Let's retypecast the var to be human,
if(humanc) //These procs all expect humans
GLOB.data_core.manifest_inject(humanc)
GLOB.data_core.manifest_inject(humanc, humanc.client, humanc.client.prefs)
if(SSshuttle.arrivals)
SSshuttle.arrivals.QueueAnnounce(humanc, rank)
else
@@ -412,6 +412,8 @@
give_guns(humanc)
if(GLOB.summon_magic_triggered)
give_magic(humanc)
if(GLOB.curse_of_madness_triggered)
give_madness(humanc, GLOB.curse_of_madness_triggered)
GLOB.joined_player_list += character.ckey
GLOB.latejoiners += character
@@ -556,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
@@ -24,7 +24,7 @@
/datum/notificationpanel/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.observer_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "notificationpanel", "Notification Preferences", 270, 360, master_ui, state)
ui = new(user, src, ui_key, "NotificationPreferences", "Notification Preferences", 270, 360, master_ui, state)
ui.open()
/datum/notificationpanel/ui_data(mob/user)
+10 -8
View File
@@ -54,6 +54,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
// Used for displaying in ghost chat, without changing the actual name
// of the mob
var/deadchat_name
var/datum/orbit_menu/orbit_menu
var/datum/spawners_menu/spawners_menu
/mob/dead/observer/Initialize(mapload, mob/body)
@@ -161,6 +162,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
updateallghostimages()
QDEL_NULL(orbit_menu)
QDEL_NULL(spawners_menu)
return ..()
@@ -490,10 +492,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Orbit" // "Haunt"
set desc = "Follow and orbit a mob."
var/list/mobs = getpois(skip_mindless=1)
var/input = input("Please, select a mob!", "Haunt", null, null) as null|anything in mobs
var/mob/target = mobs[input]
ManualFollow(target)
if(!orbit_menu)
orbit_menu = new(src)
orbit_menu.ui_interact(src)
// This is the ghost's follow verb with an argument
/mob/dead/observer/proc/ManualFollow(atom/movable/target)
@@ -837,13 +839,13 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
/mob/dead/observer/vv_edit_var(var_name, var_value)
. = ..()
switch(var_name)
if("icon")
if(NAMEOF(src, icon))
ghostimage_default.icon = icon
ghostimage_simple.icon = icon
if("icon_state")
if(NAMEOF(src, icon_state))
ghostimage_default.icon_state = icon_state
ghostimage_simple.icon_state = icon_state
if("fun_verbs")
if(NAMEOF(src, fun_verbs))
if(fun_verbs)
verbs += /mob/dead/observer/verb/boo
verbs += /mob/dead/observer/verb/possess
@@ -925,7 +927,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
/mob/dead/observer/vv_edit_var(var_name, var_value)
. = ..()
if(var_name == "invisibility")
if(var_name == NAMEOF(src, invisibility))
set_invisibility(invisibility) // updates light
/proc/set_observer_default_invisibility(amount, message=null)
+78
View File
@@ -0,0 +1,78 @@
/datum/orbit_menu
var/mob/dead/observer/owner
/datum/orbit_menu/New(mob/dead/observer/new_owner)
if(!istype(new_owner))
qdel(src)
owner = new_owner
/datum/orbit_menu/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.observer_state)
if (!ui)
ui = new(user, src, ui_key, "Orbit", "Orbit", 350, 700, master_ui, state)
ui.open()
/datum/orbit_menu/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
if (..())
return
if (action == "orbit")
var/list/pois = getpois(skip_mindless = 1)
var/atom/movable/poi = pois[params["name"]]
if (poi != null)
owner.ManualFollow(poi)
ui.close()
/datum/orbit_menu/ui_data(mob/user)
var/list/data = list()
var/list/alive = list()
var/list/antagonists = list()
var/list/dead = list()
var/list/ghosts = list()
var/list/misc = list()
var/list/npcs = list()
var/list/pois = getpois(skip_mindless = 1)
for (var/name in pois)
var/list/serialized = list()
serialized["name"] = name
var/poi = pois[name]
var/mob/M = poi
if (istype(M))
if (isobserver(M))
ghosts += list(serialized)
else if (M.stat == DEAD)
dead += list(serialized)
else if (M.mind == null)
npcs += list(serialized)
else
var/number_of_orbiters = M.orbiters?.orbiters?.len
if (number_of_orbiters)
serialized["orbiters"] = number_of_orbiters
var/datum/mind/mind = M.mind
var/was_antagonist = FALSE
for (var/_A in mind.antag_datums)
var/datum/antagonist/A = _A
if (A.show_to_ghosts)
was_antagonist = TRUE
serialized["antag"] = A.name
antagonists += list(serialized)
break
if (!was_antagonist)
alive += list(serialized)
else
misc += list(serialized)
data["alive"] = alive
data["antagonists"] = antagonists
data["dead"] = dead
data["ghosts"] = ghosts
data["misc"] = misc
data["npcs"] = npcs
return data
+54 -49
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...
@@ -158,7 +150,7 @@
//Returns if a certain item can be equipped to a certain slot.
// Currently invalid for two-handed items - call obj/item/mob_can_equip() instead.
/mob/proc/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
/mob/proc/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, clothing_check = FALSE, list/return_warning)
return FALSE
/mob/proc/can_put_in_hand(I, hand_index)
@@ -338,50 +330,63 @@
return FALSE
return TRUE
//This is a SAFE proc. Use this instead of equip_to_slot()!
//set qdel_on_fail to have it delete W if it fails to equip
//set disable_warning to disable the 'you are unable to equip that' warning.
//unset redraw_mob to prevent the mob from being redrawn at the end.
/mob/proc/equip_to_slot_if_possible(obj/item/W, slot, qdel_on_fail = FALSE, disable_warning = FALSE, redraw_mob = TRUE, bypass_equip_delay_self = FALSE, clothing_check = FALSE)
if(!istype(W))
return FALSE
var/list/warning = list("<span class='warning'>You are unable to equip that!</span>")
if(!W.mob_can_equip(src, null, slot, disable_warning, bypass_equip_delay_self, clothing_check, warning))
if(qdel_on_fail)
qdel(W)
else if(!disable_warning)
to_chat(src, warning[1])
return FALSE
equip_to_slot(W, slot, redraw_mob) //This proc should not ever fail.
return TRUE
//This is an UNSAFE proc. It merely handles the actual job of equipping. All the checks on whether you can or can't equip need to be done before! Use mob_can_equip() for that task.
//In most cases you will want to use equip_to_slot_if_possible()
/mob/proc/equip_to_slot(obj/item/W, slot)
return
//This is just a commonly used configuration for the equip_to_slot_if_possible() proc, used to equip people when the round starts and when events happen and such.
//Also bypasses equip delay checks, since the mob isn't actually putting it on.
/mob/proc/equip_to_slot_or_del(obj/item/W, slot)
return equip_to_slot_if_possible(W, slot, TRUE, TRUE, FALSE, TRUE)
//puts the item "W" into an appropriate slot in a human's inventory
//returns 0 if it cannot, 1 if successful
/mob/proc/equip_to_appropriate_slot(obj/item/W, clothing_check = FALSE)
if(!istype(W))
return 0
var/slot_priority = W.slot_equipment_priority
if(!slot_priority)
slot_priority = list( \
SLOT_BACK, SLOT_WEAR_ID,\
SLOT_W_UNIFORM, SLOT_WEAR_SUIT,\
SLOT_WEAR_MASK, SLOT_HEAD, SLOT_NECK,\
SLOT_SHOES, SLOT_GLOVES,\
SLOT_EARS, SLOT_GLASSES,\
SLOT_BELT, SLOT_S_STORE,\
SLOT_L_STORE, SLOT_R_STORE,\
SLOT_GENERC_DEXTROUS_STORAGE\
)
for(var/slot in slot_priority)
if(equip_to_slot_if_possible(W, slot, FALSE, TRUE, TRUE, FALSE, clothing_check)) //qdel_on_fail = 0; disable_warning = 1; redraw_mob = 1
return 1
return 0
//Outdated but still in use apparently. This should at least be a human proc.
//Daily reminder to murder this - Remie.
/mob/living/proc/get_equipped_items(include_pockets = FALSE)
return
/mob/living/carbon/get_equipped_items(include_pockets = FALSE)
var/list/items = list()
if(back)
items += back
if(head)
items += head
if(wear_mask)
items += wear_mask
if(wear_neck)
items += wear_neck
return items
/mob/living/carbon/human/get_equipped_items(include_pockets = FALSE)
var/list/items = ..()
if(belt)
items += belt
if(ears)
items += ears
if(glasses)
items += glasses
if(gloves)
items += gloves
if(shoes)
items += shoes
if(wear_id)
items += wear_id
if(wear_suit)
items += wear_suit
if(w_uniform)
items += w_uniform
if(include_pockets)
if(l_store)
items += l_store
if(r_store)
items += r_store
if(s_store)
items += s_store
return items
/mob/living/proc/unequip_everything()
var/list/items = list()
items |= get_equipped_items(TRUE)
@@ -394,7 +399,7 @@
to_chat(M, "<span class='warning'>You are not holding anything to equip!</span>")
return FALSE
if(M.equip_to_appropriate_slot(src))
if(M.equip_to_appropriate_slot(src, TRUE))
M.update_inv_hands()
return TRUE
else
+40 -45
View File
@@ -5,44 +5,43 @@
#define EXOTIC_BLEED_MULTIPLIER 4 //Multiplies the actually bled amount by this number for the purposes of turf reaction calculations.
/mob/living/carbon/human/proc/suppress_bloodloss(amount)
if(bleedsuppress)
/mob/living/carbon/monkey/handle_blood()
if(bodytemperature <= TCRYO || (HAS_TRAIT(src, TRAIT_HUSK))) //cryosleep or husked people do not pump the blood.
return
else
bleedsuppress = TRUE
addtimer(CALLBACK(src, .proc/resume_bleeding), amount)
var/temp_bleed = 0
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
temp_bleed += BP.get_bleed_rate()
BP.generic_bleedstacks = max(0, BP.generic_bleedstacks - 1)
if(temp_bleed)
bleed(temp_bleed)
//Blood regeneration if there is some space
if(blood_volume < BLOOD_VOLUME_NORMAL)
blood_volume += 0.1 // regenerate blood VERY slowly
if(blood_volume < BLOOD_VOLUME_OKAY)
adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1))
/mob/living/carbon/human/proc/resume_bleeding()
bleedsuppress = 0
if(stat != DEAD && bleed_rate)
if(stat != DEAD && is_bleeding())
to_chat(src, "<span class='warning'>The blood soaks through your bandage.</span>")
/mob/living/carbon/monkey/handle_blood()
if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_NOCLONE))) //cryosleep or husked people do not pump the blood.
//Blood regeneration if there is some space
if(blood_volume < (BLOOD_VOLUME_NORMAL * blood_ratio))
blood_volume += 0.1 // regenerate blood VERY slowly
if(blood_volume < (BLOOD_VOLUME_OKAY * blood_ratio))
adjustOxyLoss(round(((BLOOD_VOLUME_NORMAL * blood_ratio) - blood_volume) * 0.02, 1))
// Takes care blood loss and regeneration
/mob/living/carbon/human/handle_blood()
if(NOBLOOD in dna.species.species_traits)
bleed_rate = 0
if(NOBLOOD in dna.species.species_traits || bleedsuppress || (HAS_TRAIT(src, TRAIT_FAKEDEATH)))
return
if(bleed_rate < 0)
bleed_rate = 0
if(HAS_TRAIT(src, TRAIT_NOMARROW)) //Bloodsuckers don't need to be here.
return
if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_NOCLONE))) //cryosleep or husked people do not pump the blood.
if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_HUSK))) //cryosleep or husked people do not pump the blood.
//Blood regeneration if there is some space
if(blood_volume < (BLOOD_VOLUME_NORMAL * blood_ratio) && !HAS_TRAIT(src, TRAIT_NOHUNGER))
if(blood_volume < BLOOD_VOLUME_NORMAL && !HAS_TRAIT(src, TRAIT_NOHUNGER))
var/nutrition_ratio = 0
switch(nutrition)
if(0 to NUTRITION_LEVEL_STARVING)
@@ -55,22 +54,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,22 +91,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)
temp_bleed += 0.5 * BP.embedded_objects.len
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)
@@ -126,9 +119,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
@@ -186,7 +181,7 @@
blood_data["viruses"] += D.Copy()
blood_data["blood_DNA"] = dna.unique_enzymes
blood_data["bloodcolor"] = bloodtype_to_color(dna.blood_type)
blood_data["bloodcolor"] = dna.species.exotic_blood_color
if(disease_resistances && disease_resistances.len)
blood_data["resistances"] = disease_resistances.Copy()
var/list/temp_chem = list()
+3 -3
View File
@@ -37,10 +37,10 @@
C.put_in_hands(B1)
C.put_in_hands(B2)
C.regenerate_icons()
src.notransform = TRUE
src.mob_transforming = TRUE
spawn(0)
bloodpool_sink(B)
src.notransform = FALSE
src.mob_transforming = FALSE
return 1
/mob/living/proc/bloodpool_sink(obj/effect/decal/cleanable/B)
@@ -155,7 +155,7 @@
addtimer(CALLBACK(src, /atom/.proc/remove_atom_colour, TEMPORARY_COLOUR_PRIORITY, newcolor), 6 SECONDS)
/mob/living/proc/phasein(obj/effect/decal/cleanable/B)
if(src.notransform)
if(src.mob_transforming)
to_chat(src, "<span class='warning'>Finish eating first!</span>")
return 0
B.visible_message("<span class='warning'>[B] starts to bubble...</span>")
+3 -1
View File
@@ -39,7 +39,9 @@
laws.set_laws_config()
/obj/item/mmi/attackby(obj/item/O, mob/user, params)
user.changeNext_move(CLICK_CD_MELEE)
if(!user.CheckActionCooldown(CLICK_CD_MELEE))
return
user.DelayNextAction()
if(istype(O, /obj/item/organ/brain)) //Time to stick a brain in it --NEO
var/obj/item/organ/brain/newbrain = O
if(brain)
+6
View File
@@ -100,3 +100,9 @@
client.mouse_pointer_icon = M.mouse_pointer
if (client && ranged_ability && ranged_ability.ranged_mousepointer)
client.mouse_pointer_icon = ranged_ability.ranged_mousepointer
/mob/living/brain/proc/get_traumas()
. = list()
if(istype(loc, /obj/item/organ/brain))
var/obj/item/organ/brain/B = loc
. = B.traumas
+4 -5
View File
@@ -76,9 +76,6 @@
REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, C)
C.update_hair()
/obj/item/organ/brain/prepare_eat()
return // Too important to eat.
/obj/item/organ/brain/proc/transfer_identity(mob/living/L)
name = "[L.name]'s brain"
if(brainmob)
@@ -105,7 +102,7 @@
to_chat(brainmob, "<span class='notice'>You feel slightly disoriented. That's normal when you're just a brain.</span>")
/obj/item/organ/brain/attackby(obj/item/O, mob/user, params)
user.changeNext_move(CLICK_CD_MELEE)
user.DelayNextAction(CLICK_CD_MELEE)
if(brainmob)
O.attack(brainmob, user) //Oh noooeeeee
@@ -334,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)
@@ -392,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)
+2 -6
View File
@@ -1,11 +1,7 @@
/mob/living/brain/Life()
set invisibility = 0
if (notransform)
/mob/living/brain/BiologicalLife(seconds, times_fired)
if(!(. = ..()))
return
if(!loc)
return
. = ..()
handle_emp_damage()
/mob/living/brain/update_stat()
@@ -25,7 +25,7 @@
status_flags = CANUNCONSCIOUS|CANPUSH
var/heat_protection = 0.5
heat_protection = 0.5
var/leaping = 0
gib_type = /obj/effect/decal/cleanable/blood/gibs/xeno
unique_name = 1
@@ -8,9 +8,6 @@
/mob/living/carbon/alien/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
return ..(AM, skipcatch = TRUE, hitpush = FALSE)
/mob/living/carbon/alien/can_embed(obj/item/I)
return FALSE
/*Code for aliens attacking aliens. Because aliens act on a hivemind, I don't see them as very aggressive with each other.
As such, they can either help or harm other aliens. Help works like the human help command while harm is a simple nibble.
In all, this is a lot like the monkey code. /N
@@ -48,12 +45,14 @@ 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
switch(M.a_intent)
if(INTENT_HELP)
if(M == src && check_self_for_injuries())
return
help_shake_act(M)
if(INTENT_GRAB)
grabbedby(M)
@@ -75,7 +74,6 @@ In all, this is a lot like the monkey code. /N
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
apply_damage(rand(1, 3), BRUTE, affecting)
/mob/living/carbon/alien/attack_animal(mob/living/simple_animal/M)
. = ..()
if(.)
@@ -57,8 +57,17 @@
/mob/living/carbon/alien/humanoid/Topic(href, href_list)
..()
//strip panel
//strip panel & embeds
if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
if(href_list["embedded_object"])
var/obj/item/bodypart/L = locate(href_list["embedded_limb"]) in bodyparts
if(!L)
return
var/obj/item/I = locate(href_list["embedded_object"]) in L.embedded_objects
if(!I || I.loc != src) //no item, no limb, or item is not in limb or in the alien anymore
return
SEND_SIGNAL(src, COMSIG_CARBON_EMBED_RIP, I, L)
return
if(href_list["pouches"])
visible_message("<span class='danger'>[usr] tries to empty [src]'s pouches.</span>", \
"<span class='userdanger'>[usr] tries to empty [src]'s pouches.</span>")
@@ -21,7 +21,7 @@
"<span class='userdanger'>[user] has [hitverb] [src]!</span>", null, COMBAT_MESSAGE_RANGE)
return 1
/mob/living/carbon/alien/humanoid/attack_hand(mob/living/carbon/human/M)
/mob/living/carbon/alien/humanoid/on_attack_hand(mob/living/carbon/human/M)
. = ..()
if(.) //To allow surgery to return properly.
return
@@ -1,5 +0,0 @@
/mob/living/carbon/alien/humanoid/doUnEquip(obj/item/I)
. = ..()
if(!. || !I)
return
@@ -1,6 +1,6 @@
/mob/living/carbon/alien/larva/attack_hand(mob/living/carbon/human/M)
/mob/living/carbon/alien/larva/on_attack_hand(mob/living/carbon/human/M)
. = ..()
if(. || M.a_intent == INTENT_HELP || M.a_intent == INTENT_GRAB)
return
@@ -1,14 +1,10 @@
/mob/living/carbon/alien/larva/Life()
set invisibility = 0
if (notransform)
/mob/living/carbon/alien/larva/BiologicalLife(seconds, times_fired)
if(!(. = ..()))
return
if(..()) //not dead
// GROW!
if(amount_grown < max_grown)
amount_grown++
update_icons()
// GROW!
if(amount_grown < max_grown)
amount_grown++
update_icons()
/mob/living/carbon/alien/larva/update_stat()
+9 -11
View File
@@ -1,6 +1,7 @@
/mob/living/carbon/alien/Life()
/mob/living/carbon/alien/BiologicalLife(seconds, times_fired)
if(!(. = ..()))
return
findQueen()
return..()
/mob/living/carbon/alien/check_breath(datum/gas_mixture/breath)
if(status_flags & GODMODE)
@@ -12,26 +13,23 @@
var/toxins_used = 0
var/tox_detect_threshold = 0.02
var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME
var/list/breath_gases = breath.gases
var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.return_temperature())/BREATH_VOLUME
//Partial pressure of the toxins in our breath
var/Toxins_pp = (breath_gases[/datum/gas/plasma]/breath.total_moles())*breath_pressure
var/Toxins_pp = (breath.get_moles(/datum/gas/plasma)/breath.total_moles())*breath_pressure
if(Toxins_pp > tox_detect_threshold) // Detect toxins in air
adjustPlasma(breath_gases[/datum/gas/plasma]*250)
adjustPlasma(breath.get_moles(/datum/gas/plasma)*250)
throw_alert("alien_tox", /obj/screen/alert/alien_tox)
toxins_used = breath_gases[/datum/gas/plasma]
toxins_used = breath.get_moles(/datum/gas/plasma)
else
clear_alert("alien_tox")
//Breathe in toxins and out oxygen
breath_gases[/datum/gas/plasma] -= toxins_used
breath_gases[/datum/gas/oxygen] += toxins_used
GAS_GARBAGE_COLLECT(breath.gases)
breath.adjust_moles(/datum/gas/plasma, -toxins_used)
breath.adjust_moles(/datum/gas/oxygen, toxins_used)
//BREATH TEMPERATURE
handle_breath_temperature(breath)
+3 -12
View File
@@ -1,7 +1,8 @@
/obj/item/organ/alien
icon_state = "xgibmid2"
food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/acid = 10)
var/list/alien_powers = list()
organ_flags = ORGAN_NO_SPOIL
organ_flags = ORGAN_NO_SPOIL|ORGAN_EDIBLE
/obj/item/organ/alien/Initialize()
. = ..()
@@ -26,12 +27,6 @@
owner.RemoveAbility(P)
..()
/obj/item/organ/alien/prepare_eat()
var/obj/S = ..()
S.reagents.add_reagent(/datum/reagent/toxin/acid, 10)
return S
/obj/item/organ/alien/plasmavessel
name = "plasma vessel"
icon_state = "plasma"
@@ -39,17 +34,13 @@
zone = BODY_ZONE_CHEST
slot = "plasmavessel"
alien_powers = list(/obj/effect/proc_holder/alien/plant, /obj/effect/proc_holder/alien/transfer)
food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/plasma = 10)
var/storedPlasma = 100
var/max_plasma = 250
var/heal_rate = 5
var/plasma_rate = 10
/obj/item/organ/alien/plasmavessel/prepare_eat()
var/obj/S = ..()
S.reagents.add_reagent(/datum/reagent/toxin/plasma, storedPlasma/10)
return S
/obj/item/organ/alien/plasmavessel/large
name = "large plasma vessel"
icon_state = "plasma_large"
@@ -4,6 +4,7 @@
name = "alien embryo"
icon = 'icons/mob/alien.dmi'
icon_state = "larva0_dead"
food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/acid = 10)
var/stage = 0
var/bursting = FALSE
@@ -16,11 +17,6 @@
if(prob(10))
AttemptGrow(0)
/obj/item/organ/body_egg/alien_embryo/prepare_eat()
var/obj/S = ..()
S.reagents.add_reagent(/datum/reagent/toxin/acid, 10)
return S
/obj/item/organ/body_egg/alien_embryo/on_life()
. = ..()
if(!owner)
@@ -92,7 +88,7 @@
ghost.transfer_ckey(new_xeno, FALSE)
SEND_SOUND(new_xeno, sound('sound/voice/hiss5.ogg',0,0,0,100)) //To get the player's attention
new_xeno.Paralyze(6)
new_xeno.notransform = TRUE
new_xeno.mob_transforming = TRUE
new_xeno.invisibility = INVISIBILITY_MAXIMUM
sleep(6)
@@ -102,7 +98,7 @@
if(new_xeno)
new_xeno.SetParalyzed(0)
new_xeno.notransform = FALSE
new_xeno.mob_transforming = FALSE
new_xeno.invisibility = 0
var/mob/living/carbon/old_owner = owner
@@ -58,8 +58,7 @@
/obj/item/clothing/mask/facehugger/attack_alien(mob/user) //can be picked up by aliens
return attack_hand(user)
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/clothing/mask/facehugger/attack_hand(mob/user)
/obj/item/clothing/mask/facehugger/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if((stat == CONSCIOUS && !sterile) && !isalien(user))
if(Leap(user))
return
@@ -88,6 +87,7 @@
Die()
/obj/item/clothing/mask/facehugger/equipped(mob/M)
. = ..()
Attach(M)
/obj/item/clothing/mask/facehugger/Crossed(atom/target)
@@ -254,7 +254,7 @@
return FALSE
if(AmBloodsucker(M))
return FALSE
if(ismonkey(M))
return 1
+122 -41
View File
@@ -47,16 +47,13 @@
/mob/living/carbon/swap_hand(held_index)
. = ..()
if(!.)
var/obj/item/held_item = get_active_held_item()
to_chat(usr, "<span class='warning'>Your other hand is too busy holding [held_item].</span>")
return
if(!held_index)
held_index = (active_hand_index % held_items.len)+1
var/obj/item/item_in_hand = src.get_active_held_item()
if(item_in_hand) //this segment checks if the item in your hand is twohanded.
var/obj/item/twohanded/TH = item_in_hand
if(istype(TH))
if(TH.wielded == 1)
to_chat(usr, "<span class='warning'>Your other hand is too busy holding [TH]</span>")
return
var/oindex = active_hand_index
active_hand_index = held_index
if(hud_used)
@@ -91,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))
@@ -105,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)
@@ -156,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
@@ -182,7 +201,7 @@
to_chat(src, "<span class='notice'>You gently let go of [throwable_mob].</span>")
return
adjustStaminaLossBuffered(25)//CIT CHANGE - throwing an entire person shall be very tiring
adjustStaminaLossBuffered(STAM_COST_THROW_MOB * ((throwable_mob.mob_size+1)**2))// throwing an entire person shall be very tiring
var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors
var/turf/end_T = get_turf(target)
if(start_T && end_T)
@@ -199,12 +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))
@@ -247,7 +272,7 @@
/mob/living/carbon/Topic(href, href_list)
..()
//strip panel
if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
if(usr.canUseTopic(src, BE_CLOSE))
if(href_list["internal"] && !HAS_TRAIT(src, TRAIT_NO_INTERNALS))
var/slot = text2num(href_list["internal"])
var/obj/item/ITEM = get_item_by_slot(slot)
@@ -267,7 +292,15 @@
visible_message("<span class='danger'>[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].</span>", \
"<span class='userdanger'>[usr] [internal ? "opens" : "closes"] the valve on your [ITEM.name].</span>", \
target = usr, target_message = "<span class='danger'>You [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].</span>")
if(href_list["embedded_object"] && usr.canUseTopic(src, BE_CLOSE))
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 person anymore
return
SEND_SIGNAL(src, COMSIG_CARBON_EMBED_RIP, I, L)
return
/mob/living/carbon/fall(forced)
loc.handle_fall(src, forced)//it's loc so it doesn't call the mob's handle_fall which does nothing
@@ -287,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))
@@ -308,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)
@@ -385,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
@@ -398,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)
@@ -887,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()
@@ -977,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)
@@ -1152,3 +1176,60 @@
dna.features["body_model"] = MALE
if(update_icon)
update_body()
/mob/living/carbon/check_obscured_slots()
if(head)
if(head.flags_inv & HIDEMASK)
LAZYOR(., SLOT_WEAR_MASK)
if(head.flags_inv & HIDEEYES)
LAZYOR(., SLOT_GLASSES)
if(head.flags_inv & HIDEEARS)
LAZYOR(., SLOT_EARS)
if(wear_mask)
if(wear_mask.flags_inv & HIDEEYES)
LAZYOR(., SLOT_GLASSES)
// if any of our bodyparts are bleeding
/mob/living/carbon/proc/is_bleeding()
for(var/i in bodyparts)
var/obj/item/bodypart/BP = i
if(BP.get_bleed_rate())
return TRUE
// get our total bleedrate
/mob/living/carbon/proc/get_total_bleed_rate()
var/total_bleed_rate = 0
for(var/i in bodyparts)
var/obj/item/bodypart/BP = i
total_bleed_rate += BP.get_bleed_rate()
return total_bleed_rate
/**
* generate_fake_scars()- for when you want to scar someone, but you don't want to hurt them first. These scars don't count for temporal scarring (hence, fake)
*
* If you want a specific wound scar, pass that wound type as the second arg, otherwise you can pass a list like WOUND_LIST_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)
@@ -0,0 +1,2 @@
/mob/living/carbon/check_unarmed_parry_activation_special()
return ..() && length(get_empty_held_indexes())
@@ -65,32 +65,21 @@
throw_mode_off()
return TRUE
/mob/living/carbon/embed_item(obj/item/I)
throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
var/obj/item/bodypart/L = pick(bodyparts)
L.embedded_objects |= I
I.add_mob_blood(src)//it embedded itself in you, of course it's bloody!
I.forceMove(src)
I.embedded()
L.receive_damage(I.w_class*I.embedding.embedded_impact_pain_multiplier)
visible_message("<span class='danger'>[I] embeds itself in [src]'s [L.name]!</span>","<span class='userdanger'>[I] embeds itself in your [L.name]!</span>")
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
/mob/living/carbon/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
var/totitemdamage = pre_attacked_by(I, user) * damage_multiplier
var/impacting_zone = (user == src)? check_zone(user.zone_selected) : ran_zone(user.zone_selected)
var/list/block_return = list()
if((user != src) && (mob_run_block(I, totitemdamage, "the [I]", ((attackchain_flags & ATTACKCHAIN_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE) | ATTACK_TYPE_MELEE, I.armour_penetration, user, impacting_zone, block_return) & BLOCK_SUCCESS))
if((user != src) && (mob_run_block(I, totitemdamage, "the [I]", ((attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE) | ATTACK_TYPE_MELEE, I.armour_penetration, user, impacting_zone, block_return) & BLOCK_SUCCESS))
return FALSE
totitemdamage = block_calculate_resultant_damage(totitemdamage, block_return)
var/obj/item/bodypart/affecting = get_bodypart(impacting_zone)
if(!affecting) //missing limb? we select the first bodypart (you can never have zero, because of chest)
affecting = bodyparts[1]
SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting)
send_item_attack_message(I, user, affecting.name)
send_item_attack_message(I, user, affecting.name, 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))
@@ -122,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)
/mob/living/carbon/on_attack_hand(mob/living/carbon/human/user, act_intent, unarmed_attack_flags)
. = ..()
if(.) //was the attack blocked?
return
@@ -138,11 +126,14 @@
ContactContractDisease(D)
if(lying && surgeries.len)
if(user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM)
if(act_intent == INTENT_HELP || act_intent == INTENT_DISARM)
for(var/datum/surgery/S in surgeries)
if(S.next_step(user, user.a_intent))
if(S.next_step(user, act_intent))
return TRUE
for(var/datum/wound/W in all_wounds)
if(W.try_handling(user))
return 1
/mob/living/carbon/attack_paw(mob/living/carbon/monkey/M)
@@ -159,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)
. = ..()
@@ -274,6 +263,9 @@
to_chat(M, "<span class='warning'>You can't put [p_them()] out with just your bare hands!</span>")
return
if(M == src && check_self_for_injuries())
return
if(health >= 0 && !(HAS_TRAIT(src, TRAIT_FAKEDEATH)))
var/friendly_check = FALSE
if(mob_run_block(M, 0, M.name, ATTACK_TYPE_UNARMED, 0, null, null, null))
@@ -303,12 +295,12 @@
target_message = "<span class='notice'>[M] gives you a pat on the head to make you feel better!</span>")
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "headpat", /datum/mood_event/headpat)
friendly_check = TRUE
if(S?.can_wag_tail(src) && !dna.species.is_wagging_tail())
var/static/list/many_tails = list("tail_human", "tail_lizard", "mam_tail")
for(var/T in many_tails)
if(S.mutant_bodyparts[T] && dna.features[T] != "None")
emote("wag")
break
if(!(client?.prefs.cit_toggles & NO_AUTO_WAG))
if(S?.can_wag_tail(src) && !dna.species.is_wagging_tail())
var/static/list/many_tails = list("tail_human", "tail_lizard", "mam_tail")
for(var/T in many_tails)
if(S.mutant_bodyparts[T] && dna.features[T] != "None")
emote("wag")
else if(check_zone(M.zone_selected) == BODY_ZONE_R_ARM || check_zone(M.zone_selected) == BODY_ZONE_L_ARM)
M.visible_message( \
@@ -341,6 +333,26 @@
update_mobility()
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
/// Check ourselves to see if we've got any shrapnel, return true if we do. This is a much simpler version of what humans do, we only indicate we're checking ourselves if there's actually shrapnel
/mob/living/carbon/proc/check_self_for_injuries()
if(stat == DEAD || stat == UNCONSCIOUS)
return
var/embeds = FALSE
for(var/X in bodyparts)
var/obj/item/bodypart/LB = X
for(var/obj/item/I in LB.embedded_objects)
if(!embeds)
embeds = TRUE
// this way, we only visibly try to examine ourselves if we have something embedded, otherwise we'll still hug ourselves :)
visible_message("<span class='notice'>[src] examines [p_them()]self.</span>", \
"<span class='notice'>You check yourself for shrapnel.</span>")
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>")
return embeds
/mob/living/carbon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0)
. = ..()
@@ -455,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.
@@ -64,3 +64,17 @@
var/drunkenness = 0 //Overall drunkenness - check handle_alcohol() in life.dm for effects
var/tackling = FALSE //Whether or not we are tackling, this will prevent the knock into effects for carbons
/// All of the wounds a carbon has afflicted throughout their limbs
var/list/all_wounds
/// All of the scars a carbon has afflicted throughout their limbs
var/list/all_scars
/// Protection (insulation) from the heat, Value 0-1 corresponding to the percentage of protection
var/heat_protection = 0 // No heat protection
/// Protection (insulation) from the cold, Value 0-1 corresponding to the percentage of protection
var/cold_protection = 0 // No cold protection
/// Timer id of any transformation
var/transformation_timer
+26 -59
View File
@@ -1,32 +1,33 @@
/mob/living/carbon/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE)
/mob/living/carbon/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = FALSE)
SEND_SIGNAL(src, COMSIG_MOB_APPLY_DAMGE, damage, damagetype, def_zone)
var/hit_percent = (100-blocked)/100
if(!forced && hit_percent <= 0)
return 0
var/obj/item/bodypart/BP = null
if(isbodypart(def_zone)) //we specified a bodypart object
BP = def_zone
else
if(!def_zone)
def_zone = ran_zone(def_zone)
BP = get_bodypart(check_zone(def_zone))
if(!BP)
BP = bodyparts[1]
if(!spread_damage)
if(isbodypart(def_zone)) //we specified a bodypart object
BP = def_zone
else
if(!def_zone)
def_zone = ran_zone(def_zone)
BP = get_bodypart(check_zone(def_zone))
if(!BP)
BP = bodyparts[1]
var/damage_amount = forced ? damage : damage * hit_percent
switch(damagetype)
if(BRUTE)
if(BP)
if(damage > 0 ? BP.receive_damage(damage_amount) : BP.heal_damage(abs(damage_amount), 0))
if(BP.receive_damage(damage_amount, 0, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness))
update_damage_overlays()
else //no bodypart, we deal damage with a more general method.
adjustBruteLoss(damage_amount, forced = forced)
if(BURN)
if(BP)
if(damage > 0 ? BP.receive_damage(0, damage_amount) : BP.heal_damage(0, abs(damage_amount)))
if(BP.receive_damage(0, damage_amount, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness))
update_damage_overlays()
else
adjustFireLoss(damage_amount, forced = forced)
@@ -201,12 +202,12 @@
//Damages ONE bodypart randomly selected from damagable ones.
//It automatically updates damage overlays if necessary
//It automatically updates health status
/mob/living/carbon/take_bodypart_damage(brute = 0, burn = 0, stamina = 0)
/mob/living/carbon/take_bodypart_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE, required_status, check_armor = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = 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
@@ -234,12 +235,12 @@
update_damage_overlays()
update_stamina() //CIT CHANGE - makes sure update_stamina() always gets called after a health update
// damage MANY bodyparts, in random order
/mob/living/carbon/take_overall_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE)
/// damage MANY bodyparts, in random order
/mob/living/carbon/take_overall_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE, required_status)
if(status_flags & GODMODE)
return //godmode
var/list/obj/item/bodypart/parts = get_damageable_bodyparts()
var/list/obj/item/bodypart/parts = get_damageable_bodyparts(required_status)
var/update = 0
while(parts.len && (brute > 0 || burn > 0 || stamina > 0))
var/obj/item/bodypart/picked = pick(parts)
@@ -252,7 +253,7 @@
var/stamina_was = picked.stamina_dam
update |= picked.receive_damage(brute_per_part, burn_per_part, stamina_per_part, FALSE)
update |= picked.receive_damage(brute_per_part, burn_per_part, stamina_per_part, FALSE, required_status, wound_bonus = CANT_WOUND) // disabling wounds from these for now cuz your entire body snapping cause your heart stopped would suck
brute = round(brute - (picked.brute_dam - brute_was), DAMAGE_PRECISION)
burn = round(burn - (picked.burn_dam - burn_was), DAMAGE_PRECISION)
@@ -265,45 +266,11 @@
update_damage_overlays()
update_stamina()
/* TO_REMOVE
/mob/living/carbon/getOrganLoss(ORGAN_SLOT_BRAIN)
. = 0
var/obj/item/organ/brain/B = getorganslot(ORGAN_SLOT_BRAIN)
if(B)
. = B.get_brain_damage()
//Some sources of brain damage shouldn't be deadly
/mob/living/carbon/adjustOrganLoss(ORGAN_SLOT_BRAIN, amount, maximum = BRAIN_DAMAGE_DEATH)
if(status_flags & GODMODE)
return FALSE
var/prev_brainloss = getOrganLoss(ORGAN_SLOT_BRAIN)
var/obj/item/organ/brain/B = getorganslot(ORGAN_SLOT_BRAIN)
if(!B)
return
B.adjust_brain_damage(amount, maximum)
if(amount <= 0) //cut this early
return
var/brainloss = getOrganLoss(ORGAN_SLOT_BRAIN)
if(brainloss > BRAIN_DAMAGE_MILD)
if(prob(amount * ((2 * (100 + brainloss - BRAIN_DAMAGE_MILD)) / 100))) //Base chance is the hit damage; for every point of damage past the threshold the chance is increased by 2%
gain_trauma_type(BRAIN_TRAUMA_MILD)
if(brainloss > BRAIN_DAMAGE_SEVERE)
if(prob(amount * ((2 * (100 + brainloss - BRAIN_DAMAGE_SEVERE)) / 100))) //Base chance is the hit damage; for every point of damage past the threshold the chance is increased by 2%
if(prob(20))
gain_trauma_type(BRAIN_TRAUMA_SPECIAL)
else
gain_trauma_type(BRAIN_TRAUMA_SEVERE)
if(prev_brainloss < BRAIN_DAMAGE_MILD && brainloss >= BRAIN_DAMAGE_MILD)
to_chat(src, "<span class='warning'>You feel lightheaded.</span>")
else if(prev_brainloss < BRAIN_DAMAGE_SEVERE && brainloss >= BRAIN_DAMAGE_SEVERE)
to_chat(src, "<span class='warning'>You feel less in control of your thoughts.</span>")
else if(prev_brainloss < (BRAIN_DAMAGE_DEATH - 20) && brainloss >= (BRAIN_DAMAGE_DEATH - 20))
to_chat(src, "<span class='warning'>You can feel your mind flickering on and off...</span>")
/mob/living/carbon/setBrainLoss(amount)
var/obj/item/organ/brain/B = getorganslot(ORGAN_SLOT_BRAIN)
if(B)
var/adjusted_amount = amount - B.get_brain_damage()
B.adjust_brain_damage(adjusted_amount, null)
*/
///Returns a list of bodyparts with wounds (in case someone has a wound on an otherwise fully healed limb)
/mob/living/carbon/proc/get_wounded_bodyparts(brute = FALSE, burn = FALSE, stamina = FALSE, status)
var/list/obj/item/bodypart/parts = list()
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
if(LAZYLEN(BP.wounds))
parts += BP
return parts
+65 -4
View File
@@ -31,14 +31,37 @@
else if(get_bodypart(BODY_ZONE_HEAD))
. += "<span class='deadsay'>It appears that [t_his] brain is missing...</span>"
var/list/missing = get_missing_limbs()
var/list/msg = list("<span class='warning'>")
var/list/missing = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)
var/list/disabled = list()
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
if(BP.disabled)
disabled += BP
missing -= BP.body_zone
for(var/obj/item/I in BP.embedded_objects)
if(I.isEmbedHarmless())
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"
for(var/t in missing)
if(t==BODY_ZONE_HEAD)
. += "<span class='deadsay'><B>[t_His] [parse_zone(t)] is missing!</B></span>"
msg += "<span class='deadsay'><B>[t_His] [parse_zone(t)] is missing!</B></span>\n"
continue
. += "<span class='warning'><B>[t_His] [parse_zone(t)] is missing!</B></span>"
msg += "<span class='warning'><B>[t_His] [parse_zone(t)] is missing!</B></span>\n"
var/list/msg = list()
var/temp = getBruteLoss()
if(!(user == src && src.hal_screwyhud == SCREWYHUD_HEALTHY)) //fake healthy
if(temp)
@@ -78,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>"
@@ -114,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)
// depending on the species, it will run the corresponding apply_damage code there
return dna.species.apply_damage(damage, damagetype, def_zone, blocked, src, forced)
@@ -4,6 +4,10 @@
status_flags = GODMODE|CANPUSH
mouse_drag_pointer = MOUSE_INACTIVE_POINTER
var/in_use = FALSE
vore_flags = NO_VORE
/mob/living/carbon/human/vore
vore_flags = DEVOURABLE | DIGESTABLE | FEEDING
INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
+59 -15
View File
@@ -159,17 +159,22 @@
disabled += BP
missing -= BP.body_zone
for(var/obj/item/I in BP.embedded_objects)
msg += "<B>[t_He] [t_has] \a [icon2html(I, user)] [I] embedded in [t_his] [BP.name]!</B>\n"
if(I.isEmbedHarmless())
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
@@ -243,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"
@@ -328,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>"
+55 -53
View File
@@ -33,6 +33,7 @@
enable_intentional_sprint_mode()
RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /atom.proc/clean_blood)
GLOB.human_list += src
/mob/living/carbon/human/ComponentInitialize()
@@ -47,6 +48,7 @@
/mob/living/carbon/human/Destroy()
QDEL_NULL(physiology)
QDEL_NULL_LIST(vore_organs) // CITADEL EDIT belly stuff
GLOB.human_list -= src
return ..()
/mob/living/carbon/human/prepare_data_huds()
@@ -152,8 +154,12 @@
dat += "<tr><td>&nbsp;</td></tr>"
dat += "<tr><td><B>Exosuit:</B></td><td><A href='?src=[REF(src)];item=[SLOT_WEAR_SUIT]'>[(wear_suit && !(wear_suit.item_flags & ABSTRACT)) ? wear_suit : "<font color=grey>Empty</font>"]</A></td></tr>"
dat += "<tr><td><B>Exosuit:</B></td><td><A href='?src=[REF(src)];item=[SLOT_WEAR_SUIT]'>[(wear_suit && !(wear_suit.item_flags & ABSTRACT)) ? wear_suit : "<font color=grey>Empty</font>"]</A>"
if(wear_suit)
if(istype(wear_suit, /obj/item/clothing/suit/space/hardsuit))
var/hardsuit_head = head && istype(head, /obj/item/clothing/head/helmet/space/hardsuit)
dat += "&nbsp;<A href='?src=[REF(src)];toggle_helmet=[SLOT_WEAR_SUIT]'>[hardsuit_head ? "Retract Helmet" : "Extend Helmet"]</A>"
dat += "</td></tr>"
dat += "<tr><td>&nbsp;&#8627;<B>Suit Storage:</B></td><td><A href='?src=[REF(src)];item=[SLOT_S_STORE]'>[(s_store && !(s_store.item_flags & ABSTRACT)) ? s_store : "<font color=grey>Empty</font>"]</A>"
if(has_breathable_mask && istype(s_store, /obj/item/tank))
dat += "&nbsp;<A href='?src=[REF(src)];internal=[SLOT_S_STORE]'>[internal ? "Disable Internals" : "Set Internals"]</A>"
@@ -164,7 +170,11 @@
if(SLOT_SHOES in obscured)
dat += "<tr><td><font color=grey><B>Shoes:</B></font></td><td><font color=grey>Obscured</font></td></tr>"
else
dat += "<tr><td><B>Shoes:</B></td><td><A href='?src=[REF(src)];item=[SLOT_SHOES]'>[(shoes && !(shoes.item_flags & ABSTRACT)) ? shoes : "<font color=grey>Empty</font>"]</A></td></tr>"
dat += "<tr><td><B>Shoes:</B></td><td><A href='?src=[REF(src)];item=[SLOT_SHOES]'>[(shoes && !(shoes.item_flags & ABSTRACT)) ? shoes : "<font color=grey>Empty</font>"]</A>"
if(shoes && shoes.can_be_tied && shoes.tied != SHOES_KNOTTED)
dat += "&nbsp;<A href='?src=[REF(src)];shoes=[SLOT_SHOES]'>[shoes.tied ? "Untie shoes" : "Knot shoes"]</A>"
dat += "</td></tr>"
if(SLOT_GLOVES in obscured)
dat += "<tr><td><font color=grey><B>Gloves:</B></font></td><td><font color=grey>Obscured</font></td></tr>"
@@ -220,30 +230,30 @@
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 person anymore
return
var/time_taken = I.embedding.embedded_unsafe_removal_time/I.w_class //Citadel Change from * to /
usr.visible_message("<span class='warning'>[usr] attempts to remove [I] from [usr.p_their()] [L.name].</span>","<span class='notice'>You attempt to remove [I] from your [L.name]... (It will take [DisplayTimeText(time_taken)].)</span>")
if(do_after(usr, time_taken, needhand = 1, target = src))
remove_embedded_unsafe(L, I, usr)
/* CITADEL EDIT: remove_embedded_unsafe replaces this code
if(!I || !L || I.loc != src || !(I in L.embedded_objects))
return
L.embedded_objects -= I
L.receive_damage(I.embedding.embedded_unsafe_removal_pain_multiplier*I.w_class)//It hurts to rip it out, get surgery you dingus.
I.forceMove(get_turf(src))
usr.put_in_hands(I)
usr.emote("scream")
usr.visible_message("[usr] successfully rips [I] out of [usr.p_their()] [L.name]!","<span class='notice'>You successfully remove [I] from your [L.name].</span>")
if(!has_embedded_objects())
clear_alert("embeddedobject")
SEND_SIGNAL(usr, COMSIG_CLEAR_MOOD_EVENT, "embedded") */
SEND_SIGNAL(src, COMSIG_CARBON_EMBED_RIP, I, L)
return
if(href_list["toggle_helmet"])
if(!istype(head, /obj/item/clothing/head/helmet/space/hardsuit))
return
var/obj/item/clothing/head/helmet/space/hardsuit/hardsuit_head = head
visible_message("<span class='danger'>[usr] tries to [hardsuit_head ? "retract" : "extend"] [src]'s helmet.</span>", \
"<span class='userdanger'>[usr] tries to [hardsuit_head ? "retract" : "extend"] [src]'s helmet.</span>", \
target = usr, target_message = "<span class='danger'>You try to [hardsuit_head ? "retract" : "extend"] [src]'s helmet.</span>")
if(!do_mob(usr, src, hardsuit_head ? head.strip_delay : POCKET_STRIP_DELAY))
return
if(!istype(wear_suit, /obj/item/clothing/suit/space/hardsuit) || (hardsuit_head ? (!head || head != hardsuit_head) : head))
return
var/obj/item/clothing/suit/space/hardsuit/hardsuit = wear_suit //This should be an hardsuit given all our checks
if(hardsuit.ToggleHelmet(FALSE))
visible_message("<span class='danger'>[usr] [hardsuit_head ? "retract" : "extend"] [src]'s helmet</span>", \
"<span class='userdanger'>[usr] [hardsuit_head ? "retract" : "extend"] [src]'s helmet</span>", \
target = usr, target_message = "<span class='danger'>You [hardsuit_head ? "retract" : "extend"] [src]'s helmet.</span>")
return
if(href_list["item"])
var/slot = text2num(href_list["item"])
if(slot in check_obscured_slots())
to_chat(usr, "<span class='warning'>You can't reach that! Something is covering it.</span>")
return
if(href_list["pockets"])
var/strip_mod = 1
var/strip_silence = FALSE
@@ -288,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
@@ -384,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)
@@ -526,33 +542,15 @@
// Might need re-wording.
to_chat(user, "<span class='alert'>There is no exposed flesh or thin material [above_neck(target_zone) ? "on [p_their()] head" : "on [p_their()] body"].</span>")
/mob/living/carbon/human/proc/check_obscured_slots()
var/list/obscured = list()
/mob/living/carbon/human/check_obscured_slots()
. = ..()
if(wear_suit)
if(wear_suit.flags_inv & HIDEGLOVES)
obscured |= SLOT_GLOVES
LAZYOR(., SLOT_GLOVES)
if(wear_suit.flags_inv & HIDEJUMPSUIT)
obscured |= SLOT_W_UNIFORM
LAZYOR(., SLOT_W_UNIFORM)
if(wear_suit.flags_inv & HIDESHOES)
obscured |= SLOT_SHOES
if(head)
if(head.flags_inv & HIDEMASK)
obscured |= SLOT_WEAR_MASK
if(head.flags_inv & HIDEEYES)
obscured |= SLOT_GLASSES
if(head.flags_inv & HIDEEARS)
obscured |= SLOT_EARS
if(wear_mask)
if(wear_mask.flags_inv & HIDEEYES)
obscured |= SLOT_GLASSES
if(obscured.len)
return obscured
else
return null
LAZYOR(., SLOT_SHOES)
/mob/living/carbon/human/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null)
if(judgement_criteria & JUDGE_EMAGGED)
@@ -747,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
..()
@@ -997,7 +994,7 @@
if(target.incapacitated(FALSE, TRUE) || incapacitated(FALSE, TRUE))
target.visible_message("<span class='warning'>[target] can't hang onto [src]!</span>")
return
buckle_mob(target, TRUE, TRUE, FALSE, 0, 2, FALSE)
buckle_mob(target, TRUE, TRUE, FALSE, 1, 2, FALSE)
else
visible_message("<span class='warning'>[target] fails to climb onto [src]!</span>")
else
@@ -1043,12 +1040,6 @@
return TRUE
return FALSE
/mob/living/carbon/human/proc/clear_shove_slowdown()
remove_movespeed_modifier(/datum/movespeed_modifier/shove)
var/active_item = get_active_held_item()
if(is_type_in_typecache(active_item, GLOB.shove_disarming_types))
visible_message("<span class='warning'>[src.name] regains their grip on \the [active_item]!</span>", "<span class='warning'>You regain your grip on \the [active_item]</span>", null, COMBAT_MESSAGE_RANGE)
/mob/living/carbon/human/updatehealth()
. = ..()
@@ -1069,10 +1060,21 @@
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying)
/mob/living/carbon/human/do_after_coefficent()
. = ..()
. *= physiology.do_after_speed
/mob/living/carbon/human/is_bleeding()
if(NOBLOOD in dna.species.species_traits || bleedsuppress)
return FALSE
return ..()
/mob/living/carbon/human/get_total_bleed_rate()
if(NOBLOOD in dna.species.species_traits)
return FALSE
return ..()
/mob/living/carbon/human/species
var/race = null
@@ -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)
@@ -52,11 +65,6 @@
return martial_art_result
return ..()
/mob/living/carbon/human/can_embed(obj/item/I)
if(I.get_sharpness() || is_pointed(I) || is_type_in_typecache(I, GLOB.can_embed_types))
return TRUE
return FALSE
/mob/living/carbon/human/proc/check_martial_melee_block()
if(mind)
if(mind.martial_art && prob(mind.martial_art.block_chance) && mind.martial_art.can_use(src) && in_throw_mode && !incapacitated(FALSE, TRUE))
@@ -111,18 +119,21 @@
visible_message("<span class='danger'>[user] [hulk_verb_continous] [src]!</span>", \
"<span class='userdanger'>[user] [hulk_verb_continous] you!</span>", null, COMBAT_MESSAGE_RANGE, null, user,
"<span class='danger'>You [hulk_verb_simple] [src]!</span>")
adjustBruteLoss(15)
apply_damage(15, BRUTE, wound_bonus=10)
return 1
/mob/living/carbon/human/attack_hand(mob/user)
/mob/living/carbon/human/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.) //To allow surgery to return properly.
return
if(ishuman(user))
var/mob/living/carbon/human/H = user
dna.species.spec_attack_hand(H, src)
dna.species.spec_attack_hand(H, src, null, act_intent, unarmed_attack_flags)
/mob/living/carbon/human/attack_paw(mob/living/carbon/monkey/M)
if(!M.CheckActionCooldown(CLICK_CD_MELEE))
return
M.DelayNextAction()
var/dam_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
if(!affecting)
@@ -222,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
@@ -241,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)
@@ -619,14 +631,48 @@
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)
to_send += "\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>\n"
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>")
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"
@@ -719,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)
@@ -7,12 +7,14 @@
buckle_lying = FALSE
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
/// Enable stamina combat
combat_flags = COMBAT_FLAGS_DEFAULT
combat_flags = COMBAT_FLAGS_DEFAULT | COMBAT_FLAG_UNARMED_PARRY
status_flags = CANSTUN|CANKNOCKDOWN|CANUNCONSCIOUS|CANPUSH|CANSTAGGER
has_field_of_vision = FALSE //Handled by species.
blocks_emissive = EMISSIVE_BLOCK_UNIQUE
block_parry_data = /datum/block_parry_data/unarmed/human
//Hair colour and style
var/hair_color = "000"
var/hair_style = "Bald"
@@ -49,7 +51,6 @@
var/special_voice = "" // For changing our voice. Used by a symptom.
var/bleed_rate = 0 //how much are we bleeding
var/bleedsuppress = 0 //for stopping bloodloss, eventually this will be limb-based like bleeding
var/blood_state = BLOOD_STATE_NOT_BLOODY
@@ -71,3 +72,45 @@
var/lastpuke = 0
var/account_id
var/last_fire_update
/// Unarmed parry data for human
/datum/block_parry_data/unarmed/human
parry_respect_clickdelay = TRUE
parry_stamina_cost = 4
parry_attack_types = ATTACK_TYPE_UNARMED
parry_flags = PARRY_DEFAULT_HANDLE_FEEDBACK | PARRY_LOCK_ATTACKING
parry_time_windup = 0
parry_time_spindown = 1
parry_time_active = 5
parry_time_perfect = 1
parry_time_perfect_leeway = 1
parry_imperfect_falloff_percent = 20
parry_efficiency_perfect = 100
parry_efficiency_considered_successful = 0.01
parry_efficiency_to_counterattack = 0.01
parry_max_attacks = 3
parry_cooldown = 30
parry_failed_stagger_duration = 0
parry_failed_clickcd_duration = 0.4
parry_data = list( // yeah it's snowflake
"HUMAN_PARRY_STAGGER" = 3 SECONDS,
"HUMAN_PARRY_PUNCH" = TRUE,
"HUMAN_PARRY_MININUM_EFFICIENCY" = 0.9
)
/mob/living/carbon/human/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time)
var/datum/block_parry_data/D = return_block_parry_datum(block_parry_data)
if(!owner.Adjacent(attacker))
return ..()
if(parry_efficiency < D.parry_data["HUMAN_PARRY_MINIMUM_EFFICIENCY"])
return ..()
visible_message("<span class='warning'>[src] strikes back perfectly at [attacker], staggering them!</span>")
if(D.parry_data["HUMAN_PARRY_PUNCH"])
UnarmedAttack(attacker, TRUE, INTENT_HARM, ATTACK_IS_PARRY_COUNTERATTACK | ATTACK_IGNORE_ACTION | ATTACK_IGNORE_CLICKDELAY | NO_AUTO_CLICKDELAY_HANDLING)
var/mob/living/L = attacker
if(istype(L))
L.Stagger(D.parry_data["HUMAN_PARRY_STAGGER"])
@@ -151,3 +151,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]))
@@ -36,8 +36,9 @@
return FALSE
return ..()
/mob/living/carbon/human/experience_pressure_difference()
playsound(src, 'sound/effects/space_wind.ogg', 50, 1)
/mob/living/carbon/human/experience_pressure_difference(pressure_difference, direction, pressure_resistance_prob_delta = 0, throw_target)
if(prob(pressure_difference * 2.5))
playsound(src, 'sound/effects/space_wind.ogg', 50, 1)
if(shoes && istype(shoes, /obj/item/clothing))
var/obj/item/clothing/S = shoes
if (S.clothing_flags & NOSLIP)
@@ -58,7 +59,7 @@
. = ..()
for(var/datum/mutation/human/HM in dna.mutations)
HM.on_move(NewLoc)
if(. && (combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) && !(movement_type & FLYING) && CHECK_ALL_MOBILITY(src, MOBILITY_MOVE|MOBILITY_STAND) && m_intent == MOVE_INTENT_RUN && has_gravity(loc) && !pulledby)
if(. && (combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) && !(movement_type & FLYING) && CHECK_ALL_MOBILITY(src, MOBILITY_MOVE|MOBILITY_STAND) && m_intent == MOVE_INTENT_RUN && has_gravity(loc) && (!pulledby || (pulledby.pulledby == src)))
if(!HAS_TRAIT(src, TRAIT_FREESPRINT))
doSprintLossTiles(1)
if((oldpseudoheight - pseudo_z_axis) >= 8)
@@ -77,7 +78,7 @@
var/turf/T = get_turf(src)
if(S.bloody_shoes && S.bloody_shoes[S.blood_state])
var/obj/effect/decal/cleanable/blood/footprints/oldFP = locate(/obj/effect/decal/cleanable/blood/footprints) in T
if(oldFP && (oldFP.blood_state == S.blood_state && oldFP.color == bloodtype_to_color(S.last_bloodtype)))
if(oldFP && (oldFP.blood_state == S.blood_state && oldFP.color == S.last_blood_color))
return
S.bloody_shoes[S.blood_state] = max(0, S.bloody_shoes[S.blood_state] - BLOOD_LOSS_PER_STEP)
var/obj/effect/decal/cleanable/blood/footprints/FP = new /obj/effect/decal/cleanable/blood/footprints(T)
@@ -85,7 +86,11 @@
FP.entered_dirs |= dir
FP.bloodiness = S.bloody_shoes[S.blood_state]
if(S.last_bloodtype)
FP.blood_DNA += list(S.last_blood_DNA = S.last_bloodtype)
FP.blood_DNA[S.last_blood_DNA] = S.last_bloodtype
if(!FP.blood_DNA["color"])
FP.blood_DNA["color"] = S.last_blood_color
else
FP.blood_DNA["color"] = BlendRGB(FP.blood_DNA["color"], S.last_blood_color)
FP.update_icon()
update_inv_shoes()
//End bloody footprints
@@ -1,5 +1,32 @@
/mob/living/carbon/human/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
return dna.species.can_equip(I, slot, disable_warning, src, bypass_equip_delay_self)
/mob/living/carbon/human/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, clothing_check = FALSE, list/return_warning)
return dna.species.can_equip(I, slot, disable_warning, src, bypass_equip_delay_self, clothing_check, return_warning)
/mob/living/carbon/human/get_equipped_items(include_pockets = FALSE)
var/list/items = ..()
if(belt)
items += belt
if(ears)
items += ears
if(glasses)
items += glasses
if(gloves)
items += gloves
if(shoes)
items += shoes
if(wear_id)
items += wear_id
if(wear_suit)
items += wear_suit
if(w_uniform)
items += w_uniform
if(include_pockets)
if(l_store)
items += l_store
if(r_store)
items += r_store
if(s_store)
items += s_store
return items
// Return the item currently in the slot ID
/mob/living/carbon/human/get_item_by_slot(slot_id)
+10 -44
View File
@@ -18,36 +18,21 @@
#define THERMAL_PROTECTION_HAND_LEFT 0.025
#define THERMAL_PROTECTION_HAND_RIGHT 0.025
/mob/living/carbon/human/Life(seconds, times_fired)
set invisibility = 0
if (notransform)
/mob/living/carbon/human/BiologicalLife(seconds, times_fired)
if(!(. = ..()))
return
handle_active_genes()
//heart attack stuff
handle_heart()
dna.species.spec_life(src) // for mutantraces
return (stat != DEAD) && !QDELETED(src)
. = ..()
if (QDELETED(src))
return 0
if(.) //not dead
handle_active_genes()
if(stat != DEAD)
//heart attack stuff
handle_heart()
if(stat != DEAD)
//Stuff jammed in your limbs hurts
handle_embedded_objects()
/mob/living/carbon/human/PhysicalLife(seconds, times_fired)
if(!(. = ..()))
return
//Update our name based on whether our face is obscured/disfigured
name = get_visible_name()
dna.species.spec_life(src) // for mutantraces
if(stat != DEAD)
return 1
/mob/living/carbon/human/calculate_affecting_pressure(pressure)
var/headless = !get_bodypart(BODY_ZONE_HEAD) //should the mob be perennially headless (see dullahans), we only take the suit into account, so they can into space.
if (wear_suit && istype(wear_suit, /obj/item/clothing) && (headless || (head && istype(head, /obj/item/clothing))))
@@ -303,25 +288,6 @@
return TRUE
return ..()
/mob/living/carbon/human/proc/handle_embedded_objects()
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
for(var/obj/item/I in BP.embedded_objects)
if(prob(I.embedding.embedded_pain_chance))
BP.receive_damage(I.w_class*I.embedding.embedded_pain_multiplier)
to_chat(src, "<span class='userdanger'>[I] embedded in your [BP.name] hurts!</span>")
if(prob(I.embedding.embedded_fall_chance))
BP.receive_damage(I.w_class*I.embedding.embedded_fall_pain_multiplier)
BP.embedded_objects -= I
I.forceMove(drop_location())
I.unembedded()
visible_message("<span class='danger'>[I] falls out of [name]'s [BP.name]!</span>","<span class='userdanger'>[I] falls out of your [BP.name]!</span>")
if(!has_embedded_objects())
clear_alert("embeddedobject")
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "embedded")
/mob/living/carbon/human/proc/handle_active_genes()
if(HAS_TRAIT(src, TRAIT_MUTATION_STASIS))
return
@@ -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")
+116 -72
View File
@@ -7,7 +7,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/id // if the game needs to manually check your race to do something not included in a proc here, it will use this
var/limbs_id //this is used if you want to use a different species limb sprites. Mainly used for angels as they look like humans.
var/name // this is the fluff name. these will be left generic (such as 'Lizardperson' for the lizard race) so servers can change them to whatever
var/default_color = "#FFF" // if alien colors are disabled, this is the color that will be used by that race
var/default_color = "#FFFFFF" // if alien colors are disabled, this is the color that will be used by that race
var/sexes = 1 // whether or not the race has sexual characteristics. at the moment this is only 0 for skeletons and shadows
var/has_field_of_vision = TRUE
@@ -39,6 +39,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/use_skintones = NO_SKINTONES // does it use skintones or not? (spoiler alert this is only used by humans)
var/exotic_blood = "" // If your race wants to bleed something other than bog standard blood, change this to reagent id.
var/exotic_bloodtype = "" //If your race uses a non standard bloodtype (A+, O-, AB-, etc)
var/exotic_blood_color = BLOOD_COLOR_HUMAN //assume human as the default blood colour, override this default by species subtypes
var/meat = /obj/item/reagent_containers/food/snacks/meat/slab/human //What the species drops on gibbing
var/list/gib_types = list(/obj/effect/gibspawner/human, /obj/effect/gibspawner/human/bodypartless)
var/skinned_type
@@ -72,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
@@ -104,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
@@ -112,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()
@@ -381,7 +384,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
//keep it at the right spot, so we can't have people taking shortcuts
var/location = C.dna.mutation_index.Find(inert_mutation)
C.dna.mutation_index[location] = new_species.inert_mutation
C.dna.default_mutation_genes[location] = C.dna.mutation_index[location]
C.dna.mutation_index[new_species.inert_mutation] = create_sequence(new_species.inert_mutation)
C.dna.default_mutation_genes[new_species.inert_mutation] = C.dna.mutation_index[new_species.inert_mutation]
if(!new_species.has_field_of_vision && has_field_of_vision && ishuman(C) && CONFIG_GET(flag/use_field_of_vision))
var/datum/component/field_of_vision/F = C.GetComponent(/datum/component/field_of_vision)
@@ -851,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
@@ -1028,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.
*/
@@ -1059,17 +1063,23 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.adjustBruteLoss(1)
/datum/species/proc/spec_death(gibbed, mob/living/carbon/human/H)
return
if(H)
stop_wagging_tail(H)
/datum/species/proc/auto_equip(mob/living/carbon/human/H)
// handles the equipping of species-specific gear
return
/datum/species/proc/can_equip(obj/item/I, slot, disable_warning, mob/living/carbon/human/H, bypass_equip_delay_self = FALSE)
/datum/species/proc/can_equip(obj/item/I, slot, disable_warning, mob/living/carbon/human/H, bypass_equip_delay_self = FALSE, clothing_check = FALSE, list/return_warning)
if(slot in no_equip)
if(!I.species_exception || !is_type_in_list(src, I.species_exception))
return FALSE
if(clothing_check && (slot in H.check_obscured_slots()))
if(return_warning)
return_warning[1] = "<span class='warning'>You are unable to equip that with your current garments in the way!</span>"
return FALSE
var/num_arms = H.get_num_arms(FALSE)
var/num_legs = H.get_num_legs(FALSE)
@@ -1131,8 +1141,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(!CHECK_BITFIELD(I.item_flags, NO_UNIFORM_REQUIRED))
var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_CHEST)
if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC))
if(!disable_warning)
to_chat(H, "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>")
if(return_warning)
return_warning[1] = "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>"
return FALSE
if(!(I.slot_flags & ITEM_SLOT_BELT))
return
@@ -1173,8 +1183,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(!CHECK_BITFIELD(I.item_flags, NO_UNIFORM_REQUIRED))
var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_CHEST)
if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC))
if(!disable_warning)
to_chat(H, "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>")
if(return_warning)
return_warning[1] = "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>"
return FALSE
if( !(I.slot_flags & ITEM_SLOT_ID) )
return FALSE
@@ -1188,8 +1198,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_L_LEG)
if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC))
if(!disable_warning)
to_chat(H, "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>")
if(return_warning)
return_warning[1] = "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>"
return FALSE
if(I.slot_flags & ITEM_SLOT_DENYPOCKET)
return FALSE
@@ -1204,8 +1214,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_R_LEG)
if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC))
if(!disable_warning)
to_chat(H, "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>")
if(return_warning)
return_warning[1] = "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>"
return FALSE
if(I.slot_flags & ITEM_SLOT_DENYPOCKET)
return FALSE
@@ -1218,16 +1228,16 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(H.s_store)
return FALSE
if(!H.wear_suit)
if(!disable_warning)
to_chat(H, "<span class='warning'>You need a suit before you can attach this [I.name]!</span>")
if(return_warning)
return_warning[1] = "<span class='warning'>You need a suit before you can attach this [I.name]!</span>"
return FALSE
if(!H.wear_suit.allowed)
if(!disable_warning)
to_chat(H, "You somehow have a suit with no defined allowed items for suit storage, stop that.")
if(return_warning)
return_warning[1] = "You somehow have a suit with no defined allowed items for suit storage, stop that."
return FALSE
if(I.w_class > WEIGHT_CLASS_BULKY)
if(!disable_warning)
to_chat(H, "The [I.name] is too big to attach.") //should be src?
if(return_warning)
return_warning[1] = "The [I.name] is too big to attach."
return FALSE
if( istype(I, /obj/item/pda) || istype(I, /obj/item/pen) || is_type_in_list(I, H.wear_suit.allowed) )
return TRUE
@@ -1277,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))
@@ -1438,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)
/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
@@ -1450,10 +1460,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
target_message = "<span class='warning'>[target] blocks your attack!</span>")
return FALSE
if(HAS_TRAIT(user, TRAIT_PUGILIST))//CITADEL CHANGE - makes punching cause staminaloss but funny martial artist types get a discount
user.adjustStaminaLossBuffered(1.5)
else
user.adjustStaminaLossBuffered(3.5)
if(!(attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK))
if(HAS_TRAIT(user, TRAIT_PUGILIST))//CITADEL CHANGE - makes punching cause staminaloss but funny martial artist types get a discount
user.adjustStaminaLossBuffered(1.5)
else
user.adjustStaminaLossBuffered(3.5)
if(attacker_style && attacker_style.harm_act(user,target))
return TRUE
@@ -1481,23 +1492,26 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
//CITADEL CHANGES - makes resting and disabled combat mode reduce punch damage, makes being out of combat mode result in you taking more damage
if(!SEND_SIGNAL(target, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
damage *= 1.5
damage *= 1.2
if(!CHECK_MOBILITY(user, MOBILITY_STAND))
damage *= 0.5
damage *= 0.8
if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
damage *= 0.25
damage *= 0.8
//END OF CITADEL CHANGES
var/obj/item/bodypart/affecting = target.get_bodypart(ran_zone(user.zone_selected))
var/miss_chance = 100//calculate the odds that a punch misses entirely. considers stamina and brute damage of the puncher. punches miss by default to prevent weird cases
if(user.dna.species.punchdamagelow)
if(HAS_TRAIT(user, TRAIT_PUGILIST)) //pugilists have a flat 10% miss chance
miss_chance = 10
if(atk_verb == ATTACK_EFFECT_KICK) //kicks never miss (provided your species deals more than 0 damage)
miss_chance = 0
else
miss_chance = min(10 + ((puncherstam + puncherbrute)*0.5), 100) //probability of miss has a base of 10, and modified based on half brute total. Capped at max 100 to prevent weirdness in prob()
if(attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)
miss_chance = 0
else
if(user.dna.species.punchdamagelow)
if(atk_verb == ATTACK_EFFECT_KICK) //kicks never miss (provided your species deals more than 0 damage)
miss_chance = 0
else if(HAS_TRAIT(user, TRAIT_PUGILIST)) //pugilists have a flat 10% miss chance
miss_chance = 10
else
miss_chance = min(10 + max(puncherstam * 0.5, puncherbrute * 0.5), 100) //probability of miss has a base of 10, and modified based on half brute total. Capped at max 100 to prevent weirdness in prob()
if(!damage || !affecting || prob(miss_chance))//future-proofing for species that have 0 damage/weird cases where no zone is targeted
playsound(target.loc, user.dna.species.miss_sound, 25, TRUE, -1)
@@ -1675,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)
/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)
@@ -1687,7 +1701,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
attacker_style = M.mind.martial_art
if(attacker_style?.pacifism_check && HAS_TRAIT(M, TRAIT_PACIFISM)) // most martial arts are quite harmful, alas.
attacker_style = null
switch(M.a_intent)
switch(act_intent)
if("help")
help(M, H, attacker_style)
@@ -1695,7 +1709,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
grab(M, H, attacker_style)
if("harm")
harm(M, H, attacker_style)
harm(M, H, attacker_style, attackchain_flags)
if("disarm")
disarm(M, H, attacker_style)
@@ -1705,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())
@@ -1722,11 +1736,17 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/armor_block = H.run_armor_check(affecting, "melee", "<span class='notice'>Your armor has protected your [hit_area].</span>", "<span class='notice'>Your armor has softened a hit to your [hit_area].</span>",I.armour_penetration)
armor_block = min(90,armor_block) //cap damage reduction at 90%
var/Iforce = I.force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords)
var/Iwound_bonus = I.wound_bonus
// this way, you can't wound with a surgical tool on help intent if they have a surgery active and are laying down, so a misclick with a circular saw on the wrong limb doesn't bleed them dry (they still get hit tho)
if((I.item_flags & SURGICAL_TOOL) && user.a_intent == INTENT_HELP && (H.mobility_flags & ~MOBILITY_STAND) && (LAZYLEN(H.surgeries) > 0))
Iwound_bonus = CANT_WOUND
var/weakness = H.check_weakness(I, user)
apply_damage(totitemdamage * weakness, I.damtype, def_zone, armor_block, H) //CIT CHANGE - replaces I.force with totitemdamage
apply_damage(totitemdamage * weakness, I.damtype, def_zone, armor_block, H, wound_bonus = Iwound_bonus, bare_wound_bonus = I.bare_wound_bonus, sharpness = I.get_sharpness())
H.send_item_attack_message(I, user, hit_area)
H.send_item_attack_message(I, user, hit_area, totitemdamage)
I.do_stagger_action(H, user, totitemdamage)
@@ -1810,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
@@ -1919,11 +1942,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
target.visible_message("<span class='danger'>[user.name] shoves [target.name]!</span>",
"<span class='danger'>[user.name] shoves you!</span>", null, COMBAT_MESSAGE_RANGE, null,
user, "<span class='danger'>You shove [target.name]!</span>")
target.Stagger(SHOVE_STAGGER_DURATION)
var/obj/item/target_held_item = target.get_active_held_item()
if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types))
target_held_item = null
if(!target.has_movespeed_modifier(/datum/movespeed_modifier/shove))
target.add_movespeed_modifier(/datum/movespeed_modifier/shove)
if(!target.has_status_effect(STATUS_EFFECT_OFF_BALANCE))
if(target_held_item)
if(!HAS_TRAIT(target_held_item, TRAIT_NODROP))
target.visible_message("<span class='danger'>[target.name]'s grip on \the [target_held_item] loosens!</span>",
@@ -1931,43 +1954,43 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
append_message += ", loosening their grip on [target_held_item]"
else
append_message += ", but couldn't loose their grip on [target_held_item]"
addtimer(CALLBACK(target, /mob/living/carbon/human/proc/clear_shove_slowdown), SHOVE_SLOWDOWN_LENGTH)
else if(target_held_item)
if(target.dropItemToGround(target_held_item))
target.visible_message("<span class='danger'>[target.name] drops \the [target_held_item]!!</span>",
"<span class='danger'>You drop \the [target_held_item]!!</span>", null, COMBAT_MESSAGE_RANGE)
append_message += ", causing them to drop [target_held_item]"
target.ShoveOffBalance(SHOVE_OFFBALANCE_DURATION)
log_combat(user, target, "shoved", append_message)
/datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, forced = FALSE)
SEND_SIGNAL(src, COMSIG_MOB_APPLY_DAMGE, damage, damagetype, def_zone)
/datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = 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)
return 0
var/obj/item/bodypart/BP = null
if(isbodypart(def_zone))
if(damagetype == STAMINA && istype(def_zone, /obj/item/bodypart/head))
BP = H.get_bodypart(check_zone(BODY_ZONE_CHEST))
if(!spread_damage)
if(isbodypart(def_zone))
if(damagetype == STAMINA && istype(def_zone, /obj/item/bodypart/head))
BP = H.get_bodypart(check_zone(BODY_ZONE_CHEST))
else
BP = def_zone
else
BP = def_zone
else
if(!def_zone)
def_zone = ran_zone(def_zone)
if(damagetype == STAMINA && def_zone == BODY_ZONE_HEAD)
def_zone = BODY_ZONE_CHEST
BP = H.get_bodypart(check_zone(def_zone))
if(!BP)
BP = H.bodyparts[1]
if(!def_zone)
def_zone = ran_zone(def_zone)
if(damagetype == STAMINA && def_zone == BODY_ZONE_HEAD)
def_zone = BODY_ZONE_CHEST
BP = H.get_bodypart(check_zone(def_zone))
if(!BP)
BP = H.bodyparts[1]
switch(damagetype)
if(BRUTE)
H.damageoverlaytemp = 20
var/damage_amount = forced ? damage : damage * hit_percent * brutemod * H.physiology.brute_mod
if(BP)
if(damage > 0 ? BP.receive_damage(damage_amount, 0) : BP.heal_damage(abs(damage_amount), 0))
if(BP.receive_damage(damage_amount, 0, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness))
H.update_damage_overlays()
if(HAS_TRAIT(H, TRAIT_MASO) && prob(damage_amount))
H.mob_climax(forced_climax=TRUE)
@@ -1978,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)
@@ -2208,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
//////////////
@@ -2231,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
@@ -1,10 +1,11 @@
/datum/species/insect
name = "Anthromorphic Insect"
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'
@@ -13,33 +14,9 @@
liked_food = MEAT | FRUIT
disliked_food = TOXIC
icon_limbs = DEFAULT_BODYPART_ICON_CITADEL
exotic_bloodtype = "BUG"
exotic_blood_color = BLOOD_COLOR_BUG
/datum/species/insect/spec_death(gibbed, mob/living/carbon/human/H)
if(H)
stop_wagging_tail(H)
/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.
@@ -89,11 +90,7 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
//These count in on_life ticks which should be 2 seconds per every increment of 1 in a perfect world.
var/dwarf_eth_ticker = 0 //Currently set =< 1, that means this will fire the proc around every 2 seconds
var/last_alcohol_spam
/obj/item/organ/dwarfgland/prepare_eat()
var/obj/S = ..()
S.reagents.add_reagent(/datum/reagent/consumable/ethanol, stored_alcohol/10)
return S
food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/ethanol = 10)
/obj/item/organ/dwarfgland/on_life() //Primary loop to hook into to start delayed loops for other loops..
. = ..()
@@ -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
@@ -11,6 +11,8 @@
disliked_food = null
liked_food = GROSS
exotic_bloodtype = "BUG"
exotic_blood_color = BLOOD_COLOR_BUG
species_type = "insect"
/datum/species/fly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
if(istype(chem, /datum/reagent/toxin/pestkiller))
@@ -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
@@ -422,9 +424,9 @@
else
reactive_teleport(H)
/datum/species/golem/bluespace/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
/datum/species/golem/bluespace/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style, act_intent, unarmed_attack_flags)
..()
if(world.time > last_teleport + teleport_cooldown && M != H && M.a_intent != INTENT_HELP)
if(world.time > last_teleport + teleport_cooldown && M != H && act_intent != INTENT_HELP)
reactive_teleport(H)
/datum/species/golem/bluespace/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
@@ -519,9 +521,9 @@
var/golem_name = "[uppertext(clown_name)]"
return golem_name
/datum/species/golem/bananium/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
/datum/species/golem/bananium/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style, act_intent, unarmed_attack_flags)
..()
if(world.time > last_banana + banana_cooldown && M != H && M.a_intent != INTENT_HELP)
if(world.time > last_banana + banana_cooldown && M != H && act_intent != INTENT_HELP)
new/obj/item/grown/bananapeel/specialpeel(get_turf(H))
last_banana = world.time
@@ -830,9 +832,9 @@
if(world.time > last_gong_time + gong_cooldown)
gong(H)
/datum/species/golem/bronze/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
/datum/species/golem/bronze/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style, act_intent, unarmed_attack_flags)
..()
if(world.time > last_gong_time + gong_cooldown && M.a_intent != INTENT_HELP)
if(world.time > last_gong_time + gong_cooldown && act_intent != INTENT_HELP)
gong(H)
/datum/species/golem/bronze/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
@@ -3,15 +3,16 @@
id = "human"
default_color = "FFFFFF"
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS_PARTSONLY,WINGCOLOR)
mutant_bodyparts = list("mcolor" = "FFF", "mcolor2" = "FFF","mcolor3" = "FFF","tail_human" = "None", "ears" = "None", "taur" = "None", "deco_wings" = "None")
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS_PARTSONLY,WINGCOLOR,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()
@@ -20,6 +20,8 @@
mutanteyes = /obj/item/organ/eyes/ipc
exotic_bloodtype = "HF"
exotic_blood_color = BLOOD_COLOR_OIL
species_type = "robotic"
var/datum/action/innate/monitor_change/screen
@@ -7,12 +7,13 @@
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)
exotic_blood = /datum/reagent/blood/jellyblood
exotic_bloodtype = "GEL"
exotic_blood_color = "BLOOD_COLOR_SLIME"
damage_overlay_type = ""
var/datum/action/innate/regenerate_limbs/regenerate_limbs
var/datum/action/innate/slime_change/slime_change //CIT CHANGE
@@ -22,6 +23,17 @@
heatmod = 0.5 // = 1/4x heat damage
burnmod = 0.5 // = 1/2x generic burn damage
species_language_holder = /datum/language_holder/jelly
mutant_brain = /obj/item/organ/brain/jelly
tail_type = "mam_tail"
wagging_type = "mam_waggingtail"
species_type = "jelly"
/obj/item/organ/brain/jelly
name = "slime nucleus"
desc = "A slimey membranous mass from a slime person"
icon_state = "brain-slime"
/datum/species/jelly/on_species_loss(mob/living/carbon/C)
if(regenerate_limbs)
@@ -41,6 +53,11 @@
slime_change.Grant(C) //CIT CHANGE
C.faction |= "slime"
/datum/species/jelly/handle_body(mob/living/carbon/human/H)
. = ..()
//update blood color to body color
exotic_blood_color = "#" + H.dna.features["mcolor"]
/datum/species/jelly/spec_life(mob/living/carbon/human/H)
if(H.stat == DEAD || HAS_TRAIT(H, TRAIT_NOMARROW)) //can't farm slime jelly from a dead slime/jelly person indefinitely, and no regeneration for blooduskers
return
@@ -115,33 +132,6 @@
return
to_chat(H, "<span class='warning'>...but there is not enough of you to go around! You must attain more mass to heal!</span>")
/datum/species/jelly/spec_death(gibbed, mob/living/carbon/human/H)
if(H)
stop_wagging_tail(H)
/datum/species/jelly/spec_stun(mob/living/carbon/human/H,amount)
if(H)
stop_wagging_tail(H)
. = ..()
/datum/species/jelly/can_wag_tail(mob/living/carbon/human/H)
return mutant_bodyparts["mam_tail"] || mutant_bodyparts["mam_waggingtail"]
/datum/species/jelly/is_wagging_tail(mob/living/carbon/human/H)
return mutant_bodyparts["mam_waggingtail"]
/datum/species/jelly/start_wagging_tail(mob/living/carbon/human/H)
if(mutant_bodyparts["mam_tail"])
mutant_bodyparts["mam_waggingtail"] = mutant_bodyparts["mam_tail"]
mutant_bodyparts -= "mam_tail"
H.update_body()
/datum/species/jelly/stop_wagging_tail(mob/living/carbon/human/H)
if(mutant_bodyparts["mam_waggingtail"])
mutant_bodyparts["mam_tail"] = mutant_bodyparts["mam_waggingtail"]
mutant_bodyparts -= "mam_waggingtail"
H.update_body()
////////////////////////////////////////////////////////SLIMEPEOPLE///////////////////////////////////////////////////////////////////
@@ -239,7 +229,7 @@
"<span class='notice'>You focus intently on moving your body while \
standing perfectly still...</span>")
H.notransform = TRUE
H.mob_transforming = TRUE
if(do_after(owner, delay=60, needhand=FALSE, target=owner, progress=TRUE))
if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
@@ -249,7 +239,7 @@
else
to_chat(H, "<span class='warning'>...but fail to stand perfectly still!</span>")
H.notransform = FALSE
H.mob_transforming = FALSE
/datum/action/innate/split_body/proc/make_dupe()
var/mob/living/carbon/human/H = owner
@@ -267,7 +257,7 @@
spare.Move(get_step(H.loc, pick(NORTH,SOUTH,EAST,WEST)))
H.blood_volume *= 0.45
H.notransform = 0
H.mob_transforming = 0
var/datum/species/jelly/slime/origin_datum = H.dna.species
origin_datum.bodies |= spare
@@ -301,7 +291,7 @@
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "slime_swap_body", name, 400, 400, master_ui, state)
ui = new(user, src, ui_key, "SlimeBodySwapper", name, 400, 400, master_ui, state)
ui.open()
/datum/action/innate/swap_body/ui_data(mob/user)
@@ -430,7 +420,7 @@
default_color = "00FFFF"
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR)
inherent_traits = list(TRAIT_TOXINLOVER)
mutant_bodyparts = list("mcolor" = "FFF", "mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_body_markings" = "Plain", "mam_snouts" = "None", "taur" = "None")
mutant_bodyparts = list("mcolor" = "FFFFFF", "mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_tail" = "None", "mam_ears" = "None", "mam_body_markings" = "Plain", "mam_snouts" = "None", "taur" = "None")
say_mod = "says"
hair_color = "mutcolor"
hair_alpha = 160 //a notch brighter so it blends better.
@@ -466,8 +456,9 @@
if(new_color)
var/temp_hsv = RGBtoHSV(new_color)
if(ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright
H.dna.features["mcolor"] = sanitize_hexcolor(new_color)
H.dna.features["mcolor"] = sanitize_hexcolor(new_color, 6)
H.update_body()
H.update_hair()
else
to_chat(H, "<span class='notice'>Invalid color. Your color is not bright enough.</span>")
else if(select_alteration == "Hair Style")
@@ -533,7 +524,7 @@
H.update_body()
else if (select_alteration == "Markings")
var/list/snowflake_markings_list = list()
var/list/snowflake_markings_list = list("None")
for(var/path in GLOB.mam_body_markings_list)
var/datum/sprite_accessory/mam_body_markings/instance = GLOB.mam_body_markings_list[path]
if(istype(instance, /datum/sprite_accessory))
@@ -544,8 +535,6 @@
new_mam_body_markings = input(H, "Choose your character's body markings:", "Marking Alteration") as null|anything in snowflake_markings_list
if(new_mam_body_markings)
H.dna.features["mam_body_markings"] = new_mam_body_markings
if(new_mam_body_markings == "None")
H.dna.features["mam_body_markings"] = "Plain"
for(var/X in H.bodyparts) //propagates the markings changes
var/obj/item/bodypart/BP = X
BP.update_limb(FALSE, H)
@@ -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
@@ -21,11 +21,16 @@
gib_types = list(/obj/effect/gibspawner/lizard, /obj/effect/gibspawner/lizard/bodypartless)
skinned_type = /obj/item/stack/sheet/animalhide/lizard
exotic_bloodtype = "L"
exotic_blood_color = BLOOD_COLOR_LIZARD
disliked_food = GRAIN | DAIRY
liked_food = GROSS | MEAT
inert_mutation = FIREBREATH
species_language_holder = /datum/language_holder/lizard
tail_type = "tail_lizard"
wagging_type = "waggingtail_lizard"
species_type = "lizard"
/datum/species/lizard/random_name(gender,unique,lastname)
if(unique)
return random_unique_lizard_name(gender)
@@ -37,41 +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
@@ -33,7 +35,7 @@
if((!istype(H.w_uniform, /obj/item/clothing/under/plasmaman) || !istype(H.head, /obj/item/clothing/head/helmet/space/plasmaman)) && !atmos_sealed)
if(environment)
if(environment.total_moles())
if(environment.gases[/datum/gas/oxygen] && (environment.gases[/datum/gas/oxygen]) >= 1) //Same threshhold that extinguishes fire
if(environment.get_moles(/datum/gas/oxygen) >= 1) //Same threshhold that extinguishes fire
H.adjust_fire_stacks(0.5)
if(!H.on_fire && H.fire_stacks > 0)
H.visible_message("<span class='danger'>[H]'s body reacts with the atmosphere and bursts into flames!</span>","<span class='userdanger'>Your body reacts with the atmosphere and bursts into flame!</span>")
@@ -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)
@@ -1,20 +1,30 @@
/datum/species/skeleton
// 2spooky
name = "Spooky Scary Skeleton"
name = "Skeleton"
id = "skeleton"
say_mod = "rattles"
blacklisted = 0
sexes = 0
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/skeleton
species_traits = list(NOBLOOD,NOGENITALS,NOAROUSAL)
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER)
inherent_traits = list(TRAIT_NOBREATH,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER)
inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID
mutanttongue = /obj/item/organ/tongue/bone
damage_overlay_type = ""//let's not show bloody wounds or burns over bones.
disliked_food = NONE
liked_food = GROSS | MEAT | RAW | DAIRY
brutemod = 1.25
burnmod = 1.25
/datum/species/skeleton/check_roundstart_eligible()
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)
brutemod = 1
burnmod = 1
..()
/datum/species/skeleton/greater/check_roundstart_eligible()
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
return TRUE
return ..()
@@ -27,4 +37,4 @@
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT, TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER)
/datum/species/skeleton/space/check_roundstart_eligible()
return FALSE
return FALSE
@@ -18,35 +18,8 @@
mutanteyes = /obj/item/organ/eyes/ipc
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
@@ -117,6 +117,18 @@
if(!QDELETED(src))
update_inv_legcuffed()
/mob/living/carbon/get_equipped_items(include_pockets = FALSE)
var/list/items = list()
if(back)
items += back
if(head)
items += head
if(wear_mask)
items += wear_mask
if(wear_neck)
items += wear_neck
return items
//handle stuff to update when a mob equips/unequips a mask.
/mob/living/proc/wear_mask_update(obj/item/clothing/C, toggle_off = 1)
update_inv_wear_mask()
+56 -55
View File
@@ -1,29 +1,27 @@
/mob/living/carbon/Life()
set invisibility = 0
if(notransform)
return
if(damageoverlaytemp)
damageoverlaytemp = 0
update_damage_hud()
/mob/living/carbon/BiologicalLife(seconds, times_fired)
//Updates the number of stored chemicals for powers
handle_changeling()
//Handles the unique mentabolism of bloodsuckers, look at /datum/antagonist/bloodsucker/proc/LifeTick()
handle_bloodsucker()
//Reagent processing needs to come before breathing, to prevent edge cases.
handle_organs()
. = ..()
if (QDELETED(src))
. = ..() // if . is false, we are dead.
if(stat == DEAD)
stop_sound_channel(CHANNEL_HEARTBEAT)
handle_death()
rot()
. = FALSE
if(!.)
return
if(.) //not dead
handle_blood()
handle_blood()
// handle_blood *could* kill us.
// we should probably have a better system for if we need to check for death or something in the future hmw
if(stat != DEAD)
var/bprv = handle_bodyparts()
if(bprv & BODYPART_LIFE_UPDATE_HEALTH)
updatehealth()
update_stamina()
doSprintBufferRegen()
if(stat != DEAD)
handle_brain_damage()
@@ -31,16 +29,13 @@
if(stat != DEAD)
handle_liver()
if(stat == DEAD)
stop_sound_channel(CHANNEL_HEARTBEAT)
handle_death()
rot()
//Updates the number of stored chemicals for powers
handle_changeling()
if(stat != DEAD)
return 1
/mob/living/carbon/PhysicalLife(seconds, times_fired)
if(!(. = ..()))
return
if(damageoverlaytemp)
damageoverlaytemp = 0
update_damage_hud()
//Procs called while dead
/mob/living/carbon/proc/handle_death()
@@ -169,12 +164,11 @@
var/SA_para_min = 1
var/SA_sleep_min = 5
var/oxygen_used = 0
var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME
var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.return_temperature())/BREATH_VOLUME
var/list/breath_gases = breath.gases
var/O2_partialpressure = (breath_gases[/datum/gas/oxygen]/breath.total_moles())*breath_pressure
var/Toxins_partialpressure = (breath_gases[/datum/gas/plasma]/breath.total_moles())*breath_pressure
var/CO2_partialpressure = (breath_gases[/datum/gas/carbon_dioxide]/breath.total_moles())*breath_pressure
var/O2_partialpressure = (breath.get_moles(/datum/gas/oxygen)/breath.total_moles())*breath_pressure
var/Toxins_partialpressure = (breath.get_moles(/datum/gas/plasma)/breath.total_moles())*breath_pressure
var/CO2_partialpressure = (breath.get_moles(/datum/gas/carbon_dioxide)/breath.total_moles())*breath_pressure
//OXYGEN
@@ -198,7 +192,7 @@
var/ratio = 1 - O2_partialpressure/safe_oxy_min
adjustOxyLoss(min(5*ratio, 3))
failed_last_breath = 1
oxygen_used = breath_gases[/datum/gas/oxygen]*ratio
oxygen_used = breath.get_moles(/datum/gas/oxygen)*ratio
else
adjustOxyLoss(3)
failed_last_breath = 1
@@ -210,12 +204,12 @@
o2overloadtime = 0 //reset our counter for this too
if(health >= crit_threshold)
adjustOxyLoss(-5)
oxygen_used = breath_gases[/datum/gas/oxygen]
oxygen_used = breath.get_moles(/datum/gas/oxygen)
clear_alert("not_enough_oxy")
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "suffocation")
breath_gases[/datum/gas/oxygen] -= oxygen_used
breath_gases[/datum/gas/carbon_dioxide] += oxygen_used
breath.adjust_moles(/datum/gas/oxygen, -oxygen_used)
breath.adjust_moles(/datum/gas/carbon_dioxide, oxygen_used)
//CARBON DIOXIDE
if(CO2_partialpressure > safe_co2_max)
@@ -234,15 +228,15 @@
//TOXINS/PLASMA
if(Toxins_partialpressure > safe_tox_max)
var/ratio = (breath_gases[/datum/gas/plasma]/safe_tox_max) * 10
var/ratio = (breath.get_moles(/datum/gas/plasma)/safe_tox_max) * 10
adjustToxLoss(clamp(ratio, MIN_TOXIC_GAS_DAMAGE, MAX_TOXIC_GAS_DAMAGE))
throw_alert("too_much_tox", /obj/screen/alert/too_much_tox)
else
clear_alert("too_much_tox")
//NITROUS OXIDE
if(breath_gases[/datum/gas/nitrous_oxide])
var/SA_partialpressure = (breath_gases[/datum/gas/nitrous_oxide]/breath.total_moles())*breath_pressure
if(breath.get_moles(/datum/gas/nitrous_oxide))
var/SA_partialpressure = (breath.get_moles(/datum/gas/nitrous_oxide)/breath.total_moles())*breath_pressure
if(SA_partialpressure > SA_para_min)
Unconscious(60)
if(SA_partialpressure > SA_sleep_min)
@@ -255,26 +249,26 @@
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "chemical_euphoria")
//BZ (Facepunch port of their Agent B)
if(breath_gases[/datum/gas/bz])
var/bz_partialpressure = (breath_gases[/datum/gas/bz]/breath.total_moles())*breath_pressure
if(breath.get_moles(/datum/gas/bz))
var/bz_partialpressure = (breath.get_moles(/datum/gas/bz)/breath.total_moles())*breath_pressure
if(bz_partialpressure > 1)
hallucination += 10
else if(bz_partialpressure > 0.01)
hallucination += 5
//TRITIUM
if(breath_gases[/datum/gas/tritium])
var/tritium_partialpressure = (breath_gases[/datum/gas/tritium]/breath.total_moles())*breath_pressure
if(breath.get_moles(/datum/gas/tritium))
var/tritium_partialpressure = (breath.get_moles(/datum/gas/tritium)/breath.total_moles())*breath_pressure
radiation += tritium_partialpressure/10
//NITRYL
if(breath_gases[/datum/gas/nitryl])
var/nitryl_partialpressure = (breath_gases[/datum/gas/nitryl]/breath.total_moles())*breath_pressure
if(breath.get_moles(/datum/gas/nitryl))
var/nitryl_partialpressure = (breath.get_moles(/datum/gas/nitryl)/breath.total_moles())*breath_pressure
adjustFireLoss(nitryl_partialpressure/4)
//MIASMA
if(breath_gases[/datum/gas/miasma])
var/miasma_partialpressure = (breath_gases[/datum/gas/miasma]/breath.total_moles())*breath_pressure
if(breath.get_moles(/datum/gas/miasma))
var/miasma_partialpressure = (breath.get_moles(/datum/gas/miasma)/breath.total_moles())*breath_pressure
if(miasma_partialpressure > MINIMUM_MOLES_DELTA_TO_MOVE)
if(prob(0.05 * miasma_partialpressure))
@@ -314,11 +308,6 @@
else
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "smell")
GAS_GARBAGE_COLLECT(breath.gases)
//BREATH TEMPERATURE
handle_breath_temperature(breath)
@@ -377,9 +366,9 @@
var/datum/gas_mixture/stank = new
stank.gases[/datum/gas/miasma] = 0.1
stank.set_moles(/datum/gas/miasma,0.1)
stank.temperature = BODYTEMP_NORMAL
stank.set_temperature(BODYTEMP_NORMAL)
miasma_turf.assume_air(stank)
@@ -417,6 +406,12 @@
if(stat != DEAD || D.process_dead)
D.stage_act()
/mob/living/carbon/handle_wounds()
for(var/thing in all_wounds)
var/datum/wound/W = thing
if(W.processes) // meh
W.handle_process()
//todo generalize this and move hud out
/mob/living/carbon/proc/handle_changeling()
if(mind && hud_used && hud_used.lingchemdisplay)
@@ -429,6 +424,12 @@
hud_used.lingchemdisplay.invisibility = INVISIBILITY_ABSTRACT
/mob/living/carbon/proc/handle_bloodsucker()
if(mind && AmBloodsucker(src))
var/datum/antagonist/bloodsucker/B = mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
B.LifeTick()
/mob/living/carbon/handle_mutations_and_radiation()
if(dna && dna.temporary_mutations.len)
for(var/mut in dna.temporary_mutations)
@@ -524,7 +525,7 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put
/mob/living/carbon/handle_status_effects()
..()
if(getStaminaLoss() && !SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE)) //CIT CHANGE - prevents stamina regen while combat mode is active
adjustStaminaLoss(!CHECK_MOBILITY(src, MOBILITY_STAND) ? ((combat_flags & COMBAT_FLAG_HARD_STAMCRIT) ? -7.5 : -6) : -3)//CIT CHANGE - decreases adjuststaminaloss to stop stamina damage from being such a joke
adjustStaminaLoss(!CHECK_MOBILITY(src, MOBILITY_STAND) ? ((combat_flags & COMBAT_FLAG_HARD_STAMCRIT) ? STAM_RECOVERY_STAM_CRIT : STAM_RECOVERY_RESTING) : STAM_RECOVERY_NORMAL)
if(!(combat_flags & COMBAT_FLAG_HARD_STAMCRIT) && incomingstammult != 1)
incomingstammult = max(0.01, incomingstammult)
@@ -81,7 +81,7 @@
/mob/living/carbon/monkey/proc/pickup_and_wear(obj/item/I)
if(QDELETED(I) || I.loc != src)
return
equip_to_appropriate_slot(I)
equip_to_appropriate_slot(I, TRUE)
/mob/living/carbon/monkey/resist_restraints()
var/obj/item/I = null
@@ -90,8 +90,7 @@
else if(legcuffed)
I = legcuffed
if(I)
changeNext_move(CLICK_CD_BREAKOUT)
last_special = world.time + CLICK_CD_BREAKOUT
MarkResistTime()
cuff_resist(I)
/mob/living/carbon/monkey/proc/should_target(var/mob/living/L)
@@ -354,7 +353,7 @@
battle_screech()
a_intent = INTENT_HARM
/mob/living/carbon/monkey/attack_hand(mob/living/L)
/mob/living/carbon/monkey/on_attack_hand(mob/living/L)
if(L.a_intent == INTENT_HARM && prob(MONKEY_RETALIATE_HARM_PROB))
retaliate(L)
else if(L.a_intent == INTENT_DISARM && prob(MONKEY_RETALIATE_DISARM_PROB))
@@ -1,4 +1,9 @@
/mob/living/carbon/monkey/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
/mob/living/carbon/monkey/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, clothing_check = FALSE, list/return_warning)
if(clothing_check && (slot in check_obscured_slots()))
if(return_warning)
return_warning[1] = "<span class='warning'>You are unable to equip that with your current garments in the way!</span>"
return FALSE
switch(slot)
if(SLOT_HANDS)
if(get_empty_held_indexes())
+20 -24
View File
@@ -3,30 +3,26 @@
/mob/living/carbon/monkey
/mob/living/carbon/monkey/Life()
set invisibility = 0
if (notransform)
/mob/living/carbon/monkey/BiologicalLife(seconds, times_fired)
if(!(. = ..()))
return
if(..())
if(!client)
if(stat == CONSCIOUS)
if(on_fire || buckled || restrained() || (!CHECK_MOBILITY(src, MOBILITY_STAND) && CHECK_MOBILITY(src, MOBILITY_MOVE))) //CIT CHANGE - makes it so monkeys attempt to resist if they're resting)
if(!resisting && prob(MONKEY_RESIST_PROB))
resisting = TRUE
walk_to(src,0)
resist()
else if(resisting)
resisting = FALSE
else if((mode == MONKEY_IDLE && !pickupTarget && !prob(MONKEY_SHENANIGAN_PROB)) || !handle_combat())
if(prob(25) && CHECK_MOBILITY(src, MOBILITY_MOVE) && isturf(loc) && !pulledby)
step(src, pick(GLOB.cardinals))
else if(prob(1))
emote(pick("scratch","jump","roll","tail"))
else
if(client)
return
if(stat == CONSCIOUS)
if(on_fire || buckled || restrained() || (!CHECK_MOBILITY(src, MOBILITY_STAND) && CHECK_MOBILITY(src, MOBILITY_MOVE))) //CIT CHANGE - makes it so monkeys attempt to resist if they're resting)
if(!resisting && prob(MONKEY_RESIST_PROB))
resisting = TRUE
walk_to(src,0)
resist()
else if(resisting)
resisting = FALSE
else if((mode == MONKEY_IDLE && !pickupTarget && !prob(MONKEY_SHENANIGAN_PROB)) || !handle_combat())
if(prob(25) && CHECK_MOBILITY(src, MOBILITY_MOVE) && isturf(loc) && !pulledby)
step(src, pick(GLOB.cardinals))
else if(prob(1))
emote(pick("scratch","jump","roll","tail"))
else
walk_to(src,0)
/mob/living/carbon/monkey/handle_mutations_and_radiation()
if(radiation)
@@ -50,8 +46,8 @@
return ..()
/mob/living/carbon/monkey/handle_breath_temperature(datum/gas_mixture/breath)
if(abs(BODYTEMP_NORMAL - breath.temperature) > 50)
switch(breath.temperature)
if(abs(BODYTEMP_NORMAL - breath.return_temperature()) > 50)
switch(breath.return_temperature())
if(-INFINITY to 120)
adjustFireLoss(3)
if(120 to 200)
@@ -42,7 +42,7 @@
adjustBruteLoss(15)
return TRUE
/mob/living/carbon/monkey/attack_hand(mob/living/carbon/human/M)
/mob/living/carbon/monkey/on_attack_hand(mob/living/carbon/human/M)
. = ..()
if(.) //To allow surgery to return properly.
return
@@ -26,16 +26,19 @@
//These have to be after the parent new to ensure that the monkey
//bodyparts are actually created before we try to equip things to
//those slots
if(ancestor_chain > 1)
generate_fake_scars(rand(ancestor_chain, ancestor_chain * 4))
if(relic_hat)
equip_to_slot_or_del(new relic_hat, SLOT_HEAD)
if(relic_mask)
equip_to_slot_or_del(new relic_mask, SLOT_WEAR_MASK)
/mob/living/carbon/monkey/punpun/Life()
/mob/living/carbon/monkey/punpun/BiologicalLife(seconds, times_fired)
if(!(. = ..()))
return
if(!stat && SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
Write_Memory(FALSE, FALSE)
memory_saved = TRUE
..()
/mob/living/carbon/monkey/punpun/death(gibbed)
if(!memory_saved)
@@ -12,7 +12,7 @@
overlays_standing[cache_index] = null
/mob/living/carbon/regenerate_icons()
if(notransform)
if(mob_transforming)
return 1
update_inv_hands()
update_inv_handcuffed()
@@ -68,7 +68,7 @@
var/dam_colors = "#E62525"
if(ishuman(src))
var/mob/living/carbon/human/H = src
dam_colors = bloodtype_to_color(H.dna.blood_type)
dam_colors = H.dna.species.exotic_blood_color
var/mutable_appearance/damage_overlay = mutable_appearance('icons/mob/dam_mob.dmi', "blank", -DAMAGE_LAYER, color = dam_colors)
overlays_standing[DAMAGE_LAYER] = damage_overlay
+4
View File
@@ -0,0 +1,4 @@
/mob/living/GetActionCooldownMod()
. = ..()
for(var/datum/status_effect/S in status_effects)
. *= S.action_cooldown_mod()
+17 -11
View File
@@ -1,14 +1,20 @@
/*
apply_damage(a,b,c)
args
a:damage - How much damage to take
b:damage_type - What type of damage to take, brute, burn
c:def_zone - Where to take the damage if its brute or burn
Returns
standard 0 if fail
*/
/mob/living/proc/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE)
/**
* Applies damage to this mob
*
* Sends [COMSIG_MOB_APPLY_DAMGE]
*
* Arguuments:
* * damage - amount of damage
* * damagetype - one of [BRUTE], [BURN], [TOX], [OXY], [CLONE], [STAMINA]
* * def_zone - zone that is being hit if any
* * blocked - armor value applied
* * forced - bypass hit percentage
* * spread_damage - used in overrides
*
* Returns TRUE if damage applied
*/
/mob/living/proc/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = FALSE)
var/hit_percent = (100-blocked)/100
if(!damage || (hit_percent <= 0))
return 0
@@ -239,7 +245,7 @@
update_stamina()
// damage ONE external organ, organ gets randomly selected from damaged ones.
/mob/living/proc/take_bodypart_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE)
/mob/living/proc/take_bodypart_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE, required_status, check_armor = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = FALSE)
adjustBruteLoss(brute, FALSE) //zero as argument for no instant health update
adjustFireLoss(burn, FALSE)
adjustStaminaLoss(stamina, FALSE)
+3 -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
@@ -457,6 +457,7 @@
message = params
if(type_override)
emote_type = type_override
message = user.say_emphasis(message)
. = ..()
message = null
emote_type = EMOTE_VISIBLE
+67 -40
View File
@@ -1,12 +1,20 @@
/**
* Called by SSmobs at (hopefully) an interval of 1 second.
* Splits off into PhysicalLife() and BiologicalLife(). Override those instead of this.
*/
/mob/living/proc/Life(seconds, times_fired)
set waitfor = FALSE
set invisibility = 0
SHOULD_NOT_SLEEP(TRUE)
if(mob_transforming)
return
if(digitalinvis)
handle_diginvis() //AI becomes unable to see mob
. = SEND_SIGNAL(src, COMSIG_LIVING_LIFE, seconds, times_fired)
if(!(. & COMPONENT_INTERRUPT_LIFE_PHYSICAL))
PhysicalLife(seconds, times_fired)
if(!(. & COMPONENT_INTERRUPT_LIFE_BIOLOGICAL))
BiologicalLife(seconds, times_fired)
if((movement_type & FLYING) && !(movement_type & FLOATING)) //TODO: Better floating
float(on = TRUE)
// CODE BELOW SHOULD ONLY BE THINGS THAT SHOULD HAPPEN NO MATTER WHAT AND CAN NOT BE SUSPENDED!
// Otherwise, it goes into one of the two split Life procs!
if (client)
var/turf/T = get_turf(src)
@@ -30,28 +38,56 @@
log_game("Z-TRACKING: [src] of type [src.type] has a Z-registration despite not having a client.")
update_z(null)
if (notransform)
return
if(!loc)
return
var/datum/gas_mixture/environment = loc.return_air()
if(stat != DEAD)
//Mutations and radiation
handle_mutations_and_radiation()
if(stat != DEAD)
//Breathing, if applicable
handle_breathing(times_fired)
/**
* Handles biological life processes like chemical metabolism, breathing, etc
* Returns TRUE or FALSE based on if we were interrupted. This is used by overridden variants to check if they should stop.
*/
/mob/living/proc/BiologicalLife(seconds, times_fired)
handle_diseases()// DEAD check is in the proc itself; we want it to spread even if the mob is dead, but to handle its disease-y properties only if you're not.
if (QDELETED(src)) // diseases can qdel the mob via transformations
return
handle_wounds()
if(stat != DEAD)
//Random events (vomiting etc)
handle_random_events()
// Everything after this shouldn't process while dead (as of the time of writing)
if(stat == DEAD)
return FALSE
//Mutations and radiation
handle_mutations_and_radiation()
//Breathing, if applicable
handle_breathing(times_fired)
if (QDELETED(src)) // diseases can qdel the mob via transformations
return FALSE
//Random events (vomiting etc)
handle_random_events()
//stuff in the stomach
handle_stomach()
handle_block_parry(seconds)
// These two MIGHT need to be moved to base Life() if we get any in the future that's a "physical" effect that needs to fire even while in stasis.
handle_traits() // eye, ear, brain damages
handle_status_effects() //all special effects, stun, knockdown, jitteryness, hallucination, sleeping, etc
return TRUE
/**
* Handles physical life processes like being on fire. Don't ask why this is considered "Life".
* Returns TRUE or FALSE based on if we were interrupted. This is used by overridden variants to check if they should stop.
*/
/mob/living/proc/PhysicalLife(seconds, times_fired)
if(digitalinvis)
handle_diginvis() //AI becomes unable to see mob
if((movement_type & FLYING) && !(movement_type & FLOATING)) //TODO: Better floating
INVOKE_ASYNC(src, /atom/movable.proc/float, TRUE)
if(!loc)
return FALSE
var/datum/gas_mixture/environment = loc.return_air()
//Handle temperature/pressure differences between body and environment
if(environment)
@@ -59,23 +95,11 @@
handle_fire()
//stuff in the stomach
handle_stomach()
handle_gravity()
handle_block_parry(seconds)
if(machine)
machine.check_eye(src)
if(stat != DEAD)
handle_traits() // eye, ear, brain damages
if(stat != DEAD)
handle_status_effects() //all special effects, stun, knockdown, jitteryness, hallucination, sleeping, etc
if(stat != DEAD)
return 1
return TRUE
/mob/living/proc/handle_breathing(times_fired)
return
@@ -87,6 +111,9 @@
/mob/living/proc/handle_diseases()
return
/mob/living/proc/handle_wounds()
return
/mob/living/proc/handle_diginvis()
if(!digitaldisguise)
src.digitaldisguise = image(loc = src)
@@ -112,7 +139,7 @@
ExtinguishMob()
return
var/datum/gas_mixture/G = loc.return_air() // Check if we're standing in an oxygenless environment
if(G.gases[/datum/gas/oxygen] < 1)
if(!G.get_moles(/datum/gas/oxygen, 1))
ExtinguishMob() //If there's no oxygen in the tile we're on, put out the fire
return
var/turf/location = get_turf(src)
@@ -168,4 +195,4 @@
/mob/living/proc/handle_high_gravity(gravity)
if(gravity >= GRAVITY_DAMAGE_TRESHOLD) //Aka gravity values of 3 or more
var/grav_stregth = gravity - GRAVITY_DAMAGE_TRESHOLD
adjustBruteLoss(min(grav_stregth,3))
adjustBruteLoss(min(grav_stregth,3))
+23 -23
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)
@@ -914,7 +915,7 @@
floating_need_update = TRUE
/mob/living/proc/get_temperature(datum/gas_mixture/environment)
var/loc_temp = environment ? environment.temperature : T0C
var/loc_temp = environment ? environment.return_temperature() : T0C
if(isobj(loc))
var/obj/oloc = loc
var/obj_temp = oloc.return_temperature()
@@ -1196,30 +1197,29 @@
/mob/living/vv_edit_var(var_name, var_value)
switch(var_name)
if ("maxHealth")
if (NAMEOF(src, maxHealth))
if (!isnum(var_value) || var_value <= 0)
return FALSE
if("stat")
if(NAMEOF(src, stat))
if((stat == DEAD) && (var_value < DEAD))//Bringing the dead back to life
GLOB.dead_mob_list -= src
GLOB.alive_mob_list += src
if((stat < DEAD) && (var_value == DEAD))//Kill he
GLOB.alive_mob_list -= src
GLOB.dead_mob_list += src
if(NAMEOF(src, health)) //this doesn't work. gotta use procs instead.
return FALSE
. = ..()
switch(var_name)
if("eye_blind")
if(NAMEOF(src, eye_blind))
set_blindness(var_value)
if("eye_damage")
var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
E?.setOrganDamage(var_value)
if("eye_blurry")
if(NAMEOF(src, eye_blurry))
set_blurriness(var_value)
if("maxHealth")
if(NAMEOF(src, maxHealth))
updatehealth()
if("resize")
if(NAMEOF(src, resize))
update_transform()
if("lighting_alpha")
if(NAMEOF(src, lighting_alpha))
sync_lighting_plane_alpha()
/mob/living/proc/do_adrenaline(
+15 -9
View File
@@ -10,18 +10,17 @@
REMOVE_TRAIT(src, TRAIT_SPRINT_LOCKED, ACTIVE_BLOCK_TRAIT)
remove_movespeed_modifier(/datum/movespeed_modifier/active_block)
var/datum/block_parry_data/data = I.get_block_parry_data()
if(timeToNextMove() < data.block_end_click_cd_add)
changeNext_move(data.block_end_click_cd_add)
DelayNextAction(data.block_end_click_cd_add)
return TRUE
/mob/living/proc/start_active_blocking(obj/item/I)
/mob/living/proc/ACTIVE_BLOCK_START(obj/item/I)
if(combat_flags & (COMBAT_FLAG_ACTIVE_BLOCK_STARTING | COMBAT_FLAG_ACTIVE_BLOCKING))
return FALSE
if(!(I in held_items))
return FALSE
var/datum/block_parry_data/data = I.get_block_parry_data()
if(!istype(data)) //Typecheck because if an admin/coder screws up varediting or something we do not want someone being broken forever, the CRASH logs feedback so we know what happened.
CRASH("start_active_blocking called with an item with no valid data: [I] --> [I.block_parry_data]!")
CRASH("ACTIVE_BLOCK_START called with an item with no valid data: [I] --> [I.block_parry_data]!")
combat_flags |= COMBAT_FLAG_ACTIVE_BLOCKING
active_block_item = I
if(data.block_lock_attacking)
@@ -83,15 +82,21 @@
return FALSE
// QOL: Instead of trying to just block with held item, grab first available item.
var/obj/item/I = find_active_block_item()
if(!I)
to_chat(src, "<span class='warning'>You can't block with your bare hands!</span>")
var/list/other_items = list()
if(SEND_SIGNAL(src, COMSIG_LIVING_ACTIVE_BLOCK_START, I, other_items) & COMPONENT_PREVENT_BLOCK_START)
to_chat(src, "<span class='warning'>Something is preventing you from blocking!</span>")
return
if(!I)
if(!length(other_items))
to_chat(src, "<span class='warning'>You can't block with your bare hands!</span>")
return
I = other_items[1]
if(!I.can_active_block())
to_chat(src, "<span class='warning'>[I] is either not capable of being used to actively block, or is not currently in a state that can! (Try wielding it if it's twohanded, for example.)</span>")
return
// QOL: Attempt to toggle on combat mode if it isn't already
SEND_SIGNAL(src, COMSIG_ENABLE_COMBAT_MODE)
if(!SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE))
if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
to_chat(src, "<span class='warning'>You must be in combat mode to actively block!</span>")
return FALSE
var/datum/block_parry_data/data = I.get_block_parry_data()
@@ -104,7 +109,7 @@
animate(src, pixel_x = get_standard_pixel_x_offset(), pixel_y = get_standard_pixel_y_offset(), time = 2.5, FALSE, SINE_EASING | EASE_IN, ANIMATION_END_NOW)
return
combat_flags &= ~(COMBAT_FLAG_ACTIVE_BLOCK_STARTING)
start_active_blocking(I)
ACTIVE_BLOCK_START(I)
/**
* Gets the first item we can that can block, but if that fails, default to active held item.COMSIG_ENABLE_COMBAT_MODE
@@ -115,7 +120,8 @@
for(var/obj/item/I in held_items - held)
if(I.can_active_block())
return I
return held
else
return held
/**
* Proc called by keybindings to stop active blocking.
+34 -14
View File
@@ -24,35 +24,49 @@
// yanderedev else if time
var/obj/item/using_item = get_active_held_item()
var/datum/block_parry_data/data
var/datum/tool
var/method
if(using_item?.can_active_parry())
data = using_item.block_parry_data
method = ITEM_PARRY
tool = using_item
else if(mind?.martial_art?.can_martial_parry)
data = mind.martial_art.block_parry_data
method = MARTIAL_PARRY
else if(combat_flags & COMBAT_FLAG_UNARMED_PARRY)
tool = mind.martial_art
else if((combat_flags & COMBAT_FLAG_UNARMED_PARRY) && check_unarmed_parry_activation_special())
data = block_parry_data
method = UNARMED_PARRY
tool = src
else
// QOL: If none of the above work, try to find another item.
var/obj/item/backup = find_backup_parry_item()
if(!backup)
to_chat(src, "<span class='warning'>You have nothing to parry with!</span>")
return FALSE
data = backup.block_parry_data
using_item = backup
if(backup)
tool = backup
data = backup.block_parry_data
using_item = backup
method = ITEM_PARRY
var/list/other_items = list()
if(SEND_SIGNAL(src, COMSIG_LIVING_ACTIVE_PARRY_START, method, tool, other_items) & COMPONENT_PREVENT_PARRY_START)
to_chat(src, "<span class='warning'>Something is preventing you from parrying!</span>")
return
if(!using_item && !method && length(other_items))
using_item = other_items[1]
method = ITEM_PARRY
data = using_item.block_parry_data
if(!method)
to_chat(src, "<span class='warning'>You have nothing to parry with!</span>")
return FALSE
//QOL: Try to enable combat mode if it isn't already
SEND_SIGNAL(src, COMSIG_ENABLE_COMBAT_MODE)
if(!SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE))
if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
to_chat(src, "<span class='warning'>You must be in combat mode to parry!</span>")
return FALSE
data = return_block_parry_datum(data)
var/full_parry_duration = data.parry_time_windup + data.parry_time_active + data.parry_time_spindown
// no system in place to "fallback" if out of the 3 the top priority one can't parry due to constraints but something else can.
// can always implement it later, whatever.
if((data.parry_respect_clickdelay && (next_move > world.time)) || ((parry_end_time_last + data.parry_cooldown) > world.time))
if((data.parry_respect_clickdelay && !CheckActionCooldown()) || ((parry_end_time_last + data.parry_cooldown) > world.time))
to_chat(src, "<span class='warning'>You are not ready to parry (again)!</span>")
return
// Point of no return, make sure everything is set.
@@ -79,6 +93,12 @@
if(I.can_active_parry())
return I
/**
* Check if we can unarmed parry
*/
/mob/living/proc/check_unarmed_parry_activation_special()
return TRUE
/**
* Called via timer when the parry sequence ends.
*/
@@ -101,7 +121,7 @@
Stagger(data.parry_failed_stagger_duration)
effect_text += "staggering themselves"
if(data.parry_failed_clickcd_duration)
changeNext_move(data.parry_failed_clickcd_duration)
DelayNextAction(data.parry_failed_clickcd_duration, flush = TRUE)
effect_text += "throwing themselves off balance"
handle_parry_ending_effects(data, effect_text)
parrying = NOT_PARRYING
@@ -140,17 +160,17 @@
/**
* Called when an attack is parried using this, whether or not the parry was successful.
*/
/obj/item/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, parry_efficiency, parry_time)
/obj/item/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time)
/**
* Called when an attack is parried innately, whether or not the parry was successful.
*/
/mob/living/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, parry_efficiency, parry_time)
/mob/living/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time)
/**
* Called when an attack is parried using this, whether or not the parry was successful.
*/
/datum/martial_art/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, parry_efficiency, parry_time)
/datum/martial_art/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time)
/**
* Called when an attack is parried and block_parra_data indicates to use a proc to handle counterattack.
@@ -236,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)
@@ -257,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.")
+24 -32
View File
@@ -1,7 +1,10 @@
/mob/living/proc/run_armor_check(def_zone = null, attack_flag = "melee", absorb_text = "Your armor absorbs the blow!", soften_text = "Your armor softens the blow!", armour_penetration, penetrated_text = "Your armor was penetrated!")
/mob/living/proc/run_armor_check(def_zone = null, attack_flag = "melee", absorb_text = "Your armor absorbs the blow!", soften_text = "Your armor softens the blow!", armour_penetration, penetrated_text = "Your armor was penetrated!", silent=FALSE)
var/armor = getarmor(def_zone, attack_flag)
if(silent)
return max(0, armor - armour_penetration)
//the if "armor" check is because this is used for everything on /living, including humans
if(armor && armour_penetration)
armor = max(0, armor - armour_penetration)
@@ -74,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)
@@ -82,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
@@ -105,12 +109,6 @@
/mob/living/proc/catch_item(obj/item/I, skip_throw_mode_check = FALSE)
return FALSE
/mob/living/proc/embed_item(obj/item/I)
return
/mob/living/proc/can_embed(obj/item/I)
return FALSE
/mob/living/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
// Throwingdatum can be null if someone had an accident() while slipping with an item in hand.
var/obj/item/I
@@ -126,35 +124,22 @@
skipcatch = TRUE
blocked = TRUE
total_damage = block_calculate_resultant_damage(total_damage, block_return)
else if(I && I.throw_speed >= EMBED_THROWSPEED_THRESHOLD && can_embed(I, src) && prob(I.embedding.embed_chance) && !HAS_TRAIT(src, TRAIT_PIERCEIMMUNE) && (!HAS_TRAIT(src, TRAIT_AUTO_CATCH_ITEM) || incapacitated() || get_active_held_item()))
embed_item(I)
hitpush = FALSE
skipcatch = TRUE //can't catch the now embedded item
if(I)
var/nosell_hit = SEND_SIGNAL(I, COMSIG_MOVABLE_IMPACT_ZONE, src, impacting_zone, throwingdatum, FALSE, blocked)
if(nosell_hit)
skipcatch = TRUE
hitpush = FALSE
if(!skipcatch && isturf(I.loc) && catch_item(I))
return TRUE
var/dtype = BRUTE
var/volume = I.get_volume_by_throwforce_and_or_w_class()
SEND_SIGNAL(I, COMSIG_MOVABLE_IMPACT_ZONE, src, impacting_zone)
dtype = I.damtype
if (I.throwforce > 0) //If the weapon's throwforce is greater than zero...
if (I.throwhitsound) //...and throwhitsound is defined...
playsound(loc, I.throwhitsound, volume, 1, -1) //...play the weapon's throwhitsound.
else if(I.hitsound) //Otherwise, if the weapon's hitsound is defined...
playsound(loc, I.hitsound, volume, 1, -1) //...play the weapon's hitsound.
else if(!I.throwhitsound) //Otherwise, if throwhitsound isn't defined...
playsound(loc, 'sound/weapons/genhit.ogg',volume, 1, -1) //...play genhit.ogg.
else if(!I.throwhitsound && I.throwforce > 0) //Otherwise, if the item doesn't have a throwhitsound and has a throwforce greater than zero...
playsound(loc, 'sound/weapons/genhit.ogg', volume, 1, -1)//...play genhit.ogg
if(!I.throwforce)// Otherwise, if the item's throwforce is 0...
playsound(loc, 'sound/weapons/throwtap.ogg', 1, volume, -1)//...play throwtap.ogg.
if(!blocked)
visible_message("<span class='danger'>[src] has been hit by [I].</span>", \
"<span class='userdanger'>You have been hit by [I].</span>")
var/armor = run_armor_check(impacting_zone, "melee", "Your armor has protected your [parse_zone(impacting_zone)].", "Your armor has softened hit to your [parse_zone(impacting_zone)].",I.armour_penetration)
apply_damage(total_damage, dtype, impacting_zone, armor)
apply_damage(total_damage, dtype, impacting_zone, armor, sharpness=I.sharpness)
if(I.thrownby)
log_combat(I.thrownby, src, "threw and hit", I)
else
@@ -231,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
@@ -286,10 +271,10 @@
user.set_pull_offsets(src, grab_state)
return 1
/mob/living/attack_hand(mob/user)
/mob/living/on_attack_hand(mob/user, act_intent = user.a_intent, attackchain_flags)
..() //Ignoring parent return value here.
SEND_SIGNAL(src, COMSIG_MOB_ATTACK_HAND, user)
if((user != src) && user.a_intent != INTENT_HELP && (mob_run_block(user, 0, user.name, ATTACK_TYPE_UNARMED | ATTACK_TYPE_MELEE, null, user, check_zone(user.zone_selected), null) & BLOCK_SUCCESS))
if((user != src) && act_intent != INTENT_HELP && (mob_run_block(user, 0, user.name, ATTACK_TYPE_UNARMED | ATTACK_TYPE_MELEE | ((attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE), null, user, check_zone(user.zone_selected), null) & BLOCK_SUCCESS))
log_combat(user, src, "attempted to touch")
visible_message("<span class='warning'>[user] attempted to touch [src]!</span>",
"<span class='warning'>[user] attempted to touch you!</span>", target = user,
@@ -339,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,
@@ -354,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,
@@ -363,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>")
@@ -384,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.
+7 -1
View File
@@ -96,7 +96,13 @@
mobility_flags &= ~MOBILITY_STAND
setMovetype(movement_type | CRAWLING)
if(!lying) //force them on the ground
lying = pick(90, 270)
switch(dir)
if(NORTH, SOUTH)
lying = pick(90, 270)
if(EAST)
lying = 90
else //West
lying = 270
if(has_gravity() && !buckled)
playsound(src, "bodyfall", 20, 1)
else
+11
View File
@@ -88,11 +88,22 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
var/static/list/one_character_prefix = list(MODE_HEADSET = TRUE, MODE_ROBOT = TRUE, MODE_WHISPER = TRUE)
var/ic_blocked = FALSE
/*
if(client && !forced && config.ic_filter_regex && findtext(message, config.ic_filter_regex))
//The filter doesn't act on the sanitized message, but the raw message.
ic_blocked = TRUE
*/
if(sanitize)
message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN))
if(!message || message == "")
return
if(ic_blocked)
//The filter warning message shows the sanitized message though.
to_chat(src, "<span class='warning'>That message contained a word prohibited in IC chat! Consider reviewing the server rules.\n<span replaceRegex='show_filtered_ic_chat'>\"[message]\"</span></span>")
return
var/datum/saymode/saymode = SSradio.saymodes[talk_key]
var/message_mode = get_message_mode(message)
var/original_message = message
+31 -31
View File
@@ -3,48 +3,48 @@
#define POWER_RESTORATION_SEARCH_APC 2
#define POWER_RESTORATION_APC_FOUND 3
/mob/living/silicon/ai/Life()
if (stat == DEAD)
/mob/living/silicon/ai/BiologicalLife(seconds, times_fired)
if(!(. = ..()))
return
else //I'm not removing that shitton of tabs, unneeded as they are. -- Urist
//I'm not removing that shitton of tabs, unneeded as they are. -- Urist
//Being dead doesn't mean your temperature never changes
update_gravity(mob_has_gravity())
update_gravity(mob_has_gravity())
handle_status_effects()
handle_status_effects()
if(malfhack && malfhack.aidisabled)
deltimer(malfhacking)
// This proc handles cleanup of screen notifications and
// messenging the client
malfhacked(malfhack)
if(malfhack && malfhack.aidisabled)
deltimer(malfhacking)
// This proc handles cleanup of screen notifications and
// messenging the client
malfhacked(malfhack)
if(isturf(loc) && (QDELETED(eyeobj) || !eyeobj.loc))
view_core()
if(isturf(loc) && (QDELETED(eyeobj) || !eyeobj.loc))
view_core()
if(machine)
machine.check_eye(src)
if(machine)
machine.check_eye(src)
// Handle power damage (oxy)
if(aiRestorePowerRoutine)
// Lost power
adjustOxyLoss(1)
else
// Gain Power
if(getOxyLoss())
adjustOxyLoss(-1)
// Handle power damage (oxy)
if(aiRestorePowerRoutine)
// Lost power
adjustOxyLoss(1)
else
// Gain Power
if(getOxyLoss())
adjustOxyLoss(-1)
if(!lacks_power())
var/area/home = get_area(src)
if(home.powered(EQUIP))
home.use_power(1000, EQUIP)
if(!lacks_power())
var/area/home = get_area(src)
if(home.powered(EQUIP))
home.use_power(1000, EQUIP)
if(aiRestorePowerRoutine >= POWER_RESTORATION_SEARCH_APC)
ai_restore_power()
return
if(aiRestorePowerRoutine >= POWER_RESTORATION_SEARCH_APC)
ai_restore_power()
return
else if(!aiRestorePowerRoutine)
ai_lose_power()
else if(!aiRestorePowerRoutine)
ai_lose_power()
/mob/living/silicon/ai/proc/lacks_power()
var/turf/T = get_turf(src)
@@ -0,0 +1,74 @@
/datum/robot_control
var/mob/living/silicon/ai/owner
/datum/robot_control/New(mob/living/silicon/ai/new_owner)
if(!istype(new_owner))
qdel(src)
owner = new_owner
/datum/robot_control/proc/is_interactable(mob/user)
if(user != owner || owner.incapacitated())
return FALSE
if(owner.control_disabled)
to_chat(user, "<span class='warning'>Wireless control is disabled.</span>")
return FALSE
return TRUE
/datum/robot_control/ui_status(mob/user)
if(is_interactable(user))
return ..()
return UI_CLOSE
/datum/robot_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "RemoteRobotControl", "Remote Robot Control", 500, 500, master_ui, state)
ui.open()
/datum/robot_control/ui_data(mob/user)
if(!owner || user != owner)
return
var/list/data = list()
var/turf/ai_current_turf = get_turf(owner)
var/ai_zlevel = ai_current_turf.z
data["robots"] = list()
for(var/mob/living/simple_animal/bot/B in GLOB.bots_list)
if(B.z != ai_zlevel || B.remote_disabled) //Only non-emagged bots on the same Z-level are detected!
continue
var/list/robot_data = list(
name = B.name,
model = B.model,
mode = B.get_mode(),
hacked = B.hacked,
location = get_area_name(B, TRUE),
ref = REF(B)
)
data["robots"] += list(robot_data)
return data
/datum/robot_control/ui_act(action, params)
if(..())
return
if(!is_interactable(usr))
return
switch(action)
if("callbot") //Command a bot to move to a selected location.
if(owner.call_bot_cooldown > world.time)
to_chat(usr, "<span class='danger'>Error: Your last call bot command is still processing, please wait for the bot to finish calculating a route.</span>")
return
owner.Bot = locate(params["ref"]) in GLOB.bots_list
if(!owner.Bot || owner.Bot.remote_disabled || owner.control_disabled)
return
owner.waypoint_mode = TRUE
to_chat(usr, "<span class='notice'>Set your waypoint by clicking on a valid location free of obstructions.</span>")
. = TRUE
if("interface") //Remotely connect to a bot!
owner.Bot = locate(params["ref"]) in GLOB.bots_list
if(!owner.Bot || owner.Bot.remote_disabled || owner.control_disabled)
return
owner.Bot.attack_ai(usr)
. = TRUE
@@ -1,5 +1,5 @@
/mob/living/silicon/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE)
/mob/living/silicon/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = FALSE)
var/hit_percent = (100-blocked)/100
if(!damage || (!forced && hit_percent <= 0))
return 0
+9 -6
View File
@@ -146,10 +146,11 @@
if(possible_chassis[chassis])
AddElement(/datum/element/mob_holder, chassis, 'icons/mob/pai_item_head.dmi', 'icons/mob/pai_item_rh.dmi', 'icons/mob/pai_item_lh.dmi', ITEM_SLOT_HEAD)
/mob/living/silicon/pai/Life()
/mob/living/silicon/pai/BiologicalLife(seconds, times_fired)
if(!(. = ..()))
return
if(hacking)
process_hack()
return ..()
/mob/living/silicon/pai/proc/process_hack()
@@ -282,17 +283,19 @@
. = ..()
. += "A personal AI in holochassis mode. Its master ID string seems to be [master]."
/mob/living/silicon/pai/Life()
if(stat == DEAD)
return
/mob/living/silicon/pai/PhysicalLife()
. = ..()
if(cable)
if(get_dist(src, cable) > 1)
var/turf/T = get_turf(src.loc)
T.visible_message("<span class='warning'>[src.cable] rapidly retracts back into its spool.</span>", "<span class='italics'>You hear a click and the sound of wire spooling rapidly.</span>")
qdel(src.cable)
cable = null
/mob/living/silicon/pai/BiologicalLife()
if(!(. = ..()))
return
silent = max(silent - 1, 0)
. = ..()
/mob/living/silicon/pai/updatehealth()
if(status_flags & GODMODE)
@@ -28,8 +28,7 @@
fold_in(force = 1)
DefaultCombatKnockdown(200)
//ATTACK HAND IGNORING PARENT RETURN VALUE
/mob/living/silicon/pai/attack_hand(mob/living/carbon/human/user)
/mob/living/silicon/pai/on_attack_hand(mob/living/carbon/human/user)
switch(user.a_intent)
if(INTENT_HELP)
visible_message("<span class='notice'>[user] gently pats [src] on the head, eliciting an off-putting buzzing from its holographic field.</span>",
@@ -565,7 +565,6 @@
dat += "Unable to obtain a reading.<br>"
else
var/datum/gas_mixture/environment = T.return_air()
var/list/env_gases = environment.gases
var/pressure = environment.return_pressure()
var/total_moles = environment.total_moles()
@@ -573,11 +572,11 @@
dat += "Air Pressure: [round(pressure,0.1)] kPa<br>"
if (total_moles)
for(var/id in env_gases)
var/gas_level = env_gases[id]/total_moles
for(var/id in environment.get_gases())
var/gas_level = environment.get_moles(id)/total_moles
if(gas_level > 0.01)
dat += "[GLOB.meta_gas_names[id]]: [round(gas_level*100)]%<br>"
dat += "Temperature: [round(environment.temperature-T0C)]&deg;C<br>"
dat += "Temperature: [round(environment.return_temperature()-T0C)]&deg;C<br>"
dat += "<a href='byond://?src=[REF(src)];software=atmosensor;sub=0'>Refresh Reading</a> <br>"
dat += "<br>"
return dat
@@ -2,11 +2,20 @@
//as they handle all relevant stuff like adding it to the player's screen and such
//Returns the thing in our active hand (whatever is in our active module-slot, in this case)
//This proc has been butchered into a proc that overrides borg item holding for the sake of making grippers work.
//I'd be immensely thankful if anyone can figure out a less obtuse way of making grippers work without breaking functionality.
/mob/living/silicon/robot/get_active_held_item()
var/item = module_active
if(istype(item, /obj/item/weapon/gripper))
var/obj/item/weapon/gripper/G = item
if(G.wrapped)
if(G.wrapped.loc != G)
G.wrapped = null
return module_active
item = G.wrapped
return item
return module_active
/mob/living/silicon/robot/proc/uneq_module(obj/item/O)
if(!O)
return 0
@@ -1,9 +1,6 @@
/mob/living/silicon/robot/Life()
set invisibility = 0
if (src.notransform)
/mob/living/silicon/robot/BiologicalLife(seconds, times_fired)
if(!(. = ..()))
return
..()
adjustOxyLoss(-10) //we're a robot!
handle_robot_hud_updates()
handle_robot_cell()
@@ -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,11 +311,11 @@
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>")
if(!W.use_tool(src, user, 50, 1, max_level = JOB_SKILL_TRAINED))
if(!W.use_tool(src, user, 50, 1, skill_gain_mult = TRIVIAL_USE_TOOL_MULT))
to_chat(user, "<span class='warning'>You need more cable to repair [src]!</span>")
return
adjustFireLoss(-10)
@@ -62,8 +62,7 @@
return
//ATTACK HAND IGNORING PARENT RETURN VALUE
/mob/living/silicon/robot/attack_hand(mob/living/carbon/human/user)
/mob/living/silicon/robot/on_attack_hand(mob/living/carbon/human/user)
add_fingerprint(user)
if(opened && !wiresexposed && cell && !issilicon(user))
cell.update_icon()
@@ -128,7 +128,7 @@
S.source = get_or_create_estorage(/datum/robot_energy_storage/wrapping_paper)
if(S && S.source)
S.custom_materials = null
S.set_custom_materials(null)
S.is_cyborg = 1
if(I.loc != src)
@@ -259,7 +259,7 @@
var/prev_locked_down = R.locked_down
sleep(1)
flick("[cyborg_base_icon]_transform", R)
R.notransform = TRUE
R.mob_transforming = TRUE
R.SetLockdown(1)
R.anchored = TRUE
sleep(1)
@@ -270,7 +270,7 @@
R.SetLockdown(0)
R.setDir(SOUTH)
R.anchored = FALSE
R.notransform = FALSE
R.mob_transforming = FALSE
R.update_headlamp()
R.notify_ai(NEW_MODULE)
if(R.hud_used)
@@ -324,7 +324,7 @@
/obj/item/crowbar/cyborg,
/obj/item/healthanalyzer,
/obj/item/reagent_containers/borghypo,
/obj/item/reagent_containers/glass/beaker/large,
/obj/item/weapon/gripper/medical,
/obj/item/reagent_containers/dropper,
/obj/item/reagent_containers/syringe,
/obj/item/surgical_drapes,
@@ -334,13 +334,15 @@
/obj/item/surgicaldrill,
/obj/item/scalpel,
/obj/item/circular_saw,
/obj/item/bonesetter,
/obj/item/roller/robo,
/obj/item/borg/cyborghug/medical,
/obj/item/stack/medical/gauze/cyborg,
/obj/item/stack/medical/bone_gel/cyborg,
/obj/item/organ_storage,
/obj/item/borg/lollipop,
/obj/item/sensor_device,
/obj/item/twohanded/shockpaddles/cyborg)
/obj/item/shockpaddles/cyborg)
emag_modules = list(/obj/item/reagent_containers/borghypo/hacked)
ratvar_modules = list(
/obj/item/clockwork/slab/cyborg/medical,
@@ -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'
@@ -444,7 +443,7 @@
/obj/item/t_scanner,
/obj/item/analyzer,
/obj/item/storage/part_replacer/cyborg,
/obj/item/holosign_creator/atmos,
/obj/item/holosign_creator/combifan,
/obj/item/weapon/gripper,
/obj/item/lightreplacer/cyborg,
/obj/item/geiger_counter/cyborg,
@@ -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"
@@ -779,9 +772,8 @@
/obj/item/toy/crayon/spraycan/borg,
/obj/item/hand_labeler/borg,
/obj/item/razor,
/obj/item/rsf,
/obj/item/instrument/violin,
/obj/item/instrument/guitar,
/obj/item/rsf/cyborg,
/obj/item/instrument/piano_synth,
/obj/item/reagent_containers/dropper,
/obj/item/lighter,
/obj/item/storage/bag/tray,
@@ -835,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")
@@ -851,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"
@@ -923,7 +912,7 @@
/obj/item/borg/sight/meson,
/obj/item/storage/bag/ore/cyborg,
/obj/item/pickaxe/drill/cyborg,
/obj/item/twohanded/kinetic_crusher/cyborg,
/obj/item/kinetic_crusher/cyborg,
/obj/item/weldingtool/mini,
/obj/item/storage/bag/sheetsnatcher/borg,
/obj/item/t_scanner/adv_mining_scanner,
@@ -955,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)
@@ -1000,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 ..()
@@ -1043,7 +1029,7 @@
/obj/item/extinguisher/mini,
/obj/item/crowbar/cyborg,
/obj/item/reagent_containers/borghypo/syndicate,
/obj/item/twohanded/shockpaddles/syndicate,
/obj/item/shockpaddles/syndicate,
/obj/item/healthanalyzer/advanced,
/obj/item/surgical_drapes/advanced,
/obj/item/retractor,
@@ -1051,6 +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

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