@@ -1,145 +0,0 @@
|
||||
/mob/living/carbon/alien
|
||||
name = "alien"
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
gender = FEMALE //All xenos are girls!!
|
||||
dna = null
|
||||
faction = list(ROLE_ALIEN)
|
||||
ventcrawler = VENTCRAWLER_ALWAYS
|
||||
sight = SEE_MOBS
|
||||
see_in_dark = 4
|
||||
verb_say = "hisses"
|
||||
initial_language_holder = /datum/language_holder/alien
|
||||
bubble_icon = "alien"
|
||||
type_of_meat = /obj/item/reagent_containers/food/snacks/meat/slab/xeno
|
||||
|
||||
var/obj/item/card/id/wear_id = null // Fix for station bounced radios -- Skie
|
||||
var/has_fine_manipulation = 0
|
||||
var/move_delay_add = 0 // movement delay to add
|
||||
|
||||
status_flags = CANUNCONSCIOUS|CANPUSH
|
||||
|
||||
var/heat_protection = 0.5
|
||||
var/leaping = 0
|
||||
gib_type = /obj/effect/decal/cleanable/blood/gibs/xeno
|
||||
unique_name = 1
|
||||
|
||||
var/static/regex/alien_name_regex = new("alien (larva|sentinel|drone|hunter|praetorian|queen)( \\(\\d+\\))?")
|
||||
|
||||
/mob/living/carbon/alien/Initialize()
|
||||
verbs += /mob/living/proc/mob_sleep
|
||||
verbs += /mob/living/proc/lay_down
|
||||
|
||||
create_bodyparts() //initialize bodyparts
|
||||
|
||||
create_internal_organs()
|
||||
|
||||
. = ..()
|
||||
|
||||
/mob/living/carbon/alien/create_internal_organs()
|
||||
internal_organs += new /obj/item/organ/brain/alien
|
||||
internal_organs += new /obj/item/organ/alien/hivenode
|
||||
internal_organs += new /obj/item/organ/tongue/alien
|
||||
internal_organs += new /obj/item/organ/eyes/night_vision/alien
|
||||
internal_organs += new /obj/item/organ/ears
|
||||
..()
|
||||
|
||||
/mob/living/carbon/alien/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) // beepsky won't hunt aliums
|
||||
return -10
|
||||
|
||||
/mob/living/carbon/alien/handle_environment(datum/gas_mixture/environment)
|
||||
if(!environment)
|
||||
return
|
||||
|
||||
var/loc_temp = get_temperature(environment)
|
||||
|
||||
// Aliens are now weak to fire.
|
||||
|
||||
//After then, it reacts to the surrounding atmosphere based on your thermal protection
|
||||
if(!on_fire) // If you're on fire, ignore local air temperature
|
||||
if(loc_temp > bodytemperature)
|
||||
//Place is hotter than we are
|
||||
var/thermal_protection = heat_protection //This returns a 0 - 1 value, which corresponds to the percentage of heat protection.
|
||||
if(thermal_protection < 1)
|
||||
adjust_bodytemperature((1-thermal_protection) * ((loc_temp - bodytemperature) / BODYTEMP_HEAT_DIVISOR))
|
||||
else
|
||||
adjust_bodytemperature(1 * ((loc_temp - bodytemperature) / BODYTEMP_HEAT_DIVISOR))
|
||||
|
||||
if(bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT)
|
||||
//Body temperature is too hot.
|
||||
throw_alert("alien_fire", /obj/screen/alert/alien_fire)
|
||||
switch(bodytemperature)
|
||||
if(360 to 400)
|
||||
apply_damage(HEAT_DAMAGE_LEVEL_1, BURN)
|
||||
if(400 to 460)
|
||||
apply_damage(HEAT_DAMAGE_LEVEL_2, BURN)
|
||||
if(460 to INFINITY)
|
||||
if(on_fire)
|
||||
apply_damage(HEAT_DAMAGE_LEVEL_3, BURN)
|
||||
else
|
||||
apply_damage(HEAT_DAMAGE_LEVEL_2, BURN)
|
||||
else
|
||||
clear_alert("alien_fire")
|
||||
|
||||
/mob/living/carbon/alien/reagent_check(datum/reagent/R) //can metabolize all reagents
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/alien/IsAdvancedToolUser()
|
||||
return has_fine_manipulation
|
||||
|
||||
/mob/living/carbon/alien/Stat()
|
||||
..()
|
||||
|
||||
if(statpanel("Status"))
|
||||
stat(null, "Intent: [a_intent]")
|
||||
|
||||
/mob/living/carbon/alien/getTrail()
|
||||
if(getBruteLoss() < 200)
|
||||
return pick (list("xltrails_1", "xltrails2"))
|
||||
else
|
||||
return pick (list("xttrails_1", "xttrails2"))
|
||||
/*----------------------------------------
|
||||
Proc: AddInfectionImages()
|
||||
Des: Gives the client of the alien an image on each infected mob.
|
||||
----------------------------------------*/
|
||||
/mob/living/carbon/alien/proc/AddInfectionImages()
|
||||
if (client)
|
||||
for (var/i in GLOB.mob_living_list)
|
||||
var/mob/living/L = i
|
||||
if(HAS_TRAIT(L, TRAIT_XENO_HOST))
|
||||
var/obj/item/organ/body_egg/alien_embryo/A = L.getorgan(/obj/item/organ/body_egg/alien_embryo)
|
||||
if(A)
|
||||
var/I = image('icons/mob/alien.dmi', loc = L, icon_state = "infected[A.stage]")
|
||||
client.images += I
|
||||
return
|
||||
|
||||
|
||||
/*----------------------------------------
|
||||
Proc: RemoveInfectionImages()
|
||||
Des: Removes all infected images from the alien.
|
||||
----------------------------------------*/
|
||||
/mob/living/carbon/alien/proc/RemoveInfectionImages()
|
||||
if (client)
|
||||
for(var/image/I in client.images)
|
||||
if(dd_hasprefix_case(I.icon_state, "infected"))
|
||||
qdel(I)
|
||||
return
|
||||
|
||||
/mob/living/carbon/alien/canBeHandcuffed()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/alien/get_standard_pixel_y_offset(lying = 0)
|
||||
return initial(pixel_y)
|
||||
|
||||
/mob/living/carbon/alien/proc/alien_evolve(mob/living/carbon/alien/new_xeno)
|
||||
to_chat(src, "<span class='noticealien'>You begin to evolve!</span>")
|
||||
visible_message("<span class='alertalien'>[src] begins to twist and contort!</span>")
|
||||
new_xeno.setDir(dir)
|
||||
if(!alien_name_regex.Find(name))
|
||||
new_xeno.name = name
|
||||
new_xeno.real_name = real_name
|
||||
if(mind)
|
||||
mind.transfer_to(new_xeno)
|
||||
qdel(src)
|
||||
|
||||
/mob/living/carbon/alien/can_hold_items()
|
||||
return has_fine_manipulation
|
||||
@@ -1,15 +0,0 @@
|
||||
/mob/living/carbon/alien/spawn_gibs(with_bodyparts, atom/loc_override)
|
||||
var/location = loc_override ? loc_override.drop_location() : drop_location()
|
||||
if(with_bodyparts)
|
||||
new /obj/effect/gibspawner/xeno(location, src)
|
||||
else
|
||||
new /obj/effect/gibspawner/xeno/bodypartless(location, src)
|
||||
|
||||
/mob/living/carbon/alien/gib_animation()
|
||||
new /obj/effect/temp_visual/gib_animation(loc, "gibbed-a")
|
||||
|
||||
/mob/living/carbon/alien/spawn_dust()
|
||||
new /obj/effect/decal/remains/xeno(loc)
|
||||
|
||||
/mob/living/carbon/alien/dust_animation()
|
||||
new /obj/effect/temp_visual/dust_animation(loc, "dust-a")
|
||||
@@ -1,353 +0,0 @@
|
||||
/*NOTES:
|
||||
These are general powers. Specific powers are stored under the appropriate alien creature type.
|
||||
*/
|
||||
|
||||
/*Alien spit now works like a taser shot. It won't home in on the target but will act the same once it does hit.
|
||||
Doesn't work on other aliens/AI.*/
|
||||
|
||||
|
||||
/obj/effect/proc_holder/alien
|
||||
name = "Alien Power"
|
||||
panel = "Alien"
|
||||
var/plasma_cost = 0
|
||||
var/check_turf = FALSE
|
||||
has_action = TRUE
|
||||
base_action = /datum/action/spell_action/alien
|
||||
action_icon = 'icons/mob/actions/actions_xeno.dmi'
|
||||
action_icon_state = "spell_default"
|
||||
action_background_icon_state = "bg_alien"
|
||||
|
||||
/obj/effect/proc_holder/alien/Initialize()
|
||||
. = ..()
|
||||
action = new(src)
|
||||
|
||||
/obj/effect/proc_holder/alien/Click()
|
||||
if(!iscarbon(usr))
|
||||
return 1
|
||||
var/mob/living/carbon/user = usr
|
||||
if(cost_check(check_turf,user))
|
||||
if(fire(user) && user) // Second check to prevent runtimes when evolving
|
||||
user.adjustPlasma(-plasma_cost)
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/alien/on_gain(mob/living/carbon/user)
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/alien/on_lose(mob/living/carbon/user)
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/alien/fire(mob/living/carbon/user)
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/alien/get_panel_text()
|
||||
. = ..()
|
||||
if(plasma_cost > 0)
|
||||
return "[plasma_cost]"
|
||||
|
||||
/obj/effect/proc_holder/alien/proc/cost_check(check_turf = FALSE, mob/living/carbon/user, silent = FALSE)
|
||||
if(user.stat)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='noticealien'>You must be conscious to do this.</span>")
|
||||
return FALSE
|
||||
if(user.getPlasma() < plasma_cost)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='noticealien'>Not enough plasma stored.</span>")
|
||||
return FALSE
|
||||
if(check_turf && (!isturf(user.loc) || isspaceturf(user.loc)))
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='noticealien'>Bad place for a garden!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/alien/proc/check_vent_block(mob/living/user)
|
||||
var/obj/machinery/atmospherics/components/unary/atmos_thing = locate() in user.loc
|
||||
if(atmos_thing)
|
||||
var/rusure = alert(user, "Laying eggs and shaping resin here would block access to [atmos_thing]. Do you want to continue?", "Blocking Atmospheric Component", "Yes", "No")
|
||||
if(rusure != "Yes")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/alien/plant
|
||||
name = "Plant Weeds"
|
||||
desc = "Plants some alien weeds."
|
||||
plasma_cost = 50
|
||||
check_turf = TRUE
|
||||
action_icon_state = "alien_plant"
|
||||
|
||||
/obj/effect/proc_holder/alien/plant/fire(mob/living/carbon/user)
|
||||
if(locate(/obj/structure/alien/weeds/node) in get_turf(user))
|
||||
to_chat(user, "There's already a weed node here.")
|
||||
return 0
|
||||
user.visible_message("<span class='alertalien'>[user] has planted some alien weeds!</span>")
|
||||
new/obj/structure/alien/weeds/node(user.loc)
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/alien/whisper
|
||||
name = "Whisper"
|
||||
desc = "Whisper to someone."
|
||||
plasma_cost = 10
|
||||
action_icon_state = "alien_whisper"
|
||||
|
||||
/obj/effect/proc_holder/alien/whisper/fire(mob/living/carbon/user)
|
||||
var/list/options = list()
|
||||
for(var/mob/living/Ms in oview(user))
|
||||
options += Ms
|
||||
var/mob/living/M = input("Select who to whisper to:","Whisper to?",null) as null|mob in options
|
||||
if(!M)
|
||||
return 0
|
||||
if(M.anti_magic_check(FALSE, FALSE, TRUE, 0))
|
||||
to_chat(user, "<span class='noticealien'>As you try to communicate with [M], you're suddenly stopped by a vision of a massive tinfoil wall that streches beyond visible range. It seems you've been foiled.</span>")
|
||||
return FALSE
|
||||
var/msg = sanitize(input("Message:", "Alien Whisper") as text|null)
|
||||
if(msg)
|
||||
if(M.anti_magic_check(FALSE, FALSE, TRUE, 0))
|
||||
to_chat(user, "<span class='notice'>As you try to communicate with [M], you're suddenly stopped by a vision of a massive tinfoil wall that streches beyond visible range. It seems you've been foiled.</span>")
|
||||
return
|
||||
log_directed_talk(user, M, msg, LOG_SAY, tag="alien whisper")
|
||||
to_chat(M, "<span class='noticealien'>You hear a strange, alien voice in your head...</span>[msg]")
|
||||
to_chat(user, "<span class='noticealien'>You said: \"[msg]\" to [M]</span>")
|
||||
for(var/ded in GLOB.dead_mob_list)
|
||||
if(!isobserver(ded))
|
||||
continue
|
||||
var/follow_link_user = FOLLOW_LINK(ded, user)
|
||||
var/follow_link_whispee = FOLLOW_LINK(ded, M)
|
||||
to_chat(ded, "[follow_link_user] <span class='name'>[user]</span> <span class='alertalien'>Alien Whisper --> </span> [follow_link_whispee] <span class='name'>[M]</span> <span class='noticealien'>[msg]</span>")
|
||||
else
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/alien/transfer
|
||||
name = "Transfer Plasma"
|
||||
desc = "Transfer Plasma to another alien."
|
||||
plasma_cost = 0
|
||||
action_icon_state = "alien_transfer"
|
||||
|
||||
/obj/effect/proc_holder/alien/transfer/fire(mob/living/carbon/user)
|
||||
var/list/mob/living/carbon/aliens_around = list()
|
||||
for(var/mob/living/carbon/A in oview(user))
|
||||
if(A.getorgan(/obj/item/organ/alien/plasmavessel))
|
||||
aliens_around.Add(A)
|
||||
var/mob/living/carbon/M = input("Select who to transfer to:","Transfer plasma to?",null) as mob in aliens_around
|
||||
if(!M)
|
||||
return 0
|
||||
var/amount = input("Amount:", "Transfer Plasma to [M]") as num
|
||||
if (amount)
|
||||
amount = min(abs(round(amount)), user.getPlasma())
|
||||
if (get_dist(user,M) <= 1)
|
||||
M.adjustPlasma(amount)
|
||||
user.adjustPlasma(-amount)
|
||||
to_chat(M, "<span class='noticealien'>[user] has transferred [amount] plasma to you.</span>")
|
||||
to_chat(user, "<span class='noticealien'>You transfer [amount] plasma to [M]</span>")
|
||||
else
|
||||
to_chat(user, "<span class='noticealien'>You need to be closer!</span>")
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/alien/acid
|
||||
name = "Corrosive Acid"
|
||||
desc = "Drench an object in acid, destroying it over time."
|
||||
plasma_cost = 200
|
||||
action_icon_state = "alien_acid"
|
||||
|
||||
/obj/effect/proc_holder/alien/acid/on_gain(mob/living/carbon/user)
|
||||
user.verbs.Add(/mob/living/carbon/proc/corrosive_acid)
|
||||
|
||||
/obj/effect/proc_holder/alien/acid/on_lose(mob/living/carbon/user)
|
||||
user.verbs.Remove(/mob/living/carbon/proc/corrosive_acid)
|
||||
|
||||
/obj/effect/proc_holder/alien/acid/proc/corrode(atom/target,mob/living/carbon/user = usr)
|
||||
if(target in oview(1,user))
|
||||
if(target.acid_act(200, 100))
|
||||
user.visible_message("<span class='alertalien'>[user] vomits globs of vile stuff all over [target]. It begins to sizzle and melt under the bubbling mess of acid!</span>")
|
||||
return 1
|
||||
else
|
||||
to_chat(user, "<span class='noticealien'>You cannot dissolve this object.</span>")
|
||||
|
||||
|
||||
return 0
|
||||
else
|
||||
to_chat(src, "<span class='noticealien'>[target] is too far away.</span>")
|
||||
return 0
|
||||
|
||||
|
||||
/obj/effect/proc_holder/alien/acid/fire(mob/living/carbon/alien/user)
|
||||
var/O = input("Select what to dissolve:","Dissolve",null) as obj|turf in oview(1,user)
|
||||
if(!O || user.incapacitated())
|
||||
return 0
|
||||
else
|
||||
return corrode(O,user)
|
||||
|
||||
/mob/living/carbon/proc/corrosive_acid(O as obj|turf in oview(1)) // right click menu verb ugh
|
||||
set name = "Corrosive Acid"
|
||||
|
||||
if(!iscarbon(usr))
|
||||
return
|
||||
var/mob/living/carbon/user = usr
|
||||
var/obj/effect/proc_holder/alien/acid/A = locate() in user.abilities
|
||||
if(!A)
|
||||
return
|
||||
if(user.getPlasma() > A.plasma_cost && A.corrode(O))
|
||||
user.adjustPlasma(-A.plasma_cost)
|
||||
|
||||
/obj/effect/proc_holder/alien/neurotoxin
|
||||
name = "Spit Neurotoxin"
|
||||
desc = "Spits neurotoxin at someone, paralyzing them for a short time."
|
||||
action_icon_state = "alien_neurotoxin_0"
|
||||
active = FALSE
|
||||
|
||||
/obj/effect/proc_holder/alien/neurotoxin/fire(mob/living/carbon/user)
|
||||
var/message
|
||||
if(active)
|
||||
message = "<span class='notice'>You empty your neurotoxin gland.</span>"
|
||||
remove_ranged_ability(message)
|
||||
else
|
||||
message = "<span class='notice'>You prepare your neurotoxin gland. <B>Left-click to fire at a target!</B></span>"
|
||||
add_ranged_ability(user, message, TRUE)
|
||||
|
||||
/obj/effect/proc_holder/alien/neurotoxin/update_icon()
|
||||
action.button_icon_state = "alien_neurotoxin_[active]"
|
||||
action.UpdateButtonIcon()
|
||||
|
||||
/obj/effect/proc_holder/alien/neurotoxin/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..())
|
||||
return
|
||||
var/p_cost = 50
|
||||
if(!iscarbon(ranged_ability_user) || ranged_ability_user.lying || ranged_ability_user.stat)
|
||||
remove_ranged_ability()
|
||||
return
|
||||
|
||||
var/mob/living/carbon/user = ranged_ability_user
|
||||
|
||||
if(user.getPlasma() < p_cost)
|
||||
to_chat(user, "<span class='warning'>You need at least [p_cost] plasma to spit.</span>")
|
||||
remove_ranged_ability()
|
||||
return
|
||||
|
||||
var/turf/T = user.loc
|
||||
var/turf/U = get_step(user, user.dir) // Get the tile infront of the move, based on their direction
|
||||
if(!isturf(U) || !isturf(T))
|
||||
return FALSE
|
||||
|
||||
user.visible_message("<span class='danger'>[user] spits neurotoxin!", "<span class='alertalien'>You spit neurotoxin.</span>")
|
||||
var/obj/item/projectile/bullet/neurotoxin/A = new /obj/item/projectile/bullet/neurotoxin(user.loc)
|
||||
A.preparePixelProjectile(target, user, params)
|
||||
A.fire()
|
||||
user.newtonian_move(get_dir(U, T))
|
||||
user.adjustPlasma(-p_cost)
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/alien/neurotoxin/on_lose(mob/living/carbon/user)
|
||||
remove_ranged_ability()
|
||||
|
||||
/obj/effect/proc_holder/alien/neurotoxin/add_ranged_ability(mob/living/user,msg,forced)
|
||||
..()
|
||||
if(isalienadult(user))
|
||||
var/mob/living/carbon/alien/humanoid/A = user
|
||||
A.drooling = 1
|
||||
A.update_icons()
|
||||
|
||||
/obj/effect/proc_holder/alien/neurotoxin/remove_ranged_ability(msg)
|
||||
if(isalienadult(ranged_ability_user))
|
||||
var/mob/living/carbon/alien/humanoid/A = ranged_ability_user
|
||||
A.drooling = 0
|
||||
A.update_icons()
|
||||
..()
|
||||
|
||||
/obj/effect/proc_holder/alien/resin
|
||||
name = "Secrete Resin"
|
||||
desc = "Secrete tough malleable resin."
|
||||
plasma_cost = 55
|
||||
check_turf = TRUE
|
||||
var/list/structures = list(
|
||||
"resin wall" = /obj/structure/alien/resin/wall,
|
||||
"resin membrane" = /obj/structure/alien/resin/membrane,
|
||||
"resin nest" = /obj/structure/bed/nest)
|
||||
|
||||
action_icon_state = "alien_resin"
|
||||
|
||||
/obj/effect/proc_holder/alien/resin/fire(mob/living/carbon/user)
|
||||
if(locate(/obj/structure/alien/resin) in user.loc)
|
||||
to_chat(user, "<span class='danger'>There is already a resin structure there.</span>")
|
||||
return FALSE
|
||||
|
||||
if(!check_vent_block(user))
|
||||
return FALSE
|
||||
|
||||
var/choice = input("Choose what you wish to shape.","Resin building") as null|anything in structures
|
||||
if(!choice)
|
||||
return FALSE
|
||||
if (!cost_check(check_turf,user))
|
||||
return FALSE
|
||||
to_chat(user, "<span class='notice'>You shape a [choice].</span>")
|
||||
user.visible_message("<span class='notice'>[user] vomits up a thick purple substance and begins to shape it.</span>")
|
||||
|
||||
choice = structures[choice]
|
||||
new choice(user.loc)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/alien/regurgitate
|
||||
name = "Regurgitate"
|
||||
desc = "Empties the contents of your stomach."
|
||||
plasma_cost = 0
|
||||
action_icon_state = "alien_barf"
|
||||
|
||||
/obj/effect/proc_holder/alien/regurgitate/fire(mob/living/carbon/user)
|
||||
if(user.stomach_contents.len)
|
||||
for(var/atom/movable/A in user.stomach_contents)
|
||||
user.stomach_contents.Remove(A)
|
||||
A.forceMove(user.drop_location())
|
||||
if(isliving(A))
|
||||
var/mob/M = A
|
||||
M.reset_perspective()
|
||||
user.visible_message("<span class='alertealien'>[user] hurls out the contents of their stomach!</span>")
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/alien/sneak
|
||||
name = "Sneak"
|
||||
desc = "Blend into the shadows to stalk your prey."
|
||||
active = 0
|
||||
|
||||
action_icon_state = "alien_sneak"
|
||||
|
||||
/obj/effect/proc_holder/alien/sneak/fire(mob/living/carbon/alien/humanoid/user)
|
||||
if(!active)
|
||||
user.alpha = 75 //Still easy to see in lit areas with bright tiles, almost invisible on resin.
|
||||
user.sneaking = 1
|
||||
active = 1
|
||||
to_chat(user, "<span class='noticealien'>You blend into the shadows...</span>")
|
||||
else
|
||||
user.alpha = initial(user.alpha)
|
||||
user.sneaking = 0
|
||||
active = 0
|
||||
to_chat(user, "<span class='noticealien'>You reveal yourself!</span>")
|
||||
|
||||
|
||||
/mob/living/carbon/proc/getPlasma()
|
||||
var/obj/item/organ/alien/plasmavessel/vessel = getorgan(/obj/item/organ/alien/plasmavessel)
|
||||
if(!vessel)
|
||||
return 0
|
||||
return vessel.storedPlasma
|
||||
|
||||
|
||||
/mob/living/carbon/proc/adjustPlasma(amount)
|
||||
var/obj/item/organ/alien/plasmavessel/vessel = getorgan(/obj/item/organ/alien/plasmavessel)
|
||||
if(!vessel)
|
||||
return 0
|
||||
vessel.storedPlasma = max(vessel.storedPlasma + amount,0)
|
||||
vessel.storedPlasma = min(vessel.storedPlasma, vessel.max_plasma) //upper limit of max_plasma, lower limit of 0
|
||||
for(var/X in abilities)
|
||||
var/obj/effect/proc_holder/alien/APH = X
|
||||
if(APH.has_action)
|
||||
APH.action.UpdateButtonIcon()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/alien/adjustPlasma(amount)
|
||||
. = ..()
|
||||
updatePlasmaDisplay()
|
||||
|
||||
/mob/living/carbon/proc/usePlasma(amount)
|
||||
if(getPlasma() >= amount)
|
||||
adjustPlasma(-amount)
|
||||
return 1
|
||||
|
||||
return 0
|
||||
@@ -1,23 +0,0 @@
|
||||
/mob/living/carbon/alien/larva/death(gibbed)
|
||||
if(stat == DEAD)
|
||||
return
|
||||
|
||||
. = ..()
|
||||
|
||||
update_icons()
|
||||
|
||||
/mob/living/carbon/alien/larva/spawn_gibs(with_bodyparts, atom/loc_override)
|
||||
var/location = loc_override ? loc_override.drop_location() : drop_location()
|
||||
if(with_bodyparts)
|
||||
new /obj/effect/gibspawner/larva(location, src)
|
||||
else
|
||||
new /obj/effect/gibspawner/larva/bodypartless(location, src)
|
||||
|
||||
/mob/living/carbon/alien/larva/gib_animation()
|
||||
new /obj/effect/temp_visual/gib_animation(loc, "gibbed-l")
|
||||
|
||||
/mob/living/carbon/alien/larva/spawn_dust()
|
||||
new /obj/effect/decal/remains/xeno(loc)
|
||||
|
||||
/mob/living/carbon/alien/larva/dust_animation()
|
||||
new /obj/effect/temp_visual/dust_animation(loc, "dust-l")
|
||||
@@ -1,193 +0,0 @@
|
||||
/obj/item/organ/alien
|
||||
icon_state = "xgibmid2"
|
||||
var/list/alien_powers = list()
|
||||
organ_flags = ORGAN_NO_SPOIL
|
||||
|
||||
/obj/item/organ/alien/Initialize()
|
||||
. = ..()
|
||||
for(var/A in alien_powers)
|
||||
if(ispath(A))
|
||||
alien_powers -= A
|
||||
alien_powers += new A(src)
|
||||
|
||||
/obj/item/organ/alien/Destroy()
|
||||
QDEL_LIST(alien_powers)
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/alien/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
|
||||
..()
|
||||
for(var/obj/effect/proc_holder/alien/P in alien_powers)
|
||||
M.AddAbility(P)
|
||||
|
||||
|
||||
/obj/item/organ/alien/Remove(mob/living/carbon/M, special = 0)
|
||||
for(var/obj/effect/proc_holder/alien/P in alien_powers)
|
||||
M.RemoveAbility(P)
|
||||
..()
|
||||
|
||||
/obj/item/organ/alien/prepare_eat()
|
||||
var/obj/S = ..()
|
||||
S.reagents.add_reagent("sacid", 10)
|
||||
return S
|
||||
|
||||
|
||||
/obj/item/organ/alien/plasmavessel
|
||||
name = "plasma vessel"
|
||||
icon_state = "plasma"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
zone = BODY_ZONE_CHEST
|
||||
slot = "plasmavessel"
|
||||
alien_powers = list(/obj/effect/proc_holder/alien/plant, /obj/effect/proc_holder/alien/transfer)
|
||||
|
||||
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("plasma", storedPlasma/10)
|
||||
return S
|
||||
|
||||
/obj/item/organ/alien/plasmavessel/large
|
||||
name = "large plasma vessel"
|
||||
icon_state = "plasma_large"
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
storedPlasma = 200
|
||||
max_plasma = 500
|
||||
plasma_rate = 15
|
||||
|
||||
/obj/item/organ/alien/plasmavessel/large/queen
|
||||
plasma_rate = 20
|
||||
|
||||
/obj/item/organ/alien/plasmavessel/small
|
||||
name = "small plasma vessel"
|
||||
icon_state = "plasma_small"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
storedPlasma = 100
|
||||
max_plasma = 150
|
||||
plasma_rate = 5
|
||||
|
||||
/obj/item/organ/alien/plasmavessel/small/tiny
|
||||
name = "tiny plasma vessel"
|
||||
icon_state = "plasma_tiny"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
max_plasma = 100
|
||||
alien_powers = list(/obj/effect/proc_holder/alien/transfer)
|
||||
|
||||
/obj/item/organ/alien/plasmavessel/on_life()
|
||||
//If there are alien weeds on the ground then heal if needed or give some plasma
|
||||
if(locate(/obj/structure/alien/weeds) in owner.loc)
|
||||
if(owner.health >= owner.maxHealth)
|
||||
owner.adjustPlasma(plasma_rate)
|
||||
else
|
||||
var/heal_amt = heal_rate
|
||||
if(!isalien(owner))
|
||||
heal_amt *= 0.2
|
||||
owner.adjustPlasma(plasma_rate*0.5)
|
||||
owner.adjustBruteLoss(-heal_amt)
|
||||
owner.adjustFireLoss(-heal_amt)
|
||||
owner.adjustOxyLoss(-heal_amt)
|
||||
owner.adjustCloneLoss(-heal_amt)
|
||||
if(owner.blood_volume && (owner.blood_volume < BLOOD_VOLUME_NORMAL))
|
||||
owner.blood_volume += 5
|
||||
else
|
||||
owner.adjustPlasma(plasma_rate * 0.1)
|
||||
|
||||
/obj/item/organ/alien/plasmavessel/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
|
||||
..()
|
||||
if(isalien(M))
|
||||
var/mob/living/carbon/alien/A = M
|
||||
A.updatePlasmaDisplay()
|
||||
|
||||
/obj/item/organ/alien/plasmavessel/Remove(mob/living/carbon/M, special = 0)
|
||||
..()
|
||||
if(isalien(M))
|
||||
var/mob/living/carbon/alien/A = M
|
||||
A.updatePlasmaDisplay()
|
||||
|
||||
#define QUEEN_DEATH_DEBUFF_DURATION 2400
|
||||
|
||||
/obj/item/organ/alien/hivenode
|
||||
name = "hive node"
|
||||
icon_state = "hivenode"
|
||||
zone = BODY_ZONE_HEAD
|
||||
slot = "hivenode"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/recent_queen_death = 0 //Indicates if the queen died recently, aliens are heavily weakened while this is active.
|
||||
alien_powers = list(/obj/effect/proc_holder/alien/whisper)
|
||||
|
||||
/obj/item/organ/alien/hivenode/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
|
||||
..()
|
||||
M.faction |= ROLE_ALIEN
|
||||
|
||||
/obj/item/organ/alien/hivenode/Remove(mob/living/carbon/M, special = 0)
|
||||
M.faction -= ROLE_ALIEN
|
||||
..()
|
||||
|
||||
//When the alien queen dies, all aliens suffer a penalty as punishment for failing to protect her.
|
||||
/obj/item/organ/alien/hivenode/proc/queen_death()
|
||||
if(!owner|| owner.stat == DEAD)
|
||||
return
|
||||
if(isalien(owner)) //Different effects for aliens than humans
|
||||
to_chat(owner, "<span class='userdanger'>Your Queen has been struck down!</span>")
|
||||
to_chat(owner, "<span class='danger'>You are struck with overwhelming agony! You feel confused, and your connection to the hivemind is severed.</span>")
|
||||
owner.emote("roar")
|
||||
owner.Stun(200) //Actually just slows them down a bit.
|
||||
|
||||
else if(ishuman(owner)) //Humans, being more fragile, are more overwhelmed by the mental backlash.
|
||||
to_chat(owner, "<span class='danger'>You feel a splitting pain in your head, and are struck with a wave of nausea. You cannot hear the hivemind anymore!</span>")
|
||||
owner.emote("scream")
|
||||
owner.Knockdown(100)
|
||||
|
||||
owner.jitteriness += 30
|
||||
owner.confused += 30
|
||||
owner.stuttering += 30
|
||||
|
||||
recent_queen_death = 1
|
||||
owner.throw_alert("alien_noqueen", /obj/screen/alert/alien_vulnerable)
|
||||
addtimer(CALLBACK(src, .proc/clear_queen_death), QUEEN_DEATH_DEBUFF_DURATION)
|
||||
|
||||
|
||||
/obj/item/organ/alien/hivenode/proc/clear_queen_death()
|
||||
if(QDELETED(src)) //In case the node is deleted
|
||||
return
|
||||
recent_queen_death = 0
|
||||
if(!owner) //In case the xeno is butchered or subjected to surgery after death.
|
||||
return
|
||||
to_chat(owner, "<span class='noticealien'>The pain of the queen's death is easing. You begin to hear the hivemind again.</span>")
|
||||
owner.clear_alert("alien_noqueen")
|
||||
|
||||
#undef QUEEN_DEATH_DEBUFF_DURATION
|
||||
|
||||
/obj/item/organ/alien/resinspinner
|
||||
name = "resin spinner"
|
||||
icon_state = "stomach-x"
|
||||
zone = BODY_ZONE_PRECISE_MOUTH
|
||||
slot = "resinspinner"
|
||||
alien_powers = list(/obj/effect/proc_holder/alien/resin)
|
||||
|
||||
|
||||
/obj/item/organ/alien/acid
|
||||
name = "acid gland"
|
||||
icon_state = "acid"
|
||||
zone = BODY_ZONE_PRECISE_MOUTH
|
||||
slot = "acidgland"
|
||||
alien_powers = list(/obj/effect/proc_holder/alien/acid)
|
||||
|
||||
|
||||
/obj/item/organ/alien/neurotoxin
|
||||
name = "neurotoxin gland"
|
||||
icon_state = "neurotox"
|
||||
zone = BODY_ZONE_PRECISE_MOUTH
|
||||
slot = "neurotoxingland"
|
||||
alien_powers = list(/obj/effect/proc_holder/alien/neurotoxin)
|
||||
|
||||
|
||||
/obj/item/organ/alien/eggsac
|
||||
name = "egg sac"
|
||||
icon_state = "eggsac"
|
||||
zone = BODY_ZONE_PRECISE_GROIN
|
||||
slot = "eggsac"
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
alien_powers = list(/obj/effect/proc_holder/alien/lay_egg)
|
||||
@@ -1,137 +0,0 @@
|
||||
// This is to replace the previous datum/disease/alien_embryo for slightly improved handling and maintainability
|
||||
// It functions almost identically (see code/datums/diseases/alien_embryo.dm)
|
||||
/obj/item/organ/body_egg/alien_embryo
|
||||
name = "alien embryo"
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
icon_state = "larva0_dead"
|
||||
var/stage = 0
|
||||
var/bursting = FALSE
|
||||
|
||||
/obj/item/organ/body_egg/alien_embryo/on_find(mob/living/finder)
|
||||
..()
|
||||
if(stage < 4)
|
||||
to_chat(finder, "It's small and weak, barely the size of a foetus.")
|
||||
else
|
||||
to_chat(finder, "It's grown quite large, and writhes slightly as you look at it.")
|
||||
if(prob(10))
|
||||
AttemptGrow(0)
|
||||
|
||||
/obj/item/organ/body_egg/alien_embryo/prepare_eat()
|
||||
var/obj/S = ..()
|
||||
S.reagents.add_reagent("sacid", 10)
|
||||
return S
|
||||
|
||||
/obj/item/organ/body_egg/alien_embryo/on_life()
|
||||
. = ..()
|
||||
switch(stage)
|
||||
if(2, 3)
|
||||
if(prob(2))
|
||||
owner.emote("sneeze")
|
||||
if(prob(2))
|
||||
owner.emote("cough")
|
||||
if(prob(2))
|
||||
to_chat(owner, "<span class='danger'>Your throat feels sore.</span>")
|
||||
if(prob(2))
|
||||
to_chat(owner, "<span class='danger'>Mucous runs down the back of your throat.</span>")
|
||||
if(4)
|
||||
if(prob(2))
|
||||
owner.emote("sneeze")
|
||||
if(prob(2))
|
||||
owner.emote("cough")
|
||||
if(prob(4))
|
||||
to_chat(owner, "<span class='danger'>Your muscles ache.</span>")
|
||||
if(prob(20))
|
||||
owner.take_bodypart_damage(1)
|
||||
if(prob(4))
|
||||
to_chat(owner, "<span class='danger'>Your stomach hurts.</span>")
|
||||
if(prob(20))
|
||||
owner.adjustToxLoss(1)
|
||||
if(5)
|
||||
to_chat(owner, "<span class='danger'>You feel something tearing its way out of your stomach...</span>")
|
||||
owner.adjustToxLoss(10)
|
||||
|
||||
/obj/item/organ/body_egg/alien_embryo/egg_process()
|
||||
if(stage < 5 && prob(3))
|
||||
stage++
|
||||
INVOKE_ASYNC(src, .proc/RefreshInfectionImage)
|
||||
|
||||
if(stage == 5 && prob(50))
|
||||
for(var/datum/surgery/S in owner.surgeries)
|
||||
if(S.location == BODY_ZONE_CHEST && istype(S.get_surgery_step(), /datum/surgery_step/manipulate_organs))
|
||||
AttemptGrow(0)
|
||||
return
|
||||
AttemptGrow()
|
||||
|
||||
|
||||
|
||||
/obj/item/organ/body_egg/alien_embryo/proc/AttemptGrow(var/kill_on_sucess=TRUE)
|
||||
if(!owner || bursting)
|
||||
return
|
||||
|
||||
bursting = TRUE
|
||||
|
||||
var/list/candidates = pollGhostCandidates("Do you want to play as an alien larva that will burst out of [owner]?", ROLE_ALIEN, null, ROLE_ALIEN, 100, POLL_IGNORE_ALIEN_LARVA)
|
||||
|
||||
if(QDELETED(src) || QDELETED(owner))
|
||||
return
|
||||
|
||||
if(!candidates.len || !owner)
|
||||
bursting = FALSE
|
||||
stage = 4
|
||||
return
|
||||
|
||||
var/mob/dead/observer/ghost = pick(candidates)
|
||||
|
||||
var/mutable_appearance/overlay = mutable_appearance('icons/mob/alien.dmi', "burst_lie")
|
||||
owner.add_overlay(overlay)
|
||||
|
||||
var/atom/xeno_loc = get_turf(owner)
|
||||
var/mob/living/carbon/alien/larva/new_xeno = new(xeno_loc)
|
||||
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.canmove = 0 //so we don't move during the bursting animation
|
||||
new_xeno.notransform = 1
|
||||
new_xeno.invisibility = INVISIBILITY_MAXIMUM
|
||||
|
||||
sleep(6)
|
||||
|
||||
if(QDELETED(src) || QDELETED(owner))
|
||||
return
|
||||
|
||||
if(new_xeno)
|
||||
new_xeno.canmove = 1
|
||||
new_xeno.notransform = 0
|
||||
new_xeno.invisibility = 0
|
||||
|
||||
if(kill_on_sucess) //ITS TOO LATE
|
||||
new_xeno.visible_message("<span class='danger'>[new_xeno] bursts out of [owner]!</span>", "<span class='userdanger'>You exit [owner], your previous host.</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
|
||||
owner.apply_damage(rand(100,300),BRUTE,zone,FALSE) //Random high damage to torso so health sensors don't metagame.
|
||||
owner.spill_organs(TRUE,FALSE,TRUE) //Lets still make the death gruesome and impossible to just simply defib someone.
|
||||
owner.death(FALSE) //Just in case some freak occurance occurs where you somehow survive all your organs being removed from you and the 100-300 brute damage.
|
||||
else //When it is removed via surgery at a late stage, rather than forced.
|
||||
new_xeno.visible_message("<span class='danger'>[new_xeno] wriggles out of [owner]!</span>", "<span class='userdanger'>You exit [owner], your previous host.</span>")
|
||||
owner.adjustBruteLoss(40)
|
||||
owner.cut_overlay(overlay)
|
||||
qdel(src)
|
||||
|
||||
|
||||
/*----------------------------------------
|
||||
Proc: AddInfectionImages(C)
|
||||
Des: Adds the infection image to all aliens for this embryo
|
||||
----------------------------------------*/
|
||||
/obj/item/organ/body_egg/alien_embryo/AddInfectionImages(mob/living/carbon/C)
|
||||
for(var/mob/living/carbon/alien/alien in GLOB.player_list)
|
||||
if(alien.client)
|
||||
var/I = image('icons/mob/alien.dmi', loc = C, icon_state = "infected[stage]")
|
||||
alien.client.images += I
|
||||
|
||||
/*----------------------------------------
|
||||
Proc: RemoveInfectionImage(C)
|
||||
Des: Removes all images from the mob infected by this embryo
|
||||
----------------------------------------*/
|
||||
/obj/item/organ/body_egg/alien_embryo/RemoveInfectionImages(mob/living/carbon/C)
|
||||
for(var/mob/living/carbon/alien/alien in GLOB.player_list)
|
||||
if(alien.client)
|
||||
for(var/image/I in alien.client.images)
|
||||
if(dd_hasprefix_case(I.icon_state, "infected") && I.loc == C)
|
||||
qdel(I)
|
||||
@@ -1,953 +0,0 @@
|
||||
/mob/living/carbon
|
||||
blood_volume = BLOOD_VOLUME_NORMAL
|
||||
|
||||
/mob/living/carbon/Initialize()
|
||||
. = ..()
|
||||
create_reagents(1000)
|
||||
update_body_parts() //to update the carbon's new bodyparts appearance
|
||||
GLOB.carbon_list += src
|
||||
blood_volume = (BLOOD_VOLUME_NORMAL * blood_ratio)
|
||||
|
||||
/mob/living/carbon/Destroy()
|
||||
//This must be done first, so the mob ghosts correctly before DNA etc is nulled
|
||||
. = ..()
|
||||
|
||||
QDEL_LIST(internal_organs)
|
||||
QDEL_LIST(stomach_contents)
|
||||
QDEL_LIST(bodyparts)
|
||||
QDEL_LIST(implants)
|
||||
remove_from_all_data_huds()
|
||||
QDEL_NULL(dna)
|
||||
GLOB.carbon_list -= src
|
||||
|
||||
/mob/living/carbon/initialize_footstep()
|
||||
AddComponent(/datum/component/footstep, 0.6, 2)
|
||||
|
||||
/mob/living/carbon/relaymove(mob/user, direction)
|
||||
if(user in src.stomach_contents)
|
||||
if(prob(40))
|
||||
if(prob(25))
|
||||
audible_message("<span class='warning'>You hear something rumbling inside [src]'s stomach...</span>", \
|
||||
"<span class='warning'>You hear something rumbling.</span>", 4,\
|
||||
"<span class='userdanger'>Something is rumbling inside your stomach!</span>")
|
||||
var/obj/item/I = user.get_active_held_item()
|
||||
if(I && I.force)
|
||||
var/d = rand(round(I.force / 4), I.force)
|
||||
var/obj/item/bodypart/BP = get_bodypart(BODY_ZONE_CHEST)
|
||||
if(BP.receive_damage(d, 0))
|
||||
update_damage_overlays()
|
||||
visible_message("<span class='danger'>[user] attacks [src]'s stomach wall with the [I.name]!</span>", \
|
||||
"<span class='userdanger'>[user] attacks your stomach wall with the [I.name]!</span>")
|
||||
playsound(user.loc, 'sound/effects/attackblob.ogg', 50, 1)
|
||||
|
||||
if(prob(src.getBruteLoss() - 50))
|
||||
for(var/atom/movable/A in stomach_contents)
|
||||
A.forceMove(drop_location())
|
||||
stomach_contents.Remove(A)
|
||||
src.gib()
|
||||
|
||||
|
||||
/mob/living/carbon/swap_hand(held_index)
|
||||
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)
|
||||
var/obj/screen/inventory/hand/H
|
||||
H = hud_used.hand_slots["[oindex]"]
|
||||
if(H)
|
||||
H.update_icon()
|
||||
H = hud_used.hand_slots["[held_index]"]
|
||||
if(H)
|
||||
H.update_icon()
|
||||
|
||||
|
||||
/mob/living/carbon/activate_hand(selhand) //l/r OR 1-held_items.len
|
||||
if(!selhand)
|
||||
selhand = (active_hand_index % held_items.len)+1
|
||||
|
||||
if(istext(selhand))
|
||||
selhand = lowertext(selhand)
|
||||
if(selhand == "right" || selhand == "r")
|
||||
selhand = 2
|
||||
if(selhand == "left" || selhand == "l")
|
||||
selhand = 1
|
||||
|
||||
if(selhand != active_hand_index)
|
||||
swap_hand(selhand)
|
||||
else
|
||||
mode() // Activate held item
|
||||
|
||||
/mob/living/carbon/attackby(obj/item/I, mob/user, params)
|
||||
if(lying && surgeries.len)
|
||||
if(user != src && (user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM))
|
||||
for(var/datum/surgery/S in surgeries)
|
||||
if(S.next_step(user,user.a_intent))
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/throw_impact(atom/hit_atom, throwingdatum)
|
||||
. = ..()
|
||||
var/hurt = TRUE
|
||||
if(istype(throwingdatum, /datum/thrownthing))
|
||||
var/datum/thrownthing/D = throwingdatum
|
||||
if(iscyborg(D.thrower))
|
||||
var/mob/living/silicon/robot/R = D.thrower
|
||||
if(!R.emagged)
|
||||
hurt = FALSE
|
||||
if(hit_atom.density && isturf(hit_atom))
|
||||
if(hurt)
|
||||
Knockdown(20)
|
||||
take_bodypart_damage(10)
|
||||
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.Knockdown(20)
|
||||
Knockdown(20)
|
||||
visible_message("<span class='danger'>[src] crashes into [victim], knocking them both over!</span>",\
|
||||
"<span class='userdanger'>You violently crash into [victim]!</span>")
|
||||
playsound(src,'sound/weapons/punch1.ogg',50,1)
|
||||
|
||||
|
||||
//Throwing stuff
|
||||
/mob/living/carbon/proc/toggle_throw_mode()
|
||||
if(stat)
|
||||
return
|
||||
if(in_throw_mode)
|
||||
throw_mode_off()
|
||||
else
|
||||
throw_mode_on()
|
||||
|
||||
|
||||
/mob/living/carbon/proc/throw_mode_off()
|
||||
in_throw_mode = 0
|
||||
if(client && hud_used)
|
||||
hud_used.throw_icon.icon_state = "act_throw_off"
|
||||
|
||||
|
||||
/mob/living/carbon/proc/throw_mode_on()
|
||||
in_throw_mode = 1
|
||||
if(client && hud_used)
|
||||
hud_used.throw_icon.icon_state = "act_throw_on"
|
||||
|
||||
/mob/proc/throw_item(atom/target)
|
||||
SEND_SIGNAL(src, COMSIG_MOB_THROW, target)
|
||||
return
|
||||
|
||||
/mob/living/carbon/throw_item(atom/target)
|
||||
throw_mode_off()
|
||||
if(!target || !isturf(loc))
|
||||
return
|
||||
if(istype(target, /obj/screen))
|
||||
return
|
||||
|
||||
//CIT CHANGES - makes it impossible to throw while in stamina softcrit
|
||||
if(getStaminaLoss() >= STAMINA_SOFTCRIT)
|
||||
to_chat(src, "<span class='warning'>You're too exhausted.</span>")
|
||||
return
|
||||
//END OF CIT CHANGES
|
||||
|
||||
var/atom/movable/thrown_thing
|
||||
var/obj/item/I = src.get_active_held_item()
|
||||
|
||||
if(!I)
|
||||
if(pulling && isliving(pulling) && grab_state >= GRAB_AGGRESSIVE)
|
||||
var/mob/living/throwable_mob = pulling
|
||||
if(!throwable_mob.buckled)
|
||||
thrown_thing = throwable_mob
|
||||
stop_pulling()
|
||||
if(HAS_TRAIT(src, TRAIT_PACIFISM))
|
||||
to_chat(src, "<span class='notice'>You gently let go of [throwable_mob].</span>")
|
||||
adjustStaminaLossBuffered(25)//CIT CHANGE - 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)
|
||||
log_combat(src, throwable_mob, "thrown", addition="grab from tile in [AREACOORD(start_T)] towards tile at [AREACOORD(end_T)]")
|
||||
|
||||
else if(!CHECK_BITFIELD(I.item_flags, ABSTRACT) && !HAS_TRAIT(I, TRAIT_NODROP))
|
||||
thrown_thing = I
|
||||
dropItemToGround(I)
|
||||
|
||||
if(HAS_TRAIT(src, TRAIT_PACIFISM) && I.throwforce)
|
||||
to_chat(src, "<span class='notice'>You set [I] down gently on the ground.</span>")
|
||||
return
|
||||
|
||||
adjustStaminaLossBuffered(I.getweight()*2)//CIT CHANGE - throwing items shall be more tiring than swinging em. Doubly so.
|
||||
|
||||
if(thrown_thing)
|
||||
visible_message("<span class='danger'>[src] has thrown [thrown_thing].</span>")
|
||||
src.log_message("has thrown [thrown_thing]", 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.throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src)
|
||||
|
||||
/mob/living/carbon/restrained(ignore_grab)
|
||||
. = (handcuffed || (!ignore_grab && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE))
|
||||
|
||||
/mob/living/carbon/proc/canBeHandcuffed()
|
||||
return 0
|
||||
|
||||
|
||||
/mob/living/carbon/show_inv(mob/user)
|
||||
user.set_machine(src)
|
||||
var/dat = {"
|
||||
<HR>
|
||||
<B><FONT size=3>[name]</FONT></B>
|
||||
<HR>
|
||||
<BR><B>Head:</B> <A href='?src=[REF(src)];item=[SLOT_HEAD]'> [(head && !(head.item_flags & ABSTRACT)) ? head : "Nothing"]</A>
|
||||
<BR><B>Mask:</B> <A href='?src=[REF(src)];item=[SLOT_WEAR_MASK]'> [(wear_mask && !(wear_mask.item_flags & ABSTRACT)) ? wear_mask : "Nothing"]</A>
|
||||
<BR><B>Neck:</B> <A href='?src=[REF(src)];item=[SLOT_NECK]'> [(wear_neck && !(wear_neck.item_flags & ABSTRACT)) ? wear_neck : "Nothing"]</A>"}
|
||||
|
||||
for(var/i in 1 to held_items.len)
|
||||
var/obj/item/I = get_item_for_held_index(i)
|
||||
dat += "<BR><B>[get_held_index_name(i)]:</B></td><td><A href='?src=[REF(src)];item=[SLOT_HANDS];hand_index=[i]'>[(I && !(I.item_flags & ABSTRACT)) ? I : "Nothing"]</a>"
|
||||
|
||||
dat += "<BR><B>Back:</B> <A href='?src=[REF(src)];item=[SLOT_BACK]'>[back ? back : "Nothing"]</A>"
|
||||
|
||||
if(istype(wear_mask, /obj/item/clothing/mask) && istype(back, /obj/item/tank))
|
||||
dat += "<BR><A href='?src=[REF(src)];internal=1'>[internal ? "Disable Internals" : "Set Internals"]</A>"
|
||||
|
||||
if(handcuffed)
|
||||
dat += "<BR><A href='?src=[REF(src)];item=[SLOT_HANDCUFFED]'>Handcuffed</A>"
|
||||
if(legcuffed)
|
||||
dat += "<BR><A href='?src=[REF(src)];item=[SLOT_LEGCUFFED]'>Legcuffed</A>"
|
||||
|
||||
dat += {"
|
||||
<BR>
|
||||
<BR><A href='?src=[REF(user)];mach_close=mob[REF(src)]'>Close</A>
|
||||
"}
|
||||
user << browse(dat, "window=mob[REF(src)];size=325x500")
|
||||
onclose(user, "mob[REF(src)]")
|
||||
|
||||
/mob/living/carbon/Topic(href, href_list)
|
||||
..()
|
||||
//strip panel
|
||||
if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
|
||||
if(href_list["internal"])
|
||||
var/slot = text2num(href_list["internal"])
|
||||
var/obj/item/ITEM = get_item_by_slot(slot)
|
||||
if(ITEM && istype(ITEM, /obj/item/tank) && wear_mask && (wear_mask.clothing_flags & ALLOWINTERNALS))
|
||||
visible_message("<span class='danger'>[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].</span>", \
|
||||
"<span class='userdanger'>[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].</span>")
|
||||
if(do_mob(usr, src, POCKET_STRIP_DELAY))
|
||||
if(internal)
|
||||
internal = null
|
||||
update_internals_hud_icon(0)
|
||||
else if(ITEM && istype(ITEM, /obj/item/tank))
|
||||
if((wear_mask && (wear_mask.clothing_flags & ALLOWINTERNALS)) || getorganslot(ORGAN_SLOT_BREATHING_TUBE))
|
||||
internal = ITEM
|
||||
update_internals_hud_icon(1)
|
||||
|
||||
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 [src]'s [ITEM.name].</span>")
|
||||
|
||||
|
||||
/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
|
||||
|
||||
/mob/living/carbon/is_muzzled()
|
||||
return(istype(src.wear_mask, /obj/item/clothing/mask/muzzle))
|
||||
|
||||
/mob/living/carbon/hallucinating()
|
||||
if(hallucination)
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/resist_buckle()
|
||||
if(restrained())
|
||||
changeNext_move(CLICK_CD_BREAKOUT)
|
||||
last_special = world.time + CLICK_CD_BREAKOUT
|
||||
var/buckle_cd = 600
|
||||
if(handcuffed)
|
||||
var/obj/item/restraints/O = src.get_item_by_slot(SLOT_HANDCUFFED)
|
||||
buckle_cd = O.breakouttime
|
||||
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))
|
||||
if(!buckled)
|
||||
return
|
||||
buckled.user_unbuckle_mob(src,src)
|
||||
else
|
||||
if(src && buckled)
|
||||
to_chat(src, "<span class='warning'>You fail to unbuckle yourself!</span>")
|
||||
else
|
||||
buckled.user_unbuckle_mob(src,src)
|
||||
|
||||
/mob/living/carbon/resist_fire()
|
||||
fire_stacks -= 5
|
||||
Knockdown(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>")
|
||||
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()
|
||||
return
|
||||
|
||||
/mob/living/carbon/resist_restraints()
|
||||
var/obj/item/I = null
|
||||
var/type = 0
|
||||
if(handcuffed)
|
||||
I = handcuffed
|
||||
type = 1
|
||||
else if(legcuffed)
|
||||
I = legcuffed
|
||||
type = 2
|
||||
if(I)
|
||||
if(type == 1)
|
||||
changeNext_move(CLICK_CD_BREAKOUT)
|
||||
last_special = world.time + CLICK_CD_BREAKOUT
|
||||
if(type == 2)
|
||||
changeNext_move(CLICK_CD_RANGE)
|
||||
last_special = world.time + CLICK_CD_RANGE
|
||||
cuff_resist(I)
|
||||
|
||||
|
||||
/mob/living/carbon/proc/cuff_resist(obj/item/I, breakouttime = 600, cuff_break = 0)
|
||||
if(I.item_flags & BEING_REMOVED)
|
||||
to_chat(src, "<span class='warning'>You're already attempting to remove [I]!</span>")
|
||||
return
|
||||
I.item_flags |= BEING_REMOVED
|
||||
breakouttime = I.breakouttime
|
||||
if(!cuff_break)
|
||||
visible_message("<span class='warning'>[src] attempts to remove [I]!</span>")
|
||||
to_chat(src, "<span class='notice'>You attempt to remove [I]... (This will take around [DisplayTimeText(breakouttime)] and you need to stand still.)</span>")
|
||||
if(do_after(src, breakouttime, 0, target = src))
|
||||
clear_cuffs(I, cuff_break)
|
||||
else
|
||||
to_chat(src, "<span class='warning'>You fail to remove [I]!</span>")
|
||||
|
||||
else if(cuff_break == FAST_CUFFBREAK)
|
||||
breakouttime = 50
|
||||
visible_message("<span class='warning'>[src] is trying to break [I]!</span>")
|
||||
to_chat(src, "<span class='notice'>You attempt to break [I]... (This will take around 5 seconds and you need to stand still.)</span>")
|
||||
if(do_after(src, breakouttime, 0, target = src))
|
||||
clear_cuffs(I, cuff_break)
|
||||
else
|
||||
to_chat(src, "<span class='warning'>You fail to break [I]!</span>")
|
||||
|
||||
else if(cuff_break == INSTANT_CUFFBREAK)
|
||||
clear_cuffs(I, cuff_break)
|
||||
I.item_flags &= ~BEING_REMOVED
|
||||
|
||||
/mob/living/carbon/proc/uncuff()
|
||||
if (handcuffed)
|
||||
var/obj/item/W = handcuffed
|
||||
handcuffed = null
|
||||
if (buckled && buckled.buckle_requires_restraints)
|
||||
buckled.unbuckle_mob(src)
|
||||
update_handcuffed()
|
||||
if (client)
|
||||
client.screen -= W
|
||||
if (W)
|
||||
W.forceMove(drop_location())
|
||||
W.dropped(src)
|
||||
if (W)
|
||||
W.layer = initial(W.layer)
|
||||
W.plane = initial(W.plane)
|
||||
changeNext_move(0)
|
||||
if (legcuffed)
|
||||
var/obj/item/W = legcuffed
|
||||
legcuffed = null
|
||||
update_inv_legcuffed()
|
||||
if (client)
|
||||
client.screen -= W
|
||||
if (W)
|
||||
W.forceMove(drop_location())
|
||||
W.dropped(src)
|
||||
if (W)
|
||||
W.layer = initial(W.layer)
|
||||
W.plane = initial(W.plane)
|
||||
changeNext_move(0)
|
||||
|
||||
/mob/living/carbon/proc/clear_cuffs(obj/item/I, cuff_break)
|
||||
if(!I.loc || buckled)
|
||||
return
|
||||
visible_message("<span class='danger'>[src] manages to [cuff_break ? "break" : "remove"] [I]!</span>")
|
||||
to_chat(src, "<span class='notice'>You successfully [cuff_break ? "break" : "remove"] [I].</span>")
|
||||
|
||||
if(cuff_break)
|
||||
. = !((I == handcuffed) || (I == legcuffed))
|
||||
qdel(I)
|
||||
return
|
||||
|
||||
else
|
||||
if(I == handcuffed)
|
||||
handcuffed.forceMove(drop_location())
|
||||
handcuffed.dropped(src)
|
||||
handcuffed = null
|
||||
if(buckled && buckled.buckle_requires_restraints)
|
||||
buckled.unbuckle_mob(src)
|
||||
update_handcuffed()
|
||||
return
|
||||
if(I == legcuffed)
|
||||
legcuffed.forceMove(drop_location())
|
||||
legcuffed.dropped()
|
||||
legcuffed = null
|
||||
update_inv_legcuffed()
|
||||
return
|
||||
else
|
||||
dropItemToGround(I)
|
||||
return
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/get_standard_pixel_y_offset(lying = 0)
|
||||
if(lying)
|
||||
return -6
|
||||
else
|
||||
return initial(pixel_y)
|
||||
|
||||
/mob/living/carbon/proc/accident(obj/item/I)
|
||||
if(!I || (I.item_flags & ABSTRACT) || HAS_TRAIT(I, TRAIT_NODROP))
|
||||
return
|
||||
|
||||
//dropItemToGround(I) CIT CHANGE - makes it so the item doesn't drop if the modifier rolls above 100
|
||||
|
||||
var/modifier = 0
|
||||
|
||||
if(HAS_TRAIT(src, TRAIT_CLUMSY))
|
||||
modifier -= 40 //Clumsy people are more likely to hit themselves -Honk!
|
||||
|
||||
//CIT CHANGES START HERE
|
||||
else if(combatmode)
|
||||
modifier += 50
|
||||
|
||||
if(modifier < 100)
|
||||
dropItemToGround(I)
|
||||
//END OF CIT CHANGES
|
||||
|
||||
switch(rand(1,100)+modifier) //91-100=Nothing special happens
|
||||
if(-INFINITY to 0) //attack yourself
|
||||
I.attack(src,src)
|
||||
if(1 to 30) //throw it at yourself
|
||||
I.throw_impact(src)
|
||||
if(31 to 60) //Throw object in facing direction
|
||||
var/turf/target = get_turf(loc)
|
||||
var/range = rand(2,I.throw_range)
|
||||
for(var/i = 1; i < range; i++)
|
||||
var/turf/new_turf = get_step(target, dir)
|
||||
target = new_turf
|
||||
if(new_turf.density)
|
||||
break
|
||||
I.throw_at(target,I.throw_range,I.throw_speed,src)
|
||||
if(61 to 90) //throw it down to the floor
|
||||
var/turf/target = get_turf(loc)
|
||||
I.throw_at(target,I.throw_range,I.throw_speed,src)
|
||||
|
||||
/mob/living/carbon/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
var/obj/item/organ/alien/plasmavessel/vessel = getorgan(/obj/item/organ/alien/plasmavessel)
|
||||
if(vessel)
|
||||
stat(null, "Plasma Stored: [vessel.storedPlasma]/[vessel.max_plasma]")
|
||||
if(locate(/obj/item/assembly/health) in src)
|
||||
stat(null, "Health: [health]")
|
||||
|
||||
add_abilities_to_panel()
|
||||
|
||||
/mob/living/carbon/attack_ui(slot)
|
||||
if(!has_hand_for_held_index(active_hand_index))
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/proc/vomit(lost_nutrition = 10, blood = FALSE, stun = TRUE, distance = 1, message = TRUE, toxic = FALSE)
|
||||
if(HAS_TRAIT(src, TRAIT_NOHUNGER))
|
||||
return 1
|
||||
|
||||
if(nutrition < 100 && !blood)
|
||||
if(message)
|
||||
visible_message("<span class='warning'>[src] dry heaves!</span>", \
|
||||
"<span class='userdanger'>You try to throw up, but there's nothing in your stomach!</span>")
|
||||
if(stun)
|
||||
Knockdown(200)
|
||||
return 1
|
||||
|
||||
if(is_mouth_covered()) //make this add a blood/vomit overlay later it'll be hilarious
|
||||
if(message)
|
||||
visible_message("<span class='danger'>[src] throws up all over [p_them()]self!</span>", \
|
||||
"<span class='userdanger'>You throw up all over yourself!</span>")
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "vomit", /datum/mood_event/vomitself)
|
||||
distance = 0
|
||||
else
|
||||
if(message)
|
||||
visible_message("<span class='danger'>[src] throws up!</span>", "<span class='userdanger'>You throw up!</span>")
|
||||
if(!isflyperson(src))
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "vomit", /datum/mood_event/vomit)
|
||||
if(stun)
|
||||
Stun(80)
|
||||
|
||||
playsound(get_turf(src), 'sound/effects/splat.ogg', 50, 1)
|
||||
var/turf/T = get_turf(src)
|
||||
if(!blood)
|
||||
nutrition -= lost_nutrition
|
||||
adjustToxLoss(-3)
|
||||
for(var/i=0 to distance)
|
||||
if(blood)
|
||||
if(T)
|
||||
add_splatter_floor(T)
|
||||
if(stun)
|
||||
adjustBruteLoss(3)
|
||||
else if(src.reagents.has_reagent("blazaam"))
|
||||
if(T)
|
||||
T.add_vomit_floor(src, VOMIT_PURPLE)
|
||||
else
|
||||
if(T)
|
||||
T.add_vomit_floor(src, VOMIT_TOXIC)//toxic barf looks different
|
||||
T = get_step(T, dir)
|
||||
if (is_blocked_turf(T))
|
||||
break
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/proc/spew_organ(power = 5, amt = 1)
|
||||
for(var/i in 1 to amt)
|
||||
if(!internal_organs.len)
|
||||
break //Guess we're out of organs!
|
||||
var/obj/item/organ/guts = pick(internal_organs)
|
||||
var/turf/T = get_turf(src)
|
||||
guts.Remove(src)
|
||||
guts.forceMove(T)
|
||||
var/atom/throw_target = get_edge_target_turf(guts, dir)
|
||||
guts.throw_at(throw_target, power, 4, src)
|
||||
|
||||
|
||||
/mob/living/carbon/fully_replace_character_name(oldname,newname)
|
||||
..()
|
||||
if(dna)
|
||||
dna.real_name = real_name
|
||||
|
||||
//Updates the mob's health from bodyparts and mob damage variables
|
||||
/mob/living/carbon/updatehealth()
|
||||
if(status_flags & GODMODE)
|
||||
return
|
||||
var/total_burn = 0
|
||||
var/total_brute = 0
|
||||
var/total_stamina = 0
|
||||
for(var/X in bodyparts) //hardcoded to streamline things a bit
|
||||
var/obj/item/bodypart/BP = X
|
||||
total_brute += (BP.brute_dam * BP.body_damage_coeff)
|
||||
total_burn += (BP.burn_dam * BP.body_damage_coeff)
|
||||
total_stamina += (BP.stamina_dam * BP.stam_damage_coeff)
|
||||
health = round(maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute, DAMAGE_PRECISION)
|
||||
staminaloss = round(total_stamina, DAMAGE_PRECISION)
|
||||
update_stat()
|
||||
if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD) && stat == DEAD )
|
||||
become_husk("burn")
|
||||
med_hud_set_health()
|
||||
if(stat == SOFT_CRIT)
|
||||
add_movespeed_modifier(MOVESPEED_ID_CARBON_SOFTCRIT, TRUE, multiplicative_slowdown = SOFTCRIT_ADD_SLOWDOWN)
|
||||
else
|
||||
remove_movespeed_modifier(MOVESPEED_ID_CARBON_SOFTCRIT, TRUE)
|
||||
|
||||
/mob/living/carbon/update_stamina()
|
||||
var/stam = getStaminaLoss()
|
||||
if(stam > DAMAGE_PRECISION)
|
||||
var/total_health = (health - stam)
|
||||
if(total_health <= crit_threshold && !stat)
|
||||
if(!IsKnockdown())
|
||||
to_chat(src, "<span class='notice'>You're too exhausted to keep going...</span>")
|
||||
Knockdown(100)
|
||||
update_health_hud()
|
||||
|
||||
/mob/living/carbon/update_sight()
|
||||
if(!client)
|
||||
return
|
||||
if(stat == DEAD)
|
||||
sight = (SEE_TURFS|SEE_MOBS|SEE_OBJS)
|
||||
see_in_dark = 8
|
||||
see_invisible = SEE_INVISIBLE_OBSERVER
|
||||
return
|
||||
|
||||
sight = initial(sight)
|
||||
lighting_alpha = initial(lighting_alpha)
|
||||
var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
|
||||
if(!E)
|
||||
update_tint()
|
||||
else
|
||||
see_invisible = E.see_invisible
|
||||
see_in_dark = E.see_in_dark
|
||||
sight |= E.sight_flags
|
||||
if(!isnull(E.lighting_alpha))
|
||||
lighting_alpha = E.lighting_alpha
|
||||
|
||||
if(client.eye && client.eye != src)
|
||||
var/atom/A = client.eye
|
||||
if(A.update_remote_sight(src)) //returns 1 if we override all other sight updates.
|
||||
return
|
||||
|
||||
if(glasses)
|
||||
var/obj/item/clothing/glasses/G = glasses
|
||||
sight |= G.vision_flags
|
||||
see_in_dark = max(G.darkness_view, see_in_dark)
|
||||
if(G.invis_override)
|
||||
see_invisible = G.invis_override
|
||||
else
|
||||
see_invisible = min(G.invis_view, see_invisible)
|
||||
if(!isnull(G.lighting_alpha))
|
||||
lighting_alpha = min(lighting_alpha, G.lighting_alpha)
|
||||
if(dna)
|
||||
for(var/X in dna.mutations)
|
||||
var/datum/mutation/M = X
|
||||
if(M.name == XRAY)
|
||||
sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS)
|
||||
see_in_dark = max(see_in_dark, 8)
|
||||
|
||||
if(see_override)
|
||||
see_invisible = see_override
|
||||
. = ..()
|
||||
|
||||
|
||||
//to recalculate and update the mob's total tint from tinted equipment it's wearing.
|
||||
/mob/living/carbon/proc/update_tint()
|
||||
if(!GLOB.tinted_weldhelh)
|
||||
return
|
||||
tinttotal = get_total_tint()
|
||||
if(tinttotal >= TINT_BLIND)
|
||||
become_blind(EYES_COVERED)
|
||||
else if(tinttotal >= TINT_DARKENED)
|
||||
cure_blind(EYES_COVERED)
|
||||
overlay_fullscreen("tint", /obj/screen/fullscreen/impaired, 2)
|
||||
else
|
||||
cure_blind(EYES_COVERED)
|
||||
clear_fullscreen("tint", 0)
|
||||
|
||||
/mob/living/carbon/proc/get_total_tint()
|
||||
. = 0
|
||||
if(istype(head, /obj/item/clothing/head))
|
||||
var/obj/item/clothing/head/HT = head
|
||||
. += HT.tint
|
||||
if(wear_mask)
|
||||
. += wear_mask.tint
|
||||
|
||||
var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
|
||||
if(E)
|
||||
. += E.tint
|
||||
|
||||
else
|
||||
. += INFINITY
|
||||
|
||||
/mob/living/carbon/get_permeability_protection(list/target_zones = list(HANDS,CHEST,GROIN,LEGS,FEET,ARMS,HEAD))
|
||||
var/list/tally = list()
|
||||
for(var/obj/item/I in get_equipped_items())
|
||||
for(var/zone in target_zones)
|
||||
if(I.body_parts_covered & zone)
|
||||
tally["[zone]"] = max(1 - I.permeability_coefficient, target_zones["[zone]"])
|
||||
var/protection = 0
|
||||
for(var/key in tally)
|
||||
protection += tally[key]
|
||||
protection *= INVERSE(target_zones.len)
|
||||
return protection
|
||||
|
||||
//this handles hud updates
|
||||
/mob/living/carbon/update_damage_hud()
|
||||
|
||||
if(!client)
|
||||
return
|
||||
|
||||
if(health <= crit_threshold)
|
||||
var/severity = 0
|
||||
switch(health)
|
||||
if(-20 to -10)
|
||||
severity = 1
|
||||
if(-30 to -20)
|
||||
severity = 2
|
||||
if(-40 to -30)
|
||||
severity = 3
|
||||
if(-50 to -40)
|
||||
severity = 4
|
||||
if(-50 to -40)
|
||||
severity = 5
|
||||
if(-60 to -50)
|
||||
severity = 6
|
||||
if(-70 to -60)
|
||||
severity = 7
|
||||
if(-90 to -70)
|
||||
severity = 8
|
||||
if(-95 to -90)
|
||||
severity = 9
|
||||
if(-INFINITY to -95)
|
||||
severity = 10
|
||||
if(!InFullCritical())
|
||||
var/visionseverity = 4
|
||||
switch(health)
|
||||
if(-8 to -4)
|
||||
visionseverity = 5
|
||||
if(-12 to -8)
|
||||
visionseverity = 6
|
||||
if(-16 to -12)
|
||||
visionseverity = 7
|
||||
if(-20 to -16)
|
||||
visionseverity = 8
|
||||
if(-24 to -20)
|
||||
visionseverity = 9
|
||||
if(-INFINITY to -24)
|
||||
visionseverity = 10
|
||||
overlay_fullscreen("critvision", /obj/screen/fullscreen/crit/vision, visionseverity)
|
||||
else
|
||||
clear_fullscreen("critvision")
|
||||
overlay_fullscreen("crit", /obj/screen/fullscreen/crit, severity)
|
||||
else
|
||||
clear_fullscreen("crit")
|
||||
clear_fullscreen("critvision")
|
||||
|
||||
//Oxygen damage overlay
|
||||
var/windedup = getOxyLoss() + getStaminaLoss() * 0.2
|
||||
if(windedup)
|
||||
var/severity = 0
|
||||
switch(windedup)
|
||||
if(10 to 20)
|
||||
severity = 1
|
||||
if(20 to 25)
|
||||
severity = 2
|
||||
if(25 to 30)
|
||||
severity = 3
|
||||
if(30 to 35)
|
||||
severity = 4
|
||||
if(35 to 40)
|
||||
severity = 5
|
||||
if(40 to 45)
|
||||
severity = 6
|
||||
if(45 to INFINITY)
|
||||
severity = 7
|
||||
overlay_fullscreen("oxy", /obj/screen/fullscreen/oxy, severity)
|
||||
else
|
||||
clear_fullscreen("oxy")
|
||||
|
||||
//Fire and Brute damage overlay (BSSR)
|
||||
var/hurtdamage = getBruteLoss() + getFireLoss() + damageoverlaytemp
|
||||
if(hurtdamage)
|
||||
var/severity = 0
|
||||
switch(hurtdamage)
|
||||
if(5 to 15)
|
||||
severity = 1
|
||||
if(15 to 30)
|
||||
severity = 2
|
||||
if(30 to 45)
|
||||
severity = 3
|
||||
if(45 to 70)
|
||||
severity = 4
|
||||
if(70 to 85)
|
||||
severity = 5
|
||||
if(85 to INFINITY)
|
||||
severity = 6
|
||||
overlay_fullscreen("brute", /obj/screen/fullscreen/brute, severity)
|
||||
else
|
||||
clear_fullscreen("brute")
|
||||
|
||||
/mob/living/carbon/update_health_hud(shown_health_amount)
|
||||
if(!client || !hud_used)
|
||||
return
|
||||
if(hud_used.healths)
|
||||
if(stat != DEAD)
|
||||
. = 1
|
||||
if(!shown_health_amount)
|
||||
shown_health_amount = health
|
||||
if(shown_health_amount >= maxHealth)
|
||||
hud_used.healths.icon_state = "health0"
|
||||
else if(shown_health_amount > maxHealth*0.8)
|
||||
hud_used.healths.icon_state = "health1"
|
||||
else if(shown_health_amount > maxHealth*0.6)
|
||||
hud_used.healths.icon_state = "health2"
|
||||
else if(shown_health_amount > maxHealth*0.4)
|
||||
hud_used.healths.icon_state = "health3"
|
||||
else if(shown_health_amount > maxHealth*0.2)
|
||||
hud_used.healths.icon_state = "health4"
|
||||
else if(shown_health_amount > 0)
|
||||
hud_used.healths.icon_state = "health5"
|
||||
else
|
||||
hud_used.healths.icon_state = "health6"
|
||||
else
|
||||
hud_used.healths.icon_state = "health7"
|
||||
|
||||
/mob/living/carbon/proc/update_internals_hud_icon(internal_state = 0)
|
||||
if(hud_used && hud_used.internals)
|
||||
hud_used.internals.icon_state = "internal[internal_state]"
|
||||
|
||||
/mob/living/carbon/update_stat()
|
||||
if(status_flags & GODMODE)
|
||||
return
|
||||
if(stat != DEAD)
|
||||
if(health <= HEALTH_THRESHOLD_DEAD && !HAS_TRAIT(src, TRAIT_NODEATH))
|
||||
death()
|
||||
return
|
||||
if(IsUnconscious() || IsSleeping() || getOxyLoss() > 50 || (HAS_TRAIT(src, TRAIT_DEATHCOMA)) || (health <= HEALTH_THRESHOLD_FULLCRIT && !HAS_TRAIT(src, TRAIT_NOHARDCRIT)))
|
||||
stat = UNCONSCIOUS
|
||||
blind_eyes(1)
|
||||
else
|
||||
if(health <= crit_threshold && !HAS_TRAIT(src, TRAIT_NOSOFTCRIT))
|
||||
stat = SOFT_CRIT
|
||||
else
|
||||
stat = CONSCIOUS
|
||||
adjust_blindness(-1)
|
||||
update_canmove()
|
||||
update_damage_hud()
|
||||
update_health_hud()
|
||||
med_hud_set_status()
|
||||
|
||||
//called when we get cuffed/uncuffed
|
||||
/mob/living/carbon/proc/update_handcuffed()
|
||||
if(handcuffed)
|
||||
drop_all_held_items()
|
||||
stop_pulling()
|
||||
throw_alert("handcuffed", /obj/screen/alert/restrained/handcuffed, new_master = src.handcuffed)
|
||||
if(handcuffed.demoralize_criminals)
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "handcuffed", /datum/mood_event/handcuffed)
|
||||
else
|
||||
clear_alert("handcuffed")
|
||||
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "handcuffed")
|
||||
update_action_buttons_icon() //some of our action buttons might be unusable when we're handcuffed.
|
||||
update_inv_handcuffed()
|
||||
update_hud_handcuffed()
|
||||
|
||||
/mob/living/carbon/fully_heal(admin_revive = FALSE)
|
||||
if(reagents)
|
||||
reagents.clear_reagents()
|
||||
var/obj/item/organ/brain/B = getorgan(/obj/item/organ/brain)
|
||||
if(B)
|
||||
B.brain_death = FALSE
|
||||
for(var/thing in diseases)
|
||||
var/datum/disease/D = thing
|
||||
if(D.severity != DISEASE_SEVERITY_POSITIVE)
|
||||
D.cure(FALSE)
|
||||
if(admin_revive)
|
||||
regenerate_limbs()
|
||||
regenerate_organs()
|
||||
handcuffed = initial(handcuffed)
|
||||
for(var/obj/item/restraints/R in contents) //actually remove cuffs from inventory
|
||||
qdel(R)
|
||||
update_handcuffed()
|
||||
if(reagents)
|
||||
reagents.addiction_list = list()
|
||||
cure_all_traumas(TRAUMA_RESILIENCE_MAGIC)
|
||||
..()
|
||||
// heal ears after healing traits, since ears check TRAIT_DEAF trait
|
||||
// when healing.
|
||||
restoreEars()
|
||||
|
||||
/mob/living/carbon/can_be_revived()
|
||||
. = ..()
|
||||
if(!getorgan(/obj/item/organ/brain) && (!mind || !mind.has_antag_datum(/datum/antagonist/changeling)))
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/harvest(mob/living/user)
|
||||
if(QDELETED(src))
|
||||
return
|
||||
var/organs_amt = 0
|
||||
for(var/X in internal_organs)
|
||||
var/obj/item/organ/O = X
|
||||
if(prob(50))
|
||||
organs_amt++
|
||||
O.Remove(src)
|
||||
O.forceMove(drop_location())
|
||||
if(organs_amt)
|
||||
to_chat(user, "<span class='notice'>You retrieve some of [src]\'s internal organs!</span>")
|
||||
|
||||
/mob/living/carbon/ExtinguishMob()
|
||||
for(var/X in get_equipped_items())
|
||||
var/obj/item/I = X
|
||||
I.acid_level = 0 //washes off the acid on our clothes
|
||||
I.extinguish() //extinguishes our clothes
|
||||
..()
|
||||
|
||||
/mob/living/carbon/fakefire(var/fire_icon = "Generic_mob_burning")
|
||||
var/mutable_appearance/new_fire_overlay = mutable_appearance('icons/mob/OnFire.dmi', fire_icon, -FIRE_LAYER)
|
||||
new_fire_overlay.appearance_flags = RESET_COLOR
|
||||
overlays_standing[FIRE_LAYER] = new_fire_overlay
|
||||
apply_overlay(FIRE_LAYER)
|
||||
|
||||
/mob/living/carbon/fakefireextinguish()
|
||||
remove_overlay(FIRE_LAYER)
|
||||
|
||||
|
||||
/mob/living/carbon/proc/devour_mob(mob/living/carbon/C, devour_time = 130)
|
||||
C.visible_message("<span class='danger'>[src] is attempting to devour [C]!</span>", \
|
||||
"<span class='userdanger'>[src] is attempting to devour you!</span>")
|
||||
if(!do_mob(src, C, devour_time))
|
||||
return
|
||||
if(pulling && pulling == C && grab_state >= GRAB_AGGRESSIVE && a_intent == INTENT_GRAB)
|
||||
C.visible_message("<span class='danger'>[src] devours [C]!</span>", \
|
||||
"<span class='userdanger'>[src] devours you!</span>")
|
||||
C.forceMove(src)
|
||||
stomach_contents.Add(C)
|
||||
log_combat(src, C, "devoured")
|
||||
|
||||
/mob/living/carbon/proc/create_bodyparts()
|
||||
var/l_arm_index_next = -1
|
||||
var/r_arm_index_next = 0
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/O = new X()
|
||||
O.owner = src
|
||||
bodyparts.Remove(X)
|
||||
bodyparts.Add(O)
|
||||
if(O.body_part == ARM_LEFT)
|
||||
l_arm_index_next += 2
|
||||
O.held_index = l_arm_index_next //1, 3, 5, 7...
|
||||
hand_bodyparts += O
|
||||
else if(O.body_part == ARM_RIGHT)
|
||||
r_arm_index_next += 2
|
||||
O.held_index = r_arm_index_next //2, 4, 6, 8...
|
||||
hand_bodyparts += O
|
||||
|
||||
/mob/living/carbon/do_after_coefficent()
|
||||
. = ..()
|
||||
var/datum/component/mood/mood = src.GetComponent(/datum/component/mood) //Currently, only carbons or higher use mood, move this once that changes.
|
||||
if(mood)
|
||||
switch(mood.sanity) //Alters do_after delay based on how sane you are
|
||||
if(SANITY_INSANE to SANITY_DISTURBED)
|
||||
. *= 1.25
|
||||
if(SANITY_NEUTRAL to SANITY_GREAT)
|
||||
. *= 0.90
|
||||
|
||||
|
||||
/mob/living/carbon/proc/create_internal_organs()
|
||||
for(var/X in internal_organs)
|
||||
var/obj/item/organ/I = X
|
||||
I.Insert(src)
|
||||
|
||||
/mob/living/carbon/proc/update_disabled_bodyparts()
|
||||
for(var/B in bodyparts)
|
||||
var/obj/item/bodypart/BP = B
|
||||
BP.update_disabled()
|
||||
|
||||
/mob/living/carbon/vv_get_dropdown()
|
||||
. = ..()
|
||||
. += "---"
|
||||
.["Make AI"] = "?_src_=vars;[HrefToken()];makeai=[REF(src)]"
|
||||
.["Modify bodypart"] = "?_src_=vars;[HrefToken()];editbodypart=[REF(src)]"
|
||||
.["Modify organs"] = "?_src_=vars;[HrefToken()];editorgans=[REF(src)]"
|
||||
.["Hallucinate"] = "?_src_=vars;[HrefToken()];hallucinate=[REF(src)]"
|
||||
.["Give martial arts"] = "?_src_=vars;[HrefToken()];givemartialart=[REF(src)]"
|
||||
.["Give brain trauma"] = "?_src_=vars;[HrefToken()];givetrauma=[REF(src)]"
|
||||
.["Cure brain traumas"] = "?_src_=vars;[HrefToken()];curetraumas=[REF(src)]"
|
||||
|
||||
/mob/living/carbon/can_resist()
|
||||
return bodyparts.len > 2 && ..()
|
||||
|
||||
/mob/living/carbon/proc/hypnosis_vulnerable()//unused atm, but added in case
|
||||
if(HAS_TRAIT(src, TRAIT_MINDSHIELD))
|
||||
return FALSE
|
||||
if(hallucinating())
|
||||
return TRUE
|
||||
if(IsSleeping())
|
||||
return TRUE
|
||||
if(HAS_TRAIT(src, TRAIT_DUMB))
|
||||
return TRUE
|
||||
var/datum/component/mood/mood = src.GetComponent(/datum/component/mood)
|
||||
if(mood)
|
||||
if(mood.sanity < SANITY_UNSTABLE)
|
||||
return TRUE
|
||||
@@ -1,442 +0,0 @@
|
||||
|
||||
/mob/living/carbon/get_eye_protection()
|
||||
var/number = ..()
|
||||
|
||||
if(istype(src.head, /obj/item/clothing/head)) //are they wearing something on their head
|
||||
var/obj/item/clothing/head/HFP = src.head //if yes gets the flash protection value from that item
|
||||
number += HFP.flash_protect
|
||||
|
||||
if(istype(src.glasses, /obj/item/clothing/glasses)) //glasses
|
||||
var/obj/item/clothing/glasses/GFP = src.glasses
|
||||
number += GFP.flash_protect
|
||||
|
||||
if(istype(src.wear_mask, /obj/item/clothing/mask)) //mask
|
||||
var/obj/item/clothing/mask/MFP = src.wear_mask
|
||||
number += MFP.flash_protect
|
||||
|
||||
var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
|
||||
if(!E)
|
||||
number = INFINITY //Can't get flashed without eyes
|
||||
else
|
||||
number += E.flash_protect
|
||||
|
||||
return number
|
||||
|
||||
/mob/living/carbon/get_ear_protection()
|
||||
var/number = ..()
|
||||
var/obj/item/organ/ears/E = getorganslot(ORGAN_SLOT_EARS)
|
||||
if(!E)
|
||||
number = INFINITY
|
||||
else
|
||||
number += E.bang_protect
|
||||
return number
|
||||
|
||||
/mob/living/carbon/is_mouth_covered(head_only = 0, mask_only = 0)
|
||||
if( (!mask_only && head && (head.flags_cover & HEADCOVERSMOUTH)) || (!head_only && wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH)) )
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/is_eyes_covered(check_glasses = 1, check_head = 1, check_mask = 1)
|
||||
if(check_glasses && glasses && (glasses.flags_cover & GLASSESCOVERSEYES))
|
||||
return TRUE
|
||||
if(check_head && head && (head.flags_cover & HEADCOVERSEYES))
|
||||
return TRUE
|
||||
if(check_mask && wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH))
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
|
||||
var/obj/item/bodypart/affecting = get_bodypart(def_zone)
|
||||
if(affecting && affecting.dismemberable && affecting.get_damage() >= (affecting.max_damage - P.dismemberment))
|
||||
affecting.dismember(P.damtype)
|
||||
|
||||
/mob/living/carbon/proc/can_catch_item(skip_throw_mode_check)
|
||||
. = FALSE
|
||||
if(!skip_throw_mode_check && !in_throw_mode)
|
||||
return
|
||||
if(get_active_held_item())
|
||||
return
|
||||
if(restrained())
|
||||
return
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE)
|
||||
if(!skipcatch) //ugly, but easy
|
||||
if(can_catch_item())
|
||||
if(istype(AM, /obj/item))
|
||||
var/obj/item/I = AM
|
||||
if(isturf(I.loc))
|
||||
I.attack_hand(src)
|
||||
if(get_active_held_item() == I) //if our attack_hand() picks up the item...
|
||||
visible_message("<span class='warning'>[src] catches [I]!</span>") //catch that sucker!
|
||||
throw_mode_off()
|
||||
return 1
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/carbon/attacked_by(obj/item/I, mob/living/user)
|
||||
var/obj/item/bodypart/affecting
|
||||
if(user == src)
|
||||
affecting = get_bodypart(check_zone(user.zone_selected)) //we're self-mutilating! yay!
|
||||
else
|
||||
affecting = get_bodypart(ran_zone(user.zone_selected))
|
||||
if(!affecting) //missing limb? we select the first bodypart (you can never have zero, because of chest)
|
||||
affecting = bodyparts[1]
|
||||
SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting)
|
||||
send_item_attack_message(I, user, affecting.name)
|
||||
if(I.force)
|
||||
//CIT CHANGES START HERE - combatmode and resting checks
|
||||
var/totitemdamage = I.force
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/tempcarb = user
|
||||
if(!tempcarb.combatmode)
|
||||
totitemdamage *= 0.5
|
||||
if(user.resting)
|
||||
totitemdamage *= 0.5
|
||||
if(!combatmode)
|
||||
totitemdamage *= 1.5
|
||||
//CIT CHANGES END HERE
|
||||
apply_damage(totitemdamage, I.damtype, affecting) //CIT CHANGE - replaces I.force with totitemdamage
|
||||
if(I.damtype == BRUTE && affecting.status == BODYPART_ORGANIC)
|
||||
var/basebloodychance = affecting.brute_dam + totitemdamage
|
||||
if(prob(basebloodychance))
|
||||
I.add_mob_blood(src)
|
||||
bleed(totitemdamage)
|
||||
if(totitemdamage >= 10 && get_dist(user, src) <= 1) //people with TK won't get smeared with blood
|
||||
user.add_mob_blood(src)
|
||||
|
||||
if(affecting.body_zone == BODY_ZONE_HEAD)
|
||||
if(wear_mask && prob(basebloodychance))
|
||||
wear_mask.add_mob_blood(src)
|
||||
update_inv_wear_mask()
|
||||
if(wear_neck && prob(basebloodychance))
|
||||
wear_neck.add_mob_blood(src)
|
||||
update_inv_neck()
|
||||
if(head && prob(basebloodychance))
|
||||
head.add_mob_blood(src)
|
||||
update_inv_head()
|
||||
|
||||
//dismemberment
|
||||
var/probability = I.get_dismemberment_chance(affecting)
|
||||
if(prob(probability))
|
||||
if(affecting.dismember(I.damtype))
|
||||
I.add_mob_blood(src)
|
||||
playsound(get_turf(src), I.get_dismember_sound(), 80, 1)
|
||||
return TRUE //successful attack
|
||||
|
||||
/mob/living/carbon/attack_drone(mob/living/simple_animal/drone/user)
|
||||
return //so we don't call the carbon's attack_hand().
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/mob/living/carbon/attack_hand(mob/living/carbon/human/user)
|
||||
|
||||
for(var/thing in diseases)
|
||||
var/datum/disease/D = thing
|
||||
if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
|
||||
user.ContactContractDisease(D)
|
||||
|
||||
for(var/thing in user.diseases)
|
||||
var/datum/disease/D = thing
|
||||
if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
|
||||
ContactContractDisease(D)
|
||||
|
||||
if(lying && surgeries.len)
|
||||
if(user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM)
|
||||
for(var/datum/surgery/S in surgeries)
|
||||
if(S.next_step(user, user.a_intent))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
/mob/living/carbon/attack_paw(mob/living/carbon/monkey/M)
|
||||
|
||||
if(can_inject(M, TRUE))
|
||||
for(var/thing in diseases)
|
||||
var/datum/disease/D = thing
|
||||
if((D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) && prob(85))
|
||||
M.ContactContractDisease(D)
|
||||
|
||||
for(var/thing in M.diseases)
|
||||
var/datum/disease/D = thing
|
||||
if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
|
||||
ContactContractDisease(D)
|
||||
|
||||
if(M.a_intent == INTENT_HELP)
|
||||
help_shake_act(M)
|
||||
return 0
|
||||
|
||||
if(..()) //successful monkey bite.
|
||||
for(var/thing in M.diseases)
|
||||
var/datum/disease/D = thing
|
||||
ForceContractDisease(D)
|
||||
return 1
|
||||
|
||||
|
||||
/mob/living/carbon/attack_slime(mob/living/simple_animal/slime/M)
|
||||
if(..()) //successful slime attack
|
||||
if(M.powerlevel > 0)
|
||||
var/stunprob = M.powerlevel * 7 + 10 // 17 at level 1, 80 at level 10
|
||||
if(prob(stunprob))
|
||||
M.powerlevel -= 3
|
||||
if(M.powerlevel < 0)
|
||||
M.powerlevel = 0
|
||||
|
||||
visible_message("<span class='danger'>The [M.name] has shocked [src]!</span>", \
|
||||
"<span class='userdanger'>The [M.name] has shocked [src]!</span>")
|
||||
|
||||
do_sparks(5, TRUE, src)
|
||||
var/power = M.powerlevel + rand(0,3)
|
||||
Knockdown(power*20)
|
||||
if(stuttering < power)
|
||||
stuttering = power
|
||||
if (prob(stunprob) && M.powerlevel >= 8)
|
||||
adjustFireLoss(M.powerlevel * rand(6,10))
|
||||
updatehealth()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/proc/dismembering_strike(mob/living/attacker, dam_zone)
|
||||
if(!attacker.limb_destroyer)
|
||||
return dam_zone
|
||||
var/obj/item/bodypart/affecting
|
||||
if(dam_zone && attacker.client)
|
||||
affecting = get_bodypart(ran_zone(dam_zone))
|
||||
else
|
||||
var/list/things_to_ruin = shuffle(bodyparts.Copy())
|
||||
for(var/B in things_to_ruin)
|
||||
var/obj/item/bodypart/bodypart = B
|
||||
if(bodypart.body_zone == BODY_ZONE_HEAD || bodypart.body_zone == BODY_ZONE_CHEST)
|
||||
continue
|
||||
if(!affecting || ((affecting.get_damage() / affecting.max_damage) < (bodypart.get_damage() / bodypart.max_damage)))
|
||||
affecting = bodypart
|
||||
if(affecting)
|
||||
dam_zone = affecting.body_zone
|
||||
if(affecting.get_damage() >= affecting.max_damage)
|
||||
affecting.dismember()
|
||||
return null
|
||||
return affecting.body_zone
|
||||
return dam_zone
|
||||
|
||||
|
||||
/mob/living/carbon/blob_act(obj/structure/blob/B)
|
||||
if (stat == DEAD)
|
||||
return
|
||||
else
|
||||
show_message("<span class='userdanger'>The blob attacks!</span>")
|
||||
adjustBruteLoss(10)
|
||||
|
||||
/mob/living/carbon/emp_act(severity)
|
||||
. = ..()
|
||||
if(. & EMP_PROTECT_CONTENTS)
|
||||
return
|
||||
for(var/X in internal_organs)
|
||||
var/obj/item/organ/O = X
|
||||
O.emp_act(severity)
|
||||
|
||||
/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
|
||||
if(tesla_shock && (flags_1 & TESLA_IGNORE_1))
|
||||
return FALSE
|
||||
if(HAS_TRAIT(src, TRAIT_SHOCKIMMUNE))
|
||||
return FALSE
|
||||
shock_damage *= siemens_coeff
|
||||
if(dna && dna.species)
|
||||
shock_damage *= dna.species.siemens_coeff
|
||||
if(shock_damage<1 && !override)
|
||||
return 0
|
||||
if(reagents.has_reagent("teslium"))
|
||||
shock_damage *= 1.5 //If the mob has teslium in their body, shocks are 50% more damaging!
|
||||
if(illusion)
|
||||
adjustStaminaLoss(shock_damage)
|
||||
else
|
||||
take_overall_damage(0,shock_damage)
|
||||
visible_message(
|
||||
"<span class='danger'>[src] was shocked by \the [source]!</span>", \
|
||||
"<span class='userdanger'>You feel a powerful shock coursing through your body!</span>", \
|
||||
"<span class='italics'>You hear a heavy electrical crack.</span>" \
|
||||
)
|
||||
jitteriness += 1000 //High numbers for violent convulsions
|
||||
do_jitter_animation(jitteriness)
|
||||
stuttering += 2
|
||||
if((!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) && stun)
|
||||
Stun(40)
|
||||
spawn(20)
|
||||
jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less
|
||||
if((!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) && stun)
|
||||
Knockdown(60)
|
||||
if(override)
|
||||
return override
|
||||
else
|
||||
return shock_damage
|
||||
|
||||
/mob/living/carbon/proc/help_shake_act(mob/living/carbon/M)
|
||||
if(on_fire)
|
||||
to_chat(M, "<span class='warning'>You can't put [p_them()] out with just your bare hands!</span>")
|
||||
return
|
||||
|
||||
if(health >= 0 && !(HAS_TRAIT(src, TRAIT_FAKEDEATH)))
|
||||
|
||||
if(lying)
|
||||
if(buckled)
|
||||
to_chat(M, "<span class='warning'>You need to unbuckle [src] first to do that!")
|
||||
return
|
||||
M.visible_message("<span class='notice'>[M] shakes [src] trying to get [p_them()] up!</span>", \
|
||||
"<span class='notice'>You shake [src] trying to get [p_them()] up!</span>")
|
||||
|
||||
else if(check_zone(M.zone_selected) == "head")
|
||||
var/mob/living/carbon/human/H = src
|
||||
var/datum/species/pref_species = H.dna.species
|
||||
|
||||
M.visible_message("<span class='notice'>[M] gives [H] a pat on the head to make [p_them()] feel better!</span>", \
|
||||
"<span class='notice'>You give [H] a pat on the head to make [p_them()] feel better!</span>")
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "headpat", /datum/mood_event/headpat)
|
||||
if(HAS_TRAIT(M, TRAIT_FRIENDLY))
|
||||
var/datum/component/mood/mood = M.GetComponent(/datum/component/mood)
|
||||
if (mood.sanity >= SANITY_GREAT)
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/besthug, M)
|
||||
else if (mood.sanity >= SANITY_DISTURBED)
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/betterhug, M)
|
||||
if(H.dna.species.can_wag_tail(H))
|
||||
if("tail_human" in pref_species.default_features)
|
||||
if(H.dna.features["tail_human"] == "None")
|
||||
return
|
||||
else
|
||||
if(!H.dna.species.is_wagging_tail())
|
||||
H.emote("wag")
|
||||
|
||||
if("tail_lizard" in pref_species.default_features)
|
||||
if(H.dna.features["tail_lizard"] == "None")
|
||||
return
|
||||
else
|
||||
if(!H.dna.species.is_wagging_tail())
|
||||
H.emote("wag")
|
||||
|
||||
if("mam_tail" in pref_species.default_features)
|
||||
if(H.dna.features["mam_tail"] == "None")
|
||||
return
|
||||
else
|
||||
if(!H.dna.species.is_wagging_tail())
|
||||
H.emote("wag")
|
||||
|
||||
else
|
||||
return
|
||||
|
||||
else
|
||||
M.visible_message("<span class='notice'>[M] hugs [src] to make [p_them()] feel better!</span>", \
|
||||
"<span class='notice'>You hug [src] to make [p_them()] feel better!</span>")
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "hug", /datum/mood_event/hug)
|
||||
if(HAS_TRAIT(M, TRAIT_FRIENDLY))
|
||||
var/datum/component/mood/mood = M.GetComponent(/datum/component/mood)
|
||||
if (mood.sanity >= SANITY_GREAT)
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/besthug, M)
|
||||
else if (mood.sanity >= SANITY_DISTURBED)
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/betterhug, M)
|
||||
|
||||
AdjustStun(-60)
|
||||
AdjustKnockdown(-60)
|
||||
AdjustUnconscious(-60)
|
||||
AdjustSleeping(-100)
|
||||
if(recoveringstam)
|
||||
adjustStaminaLoss(-15)
|
||||
else if(resting)
|
||||
resting = 0
|
||||
update_canmove()
|
||||
|
||||
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
|
||||
|
||||
/mob/living/carbon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0)
|
||||
. = ..()
|
||||
|
||||
var/damage = intensity - get_eye_protection()
|
||||
if(.) // we've been flashed
|
||||
var/obj/item/organ/eyes/eyes = getorganslot(ORGAN_SLOT_EYES)
|
||||
if (!eyes)
|
||||
return
|
||||
if(visual)
|
||||
return
|
||||
|
||||
if (damage == 1)
|
||||
to_chat(src, "<span class='warning'>Your eyes sting a little.</span>")
|
||||
if(prob(40))
|
||||
adjust_eye_damage(1)
|
||||
|
||||
else if (damage == 2)
|
||||
to_chat(src, "<span class='warning'>Your eyes burn.</span>")
|
||||
adjust_eye_damage(rand(2, 4))
|
||||
|
||||
else if( damage >= 3)
|
||||
to_chat(src, "<span class='warning'>Your eyes itch and burn severely!</span>")
|
||||
adjust_eye_damage(rand(12, 16))
|
||||
|
||||
if(eyes.eye_damage > 10)
|
||||
blind_eyes(damage)
|
||||
blur_eyes(damage * rand(3, 6))
|
||||
|
||||
if(eyes.eye_damage > 20)
|
||||
if(prob(eyes.eye_damage - 20))
|
||||
if(!HAS_TRAIT(src, TRAIT_NEARSIGHT))
|
||||
to_chat(src, "<span class='warning'>Your eyes start to burn badly!</span>")
|
||||
become_nearsighted(EYE_DAMAGE)
|
||||
|
||||
else if(prob(eyes.eye_damage - 25))
|
||||
if(!HAS_TRAIT(src, TRAIT_BLIND))
|
||||
to_chat(src, "<span class='warning'>You can't see anything!</span>")
|
||||
become_blind(EYE_DAMAGE)
|
||||
|
||||
else
|
||||
to_chat(src, "<span class='warning'>Your eyes are really starting to hurt. This can't be good for you!</span>")
|
||||
if(has_bane(BANE_LIGHT))
|
||||
mind.disrupt_spells(-500)
|
||||
return 1
|
||||
else if(damage == 0) // just enough protection
|
||||
if(prob(20))
|
||||
to_chat(src, "<span class='notice'>Something bright flashes in the corner of your vision!</span>")
|
||||
if(has_bane(BANE_LIGHT))
|
||||
mind.disrupt_spells(0)
|
||||
|
||||
|
||||
/mob/living/carbon/soundbang_act(intensity = 1, stun_pwr = 20, damage_pwr = 5, deafen_pwr = 15)
|
||||
var/list/reflist = list(intensity) // Need to wrap this in a list so we can pass a reference
|
||||
SEND_SIGNAL(src, COMSIG_CARBON_SOUNDBANG, reflist)
|
||||
intensity = reflist[1]
|
||||
var/ear_safety = get_ear_protection()
|
||||
var/obj/item/organ/ears/ears = getorganslot(ORGAN_SLOT_EARS)
|
||||
var/effect_amount = intensity - ear_safety
|
||||
if(effect_amount > 0)
|
||||
if(stun_pwr)
|
||||
Knockdown(stun_pwr*effect_amount)
|
||||
|
||||
if(istype(ears) && (deafen_pwr || damage_pwr))
|
||||
var/ear_damage = damage_pwr * effect_amount
|
||||
var/deaf = deafen_pwr * effect_amount
|
||||
adjustEarDamage(ear_damage,deaf)
|
||||
|
||||
if(ears.damage >= 15)
|
||||
to_chat(src, "<span class='warning'>Your ears start to ring badly!</span>")
|
||||
if(prob(ears.damage - 5))
|
||||
to_chat(src, "<span class='userdanger'>You can't hear anything!</span>")
|
||||
ears.damage = min(ears.damage, ears.maxHealth)
|
||||
// you need earmuffs, inacusiate, or replacement
|
||||
else if(ears.damage >= 5)
|
||||
to_chat(src, "<span class='warning'>Your ears start to ring!</span>")
|
||||
SEND_SOUND(src, sound('sound/weapons/flash_ring.ogg',0,1,0,250))
|
||||
return effect_amount //how soundbanged we are
|
||||
|
||||
|
||||
/mob/living/carbon/damage_clothes(damage_amount, damage_type = BRUTE, damage_flag = 0, def_zone)
|
||||
if(damage_type != BRUTE && damage_type != BURN)
|
||||
return
|
||||
damage_amount *= 0.5 //0.5 multiplier for balance reason, we don't want clothes to be too easily destroyed
|
||||
if(!def_zone || def_zone == BODY_ZONE_HEAD)
|
||||
var/obj/item/clothing/hit_clothes
|
||||
if(wear_mask)
|
||||
hit_clothes = wear_mask
|
||||
if(wear_neck)
|
||||
hit_clothes = wear_neck
|
||||
if(head)
|
||||
hit_clothes = head
|
||||
if(hit_clothes)
|
||||
hit_clothes.take_damage(damage_amount, damage_type, damage_flag, 0)
|
||||
|
||||
/mob/living/carbon/can_hear()
|
||||
. = FALSE
|
||||
var/obj/item/organ/ears/ears = getorganslot(ORGAN_SLOT_EARS)
|
||||
if(istype(ears) && !ears.deaf)
|
||||
. = TRUE
|
||||
@@ -1,66 +0,0 @@
|
||||
/mob/living/carbon
|
||||
gender = MALE
|
||||
pressure_resistance = 15
|
||||
possible_a_intents = list(INTENT_HELP, INTENT_HARM)
|
||||
hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD,GLAND_HUD,NANITE_HUD,DIAG_NANITE_FULL_HUD,RAD_HUD)
|
||||
has_limbs = 1
|
||||
held_items = list(null, null)
|
||||
var/list/stomach_contents = list()
|
||||
var/list/internal_organs = list() //List of /obj/item/organ in the mob. They don't go in the contents for some reason I don't want to know.
|
||||
var/list/internal_organs_slot= list() //Same as above, but stores "slot ID" - "organ" pairs for easy access.
|
||||
var/silent = FALSE //Can't talk. Value goes down every life proc. //NOTE TO FUTURE CODERS: DO NOT INITIALIZE NUMERICAL VARS AS NULL OR I WILL MURDER YOU.
|
||||
var/dreaming = 0 //How many dream images we have left to send
|
||||
|
||||
var/obj/item/restraints/handcuffed //Whether or not the mob is handcuffed
|
||||
var/obj/item/restraints/legcuffed //Same as handcuffs but for legs. Bear traps use this.
|
||||
|
||||
var/disgust = 0
|
||||
|
||||
//inventory slots
|
||||
var/obj/item/back = null
|
||||
var/obj/item/clothing/mask/wear_mask = null
|
||||
var/obj/item/clothing/neck/wear_neck = null
|
||||
var/obj/item/tank/internal = null
|
||||
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/glasses/glasses = null //only used by humans.
|
||||
var/obj/item/ears = null //only used by humans.
|
||||
|
||||
var/datum/dna/dna = null//Carbon
|
||||
var/datum/mind/last_mind = null //last mind to control this mob, for blood-based cloning
|
||||
|
||||
var/failed_last_breath = 0 //This is used to determine if the mob failed a breath. If they did fail a brath, they will attempt to breathe each tick, otherwise just once per 4 ticks.
|
||||
|
||||
var/co2overloadtime = null
|
||||
var/o2overloadtime = null //for Ash walker's weaker lungs, and future atmosia hazards
|
||||
var/temperature_resistance = T0C+75
|
||||
var/obj/item/reagent_containers/food/snacks/meat/slab/type_of_meat = /obj/item/reagent_containers/food/snacks/meat/slab
|
||||
|
||||
var/gib_type = /obj/effect/decal/cleanable/blood/gibs
|
||||
|
||||
var/rotate_on_lying = 1
|
||||
|
||||
var/tinttotal = 0 // Total level of visualy impairing items
|
||||
|
||||
var/list/bodyparts = list(/obj/item/bodypart/chest, /obj/item/bodypart/head, /obj/item/bodypart/l_arm,
|
||||
/obj/item/bodypart/r_arm, /obj/item/bodypart/r_leg, /obj/item/bodypart/l_leg)
|
||||
//Gets filled up in create_bodyparts()
|
||||
|
||||
var/list/hand_bodyparts = list() //a collection of arms (or actually whatever the fug /bodyparts you monsters use to wreck my systems)
|
||||
var/list/leg_bodyparts = list()
|
||||
|
||||
var/icon_render_key = ""
|
||||
var/static/list/limb_icon_cache = list()
|
||||
|
||||
//halucination vars
|
||||
var/image/halimage
|
||||
var/image/halbody
|
||||
var/obj/halitem
|
||||
var/hal_screwyhud = SCREWYHUD_NONE
|
||||
var/next_hallucination = 0
|
||||
var/cpr_time = 1 //CPR cooldown.
|
||||
var/damageoverlaytemp = 0
|
||||
|
||||
var/drunkenness = 0 //Overall drunkenness - check handle_alcohol() in life.dm for effects
|
||||
@@ -1,45 +0,0 @@
|
||||
/mob/living/carbon/movement_delay()
|
||||
. = ..()
|
||||
. += grab_state * 3 //can't go fast while grabbing something.
|
||||
|
||||
if(!get_leg_ignore()) //ignore the fact we lack legs
|
||||
var/leg_amount = get_num_legs()
|
||||
. += 6 - 3*leg_amount //the fewer the legs, the slower the mob
|
||||
if(!leg_amount)
|
||||
. += 6 - 3*get_num_arms() //crawling is harder with fewer arms
|
||||
if(legcuffed)
|
||||
. += legcuffed.slowdown
|
||||
if(stat == SOFT_CRIT)
|
||||
. += SOFTCRIT_ADD_SLOWDOWN
|
||||
|
||||
/mob/living/carbon/slip(knockdown_amount, obj/O, lube)
|
||||
if(movement_type & FLYING)
|
||||
return 0
|
||||
if(!(lube&SLIDE_ICE))
|
||||
log_combat(src, (O ? O : get_turf(src)), "slipped on the", null, ((lube & SLIDE) ? "(LUBE)" : null))
|
||||
return loc.handle_slip(src, knockdown_amount, O, lube)
|
||||
|
||||
/mob/living/carbon/Process_Spacemove(movement_dir = 0)
|
||||
if(..())
|
||||
return 1
|
||||
if(!isturf(loc))
|
||||
return 0
|
||||
|
||||
// Do we have a jetpack implant (and is it on)?
|
||||
var/obj/item/organ/cyberimp/chest/thrusters/T = getorganslot(ORGAN_SLOT_THRUSTERS)
|
||||
if(istype(T) && movement_dir && T.allow_thrust(0.01))
|
||||
return 1
|
||||
|
||||
var/obj/item/tank/jetpack/J = get_jetpack()
|
||||
if(istype(J) && (movement_dir || J.stabilizers) && J.allow_thrust(0.01, src))
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/Move(NewLoc, direct)
|
||||
. = ..()
|
||||
if(. && (movement_type & FLOATING)) //floating is easy
|
||||
if(HAS_TRAIT(src, TRAIT_NOHUNGER))
|
||||
nutrition = NUTRITION_LEVEL_FED - 1 //just less than feeling vigorous
|
||||
else if(nutrition && stat != DEAD)
|
||||
nutrition -= HUNGER_FACTOR/10
|
||||
if(m_intent == MOVE_INTENT_RUN)
|
||||
nutrition -= HUNGER_FACTOR/10
|
||||
@@ -1,302 +0,0 @@
|
||||
|
||||
|
||||
/mob/living/carbon/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE)
|
||||
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]
|
||||
|
||||
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))
|
||||
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)))
|
||||
update_damage_overlays()
|
||||
else
|
||||
adjustFireLoss(damage_amount, forced = forced)
|
||||
if(TOX)
|
||||
adjustToxLoss(damage_amount, forced = forced)
|
||||
if(OXY)
|
||||
adjustOxyLoss(damage_amount, forced = forced)
|
||||
if(CLONE)
|
||||
adjustCloneLoss(damage_amount, forced = forced)
|
||||
if(STAMINA)
|
||||
if(BP)
|
||||
if(damage > 0 ? BP.receive_damage(0, 0, damage_amount) : BP.heal_damage(0, 0, abs(damage_amount)))
|
||||
update_damage_overlays()
|
||||
else
|
||||
adjustStaminaLoss(damage_amount, forced = forced)
|
||||
//citadel code
|
||||
if(AROUSAL)
|
||||
adjustArousalLoss(damage_amount, forced = forced)
|
||||
return TRUE
|
||||
|
||||
|
||||
|
||||
//These procs fetch a cumulative total damage from all bodyparts
|
||||
/mob/living/carbon/getBruteLoss()
|
||||
var/amount = 0
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
amount += BP.brute_dam
|
||||
return amount
|
||||
|
||||
/mob/living/carbon/getFireLoss()
|
||||
var/amount = 0
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
amount += BP.burn_dam
|
||||
return amount
|
||||
|
||||
|
||||
/mob/living/carbon/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE)
|
||||
if(!forced && (status_flags & GODMODE))
|
||||
return FALSE
|
||||
if(amount > 0)
|
||||
take_overall_damage(amount, 0, 0, updating_health)
|
||||
else
|
||||
heal_overall_damage(abs(amount), 0, 0, FALSE, TRUE, updating_health)
|
||||
return amount
|
||||
|
||||
/mob/living/carbon/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE)
|
||||
if(!forced && (status_flags & GODMODE))
|
||||
return FALSE
|
||||
if(amount > 0)
|
||||
take_overall_damage(0, amount, 0, updating_health)
|
||||
else
|
||||
heal_overall_damage(0, abs(amount), 0, FALSE, TRUE, updating_health)
|
||||
return amount
|
||||
|
||||
/mob/living/carbon/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE)
|
||||
if(!forced && HAS_TRAIT(src, TRAIT_TOXINLOVER)) //damage becomes healing and healing becomes damage
|
||||
amount = -amount
|
||||
if(amount > 0)
|
||||
blood_volume -= 3*amount // x5 is too much, x3 should be still penalizing enough.
|
||||
else
|
||||
blood_volume -= amount
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/getStaminaLoss()
|
||||
. = 0
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
. += round(BP.stamina_dam * BP.stam_damage_coeff, DAMAGE_PRECISION)
|
||||
|
||||
/mob/living/carbon/adjustStaminaLoss(amount, updating_health = TRUE, forced = FALSE)
|
||||
if(!forced && (status_flags & GODMODE))
|
||||
return FALSE
|
||||
if(amount > 0)
|
||||
take_overall_damage(0, 0, amount, updating_health)
|
||||
else
|
||||
heal_overall_damage(0, 0, abs(amount), FALSE, FALSE, updating_health)
|
||||
return amount
|
||||
|
||||
/mob/living/carbon/setStaminaLoss(amount, updating = TRUE, forced = FALSE)
|
||||
var/current = getStaminaLoss()
|
||||
var/diff = amount - current
|
||||
if(!diff)
|
||||
return
|
||||
adjustStaminaLoss(diff, updating, forced)
|
||||
|
||||
/** adjustOrganLoss
|
||||
* inputs: slot (organ slot, like ORGAN_SLOT_HEART), amount (damage to be done), and maximum (currently an arbitrarily large number, can be set so as to limit damage)
|
||||
* outputs:
|
||||
* description: If an organ exists in the slot requested, and we are capable of taking damage (we don't have GODMODE on), call the damage proc on that organ.
|
||||
*/
|
||||
/mob/living/carbon/adjustOrganLoss(slot, amount, maximum)
|
||||
var/obj/item/organ/O = getorganslot(slot)
|
||||
if(O && !(status_flags & GODMODE))
|
||||
if(!maximum)
|
||||
maximum = O.maxHealth
|
||||
O.applyOrganDamage(amount, maximum)
|
||||
O.onDamage(amount, maximum)
|
||||
|
||||
/** setOrganLoss
|
||||
* inputs: slot (organ slot, like ORGAN_SLOT_HEART), amount(damage to be set to)
|
||||
* outputs:
|
||||
* description: If an organ exists in the slot requested, and we are capable of taking damage (we don't have GODMODE on), call the set damage proc on that organ, which can
|
||||
* set or clear the failing variable on that organ, making it either cease or start functions again, unlike adjustOrganLoss.
|
||||
*/
|
||||
/mob/living/carbon/setOrganLoss(slot, amount)
|
||||
var/obj/item/organ/O = getorganslot(slot)
|
||||
if(O && !(status_flags & GODMODE))
|
||||
O.setOrganDamage(amount)
|
||||
O.onSetDamage(amount)
|
||||
|
||||
/** getOrganLoss
|
||||
* inputs: slot (organ slot, like ORGAN_SLOT_HEART)
|
||||
* outputs: organ damage
|
||||
* description: If an organ exists in the slot requested, return the amount of damage that organ has
|
||||
*/
|
||||
/mob/living/carbon/getOrganLoss(slot)
|
||||
var/obj/item/organ/O = getorganslot(slot)
|
||||
if(O)
|
||||
return O.damage
|
||||
|
||||
/mob/living/carbon/proc/adjustAllOrganLoss(amount, maximum)
|
||||
for(var/obj/item/organ/O in internal_organs)
|
||||
if(O && !(status_flags & GODMODE))
|
||||
continue
|
||||
if(!maximum)
|
||||
maximum = O.maxHealth
|
||||
O.applyOrganDamage(amount, maximum)
|
||||
O.onDamage(amount, maximum)
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
|
||||
//Returns a list of damaged bodyparts
|
||||
/mob/living/carbon/proc/get_damaged_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(status && BP.status != status)
|
||||
continue
|
||||
if((brute && BP.brute_dam) || (burn && BP.burn_dam) || (stamina && BP.stamina_dam))
|
||||
parts += BP
|
||||
return parts
|
||||
|
||||
//Returns a list of damageable bodyparts
|
||||
/mob/living/carbon/proc/get_damageable_bodyparts()
|
||||
var/list/obj/item/bodypart/parts = list()
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
if(BP.brute_dam + BP.burn_dam < BP.max_damage)
|
||||
parts += BP
|
||||
return parts
|
||||
|
||||
//Heals ONE bodypart randomly selected from damaged ones.
|
||||
//It automatically updates damage overlays if necessary
|
||||
//It automatically updates health status
|
||||
/mob/living/carbon/heal_bodypart_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE, only_robotic = FALSE, only_organic = TRUE)
|
||||
var/list/obj/item/bodypart/parts = get_damaged_bodyparts(brute,burn)
|
||||
if(!parts.len)
|
||||
return
|
||||
var/obj/item/bodypart/picked = pick(parts)
|
||||
if(picked.heal_damage(brute, burn, stamina, only_robotic, only_organic))
|
||||
update_damage_overlays()
|
||||
|
||||
//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)
|
||||
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))
|
||||
update_damage_overlays()
|
||||
|
||||
//Heal MANY bodyparts, in random order
|
||||
/mob/living/carbon/heal_overall_damage(brute = 0, burn = 0, stamina = 0, only_robotic = FALSE, only_organic = TRUE, updating_health = TRUE)
|
||||
var/list/obj/item/bodypart/parts = get_damaged_bodyparts(brute, burn, stamina)
|
||||
|
||||
var/update = NONE
|
||||
while(parts.len && (brute > 0 || burn > 0 || stamina > 0))
|
||||
var/obj/item/bodypart/picked = pick(parts)
|
||||
|
||||
var/brute_was = picked.brute_dam
|
||||
var/burn_was = picked.burn_dam
|
||||
var/stamina_was = picked.stamina_dam
|
||||
|
||||
update |= picked.heal_damage(brute, burn, stamina, only_robotic, only_organic, FALSE)
|
||||
|
||||
brute = round(brute - (brute_was - picked.brute_dam), DAMAGE_PRECISION)
|
||||
burn = round(burn - (burn_was - picked.burn_dam), DAMAGE_PRECISION)
|
||||
stamina = round(stamina - (stamina_was - picked.stamina_dam), DAMAGE_PRECISION)
|
||||
|
||||
parts -= picked
|
||||
if(updating_health)
|
||||
updatehealth()
|
||||
if(update)
|
||||
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)
|
||||
if(status_flags & GODMODE)
|
||||
return //godmode
|
||||
|
||||
var/list/obj/item/bodypart/parts = get_damageable_bodyparts()
|
||||
var/update = 0
|
||||
while(parts.len && (brute > 0 || burn > 0 || stamina > 0))
|
||||
var/obj/item/bodypart/picked = pick(parts)
|
||||
var/brute_per_part = round(brute/parts.len, DAMAGE_PRECISION)
|
||||
var/burn_per_part = round(burn/parts.len, DAMAGE_PRECISION)
|
||||
var/stamina_per_part = round(stamina/parts.len, DAMAGE_PRECISION)
|
||||
|
||||
var/brute_was = picked.brute_dam
|
||||
var/burn_was = picked.burn_dam
|
||||
var/stamina_was = picked.stamina_dam
|
||||
|
||||
|
||||
update |= picked.receive_damage(brute_per_part, burn_per_part, stamina_per_part, FALSE)
|
||||
|
||||
brute = round(brute - (picked.brute_dam - brute_was), DAMAGE_PRECISION)
|
||||
burn = round(burn - (picked.burn_dam - burn_was), DAMAGE_PRECISION)
|
||||
stamina = round(stamina - (picked.stamina_dam - stamina_was), DAMAGE_PRECISION)
|
||||
|
||||
parts -= picked
|
||||
if(updating_health)
|
||||
updatehealth()
|
||||
if(update)
|
||||
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)
|
||||
*/
|
||||
@@ -1,99 +0,0 @@
|
||||
/datum/emote/living/carbon
|
||||
mob_type_allowed_typecache = list(/mob/living/carbon)
|
||||
|
||||
/datum/emote/living/carbon/airguitar
|
||||
key = "airguitar"
|
||||
message = "is strumming the air and headbanging like a safari chimp."
|
||||
restraint_check = TRUE
|
||||
|
||||
/datum/emote/living/carbon/blink
|
||||
key = "blink"
|
||||
key_third_person = "blinks"
|
||||
message = "blinks."
|
||||
|
||||
/datum/emote/living/carbon/blink_r
|
||||
key = "blink_r"
|
||||
message = "blinks rapidly."
|
||||
|
||||
/datum/emote/living/carbon/clap
|
||||
key = "clap"
|
||||
key_third_person = "claps"
|
||||
message = "claps."
|
||||
muzzle_ignore = TRUE
|
||||
restraint_check = TRUE
|
||||
emote_type = EMOTE_AUDIBLE
|
||||
|
||||
/datum/emote/living/carbon/clap/run_emote(mob/living/user, params)
|
||||
. = ..()
|
||||
if (.)
|
||||
if (ishuman(user))
|
||||
// Need hands to clap
|
||||
if (!user.get_bodypart(BODY_ZONE_L_ARM) || !user.get_bodypart(BODY_ZONE_R_ARM))
|
||||
return
|
||||
var/clap = pick('sound/misc/clap1.ogg',
|
||||
'sound/misc/clap2.ogg',
|
||||
'sound/misc/clap3.ogg',
|
||||
'sound/misc/clap4.ogg')
|
||||
playsound(user, clap, 50, 1, -1)
|
||||
|
||||
/datum/emote/living/carbon/gnarl
|
||||
key = "gnarl"
|
||||
key_third_person = "gnarls"
|
||||
message = "gnarls and shows its teeth..."
|
||||
mob_type_allowed_typecache = list(/mob/living/carbon/monkey, /mob/living/carbon/alien)
|
||||
|
||||
/datum/emote/living/carbon/moan
|
||||
key = "moan"
|
||||
key_third_person = "moans"
|
||||
message = "moans!"
|
||||
message_mime = "appears to moan!"
|
||||
emote_type = EMOTE_AUDIBLE
|
||||
|
||||
/datum/emote/living/carbon/roll
|
||||
key = "roll"
|
||||
key_third_person = "rolls"
|
||||
message = "rolls."
|
||||
mob_type_allowed_typecache = list(/mob/living/carbon/monkey, /mob/living/carbon/alien)
|
||||
restraint_check = TRUE
|
||||
|
||||
/datum/emote/living/carbon/scratch
|
||||
key = "scratch"
|
||||
key_third_person = "scratches"
|
||||
message = "scratches."
|
||||
mob_type_allowed_typecache = list(/mob/living/carbon/monkey, /mob/living/carbon/alien)
|
||||
restraint_check = TRUE
|
||||
|
||||
/datum/emote/living/carbon/screech
|
||||
key = "screech"
|
||||
key_third_person = "screeches"
|
||||
message = "screeches."
|
||||
mob_type_allowed_typecache = list(/mob/living/carbon/monkey, /mob/living/carbon/alien)
|
||||
|
||||
/datum/emote/living/carbon/sign
|
||||
key = "sign"
|
||||
key_third_person = "signs"
|
||||
message_param = "signs the number %t."
|
||||
mob_type_allowed_typecache = list(/mob/living/carbon/monkey, /mob/living/carbon/alien)
|
||||
restraint_check = TRUE
|
||||
|
||||
/datum/emote/living/carbon/sign/select_param(mob/user, params)
|
||||
. = ..()
|
||||
if(!isnum(text2num(params)))
|
||||
return message
|
||||
|
||||
/datum/emote/living/carbon/sign/signal
|
||||
key = "signal"
|
||||
key_third_person = "signals"
|
||||
message_param = "raises %t fingers."
|
||||
mob_type_allowed_typecache = list(/mob/living/carbon/human)
|
||||
restraint_check = TRUE
|
||||
|
||||
/datum/emote/living/carbon/tail
|
||||
key = "tail"
|
||||
message = "waves their tail."
|
||||
mob_type_allowed_typecache = list(/mob/living/carbon/monkey, /mob/living/carbon/alien)
|
||||
|
||||
/datum/emote/living/carbon/wink
|
||||
key = "wink"
|
||||
key_third_person = "winks"
|
||||
message = "winks."
|
||||
@@ -1,114 +0,0 @@
|
||||
/mob/living/carbon/examine(mob/user)
|
||||
var/t_He = p_they(TRUE)
|
||||
var/t_His = p_their(TRUE)
|
||||
var/t_his = p_their()
|
||||
var/t_him = p_them()
|
||||
var/t_has = p_have()
|
||||
var/t_is = p_are()
|
||||
|
||||
var/msg = "<span class='info'>*---------*\nThis is [icon2html(src, user)] \a <EM>[src]</EM>!\n"
|
||||
|
||||
if (handcuffed)
|
||||
msg += "<span class='warning'>[t_He] [t_is] [icon2html(handcuffed, user)] handcuffed!</span>\n"
|
||||
if (head)
|
||||
msg += "[t_He] [t_is] wearing [head.get_examine_string(user)] on [t_his] head. \n"
|
||||
if (wear_mask)
|
||||
msg += "[t_He] [t_is] wearing [wear_mask.get_examine_string(user)] on [t_his] face.\n"
|
||||
if (wear_neck)
|
||||
msg += "[t_He] [t_is] wearing [wear_neck.get_examine_string(user)] around [t_his] neck.\n"
|
||||
|
||||
for(var/obj/item/I in held_items)
|
||||
if(!(I.item_flags & ABSTRACT))
|
||||
msg += "[t_He] [t_is] holding [I.get_examine_string(user)] in [t_his] [get_held_index_name(get_held_index_of_item(I))].\n"
|
||||
|
||||
if (back)
|
||||
msg += "[t_He] [t_has] [back.get_examine_string(user)] on [t_his] back.\n"
|
||||
var/appears_dead = 0
|
||||
if (stat == DEAD)
|
||||
appears_dead = 1
|
||||
if(getorgan(/obj/item/organ/brain))
|
||||
msg += "<span class='deadsay'>[t_He] [t_is] limp and unresponsive, with no signs of life.</span>\n"
|
||||
else if(get_bodypart(BODY_ZONE_HEAD))
|
||||
msg += "<span class='deadsay'>It appears that [t_his] brain is missing...</span>\n"
|
||||
|
||||
var/list/missing = get_missing_limbs()
|
||||
for(var/t in missing)
|
||||
if(t==BODY_ZONE_HEAD)
|
||||
msg += "<span class='deadsay'><B>[t_His] [parse_zone(t)] is missing!</B></span>\n"
|
||||
continue
|
||||
msg += "<span class='warning'><B>[t_His] [parse_zone(t)] is missing!</B></span>\n"
|
||||
|
||||
msg += "<span class='warning'>"
|
||||
var/temp = getBruteLoss()
|
||||
if(!(user == src && src.hal_screwyhud == SCREWYHUD_HEALTHY)) //fake healthy
|
||||
if(temp)
|
||||
if (temp < 25)
|
||||
msg += "[t_He] [t_has] minor bruising.\n"
|
||||
else if (temp < 50)
|
||||
msg += "[t_He] [t_has] <b>moderate</b> bruising!\n"
|
||||
else
|
||||
msg += "<B>[t_He] [t_has] severe bruising!</B>\n"
|
||||
|
||||
temp = getFireLoss()
|
||||
if(temp)
|
||||
if (temp < 25)
|
||||
msg += "[t_He] [t_has] minor burns.\n"
|
||||
else if (temp < 50)
|
||||
msg += "[t_He] [t_has] <b>moderate</b> burns!\n"
|
||||
else
|
||||
msg += "<B>[t_He] [t_has] severe burns!</B>\n"
|
||||
|
||||
temp = getCloneLoss()
|
||||
if(temp)
|
||||
if(temp < 25)
|
||||
msg += "[t_He] [t_is] slightly deformed.\n"
|
||||
else if (temp < 50)
|
||||
msg += "[t_He] [t_is] <b>moderately</b> deformed!\n"
|
||||
else
|
||||
msg += "<b>[t_He] [t_is] severely deformed!</b>\n"
|
||||
|
||||
if(HAS_TRAIT(src, TRAIT_DUMB))
|
||||
msg += "[t_He] seem[p_s()] to be clumsy and unable to think.\n"
|
||||
|
||||
if(fire_stacks > 0)
|
||||
msg += "[t_He] [t_is] covered in something flammable.\n"
|
||||
if(fire_stacks < 0)
|
||||
msg += "[t_He] look[p_s()] a little soaked.\n"
|
||||
|
||||
if(pulledby && pulledby.grab_state)
|
||||
msg += "[t_He] [t_is] restrained by [pulledby]'s grip.\n"
|
||||
|
||||
msg += "</span>"
|
||||
|
||||
if(!appears_dead)
|
||||
if(stat == UNCONSCIOUS)
|
||||
msg += "[t_He] [t_is]n't responding to anything around [t_him] and seems to be asleep.\n"
|
||||
else if(InCritical())
|
||||
msg += "[t_His] breathing is shallow and labored.\n"
|
||||
|
||||
if(digitalcamo)
|
||||
msg += "[t_He] [t_is] moving [t_his] body in an unnatural and blatantly unsimian manner.\n"
|
||||
|
||||
if(combatmode)
|
||||
msg += "[t_He] [t_is] visibly tense[resting ? "." : ", and [t_is] standing in combative stance."]\n"
|
||||
msg += common_trait_examine()
|
||||
|
||||
var/datum/component/mood/mood = src.GetComponent(/datum/component/mood)
|
||||
if(mood)
|
||||
switch(mood.shown_mood)
|
||||
if(-INFINITY to MOOD_LEVEL_SAD4)
|
||||
msg += "[t_He] look[p_s()] depressed.\n"
|
||||
if(MOOD_LEVEL_SAD4 to MOOD_LEVEL_SAD3)
|
||||
msg += "[t_He] look[p_s()] very sad.\n"
|
||||
if(MOOD_LEVEL_SAD3 to MOOD_LEVEL_SAD2)
|
||||
msg += "[t_He] look[p_s()] a bit down.\n"
|
||||
if(MOOD_LEVEL_HAPPY2 to MOOD_LEVEL_HAPPY3)
|
||||
msg += "[t_He] look[p_s()] quite happy.\n"
|
||||
if(MOOD_LEVEL_HAPPY3 to MOOD_LEVEL_HAPPY4)
|
||||
msg += "[t_He] look[p_s()] very happy.\n"
|
||||
if(MOOD_LEVEL_HAPPY4 to INFINITY)
|
||||
msg += "[t_He] look[p_s()] ecstatic.\n"
|
||||
msg += "*---------*</span>"
|
||||
|
||||
to_chat(user, msg)
|
||||
return msg
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
|
||||
/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)
|
||||
@@ -1,69 +0,0 @@
|
||||
/mob/living/carbon/human/gib_animation()
|
||||
new /obj/effect/temp_visual/gib_animation(loc, "gibbed-h")
|
||||
|
||||
/mob/living/carbon/human/dust_animation()
|
||||
new /obj/effect/temp_visual/dust_animation(loc, "dust-h")
|
||||
|
||||
/mob/living/carbon/human/spawn_gibs(with_bodyparts, atom/loc_override)
|
||||
var/location = loc_override ? loc_override.drop_location() : drop_location()
|
||||
if(dna?.species?.gib_types)
|
||||
var/datum/species/S = dna.species
|
||||
var/length = length(S.gib_types)
|
||||
if(length)
|
||||
var/path = (with_bodyparts && length > 1) ? S.gib_types[2] : S.gib_types[1]
|
||||
new path(location, src, get_static_viruses())
|
||||
else
|
||||
new S.gib_types(location, src, get_static_viruses())
|
||||
else
|
||||
if(with_bodyparts)
|
||||
new /obj/effect/gibspawner/human(location, src, get_static_viruses())
|
||||
else
|
||||
new /obj/effect/gibspawner/human/bodypartless(location, src, get_static_viruses())
|
||||
|
||||
/mob/living/carbon/human/spawn_dust(just_ash = FALSE)
|
||||
if(just_ash)
|
||||
new /obj/effect/decal/cleanable/ash(loc)
|
||||
else
|
||||
new /obj/effect/decal/remains/human(loc)
|
||||
|
||||
/mob/living/carbon/human/death(gibbed)
|
||||
if(stat == DEAD)
|
||||
return
|
||||
stop_sound_channel(CHANNEL_HEARTBEAT)
|
||||
var/obj/item/organ/heart/H = getorganslot(ORGAN_SLOT_HEART)
|
||||
if(H)
|
||||
H.beat = BEAT_NONE
|
||||
|
||||
. = ..()
|
||||
|
||||
dizziness = 0
|
||||
jitteriness = 0
|
||||
|
||||
if(ismecha(loc))
|
||||
var/obj/mecha/M = loc
|
||||
if(M.occupant == src)
|
||||
M.go_out()
|
||||
|
||||
dna.species.spec_death(gibbed, src)
|
||||
|
||||
if(SSticker.HasRoundStarted())
|
||||
SSblackbox.ReportDeath(src)
|
||||
if(is_devil(src))
|
||||
INVOKE_ASYNC(is_devil(src), /datum/antagonist/devil.proc/beginResurrectionCheck, src)
|
||||
|
||||
/mob/living/carbon/human/proc/makeSkeleton()
|
||||
ADD_TRAIT(src, TRAIT_DISFIGURED, TRAIT_GENERIC)
|
||||
set_species(/datum/species/skeleton)
|
||||
return TRUE
|
||||
|
||||
|
||||
/mob/living/carbon/proc/Drain()
|
||||
become_husk(CHANGELING_DRAIN)
|
||||
ADD_TRAIT(src, TRAIT_NOCLONE, CHANGELING_DRAIN)
|
||||
blood_volume = 0
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/proc/makeUncloneable()
|
||||
ADD_TRAIT(src, TRAIT_NOCLONE, MADE_UNCLONEABLE)
|
||||
blood_volume = 0
|
||||
return TRUE
|
||||
@@ -1,47 +0,0 @@
|
||||
|
||||
/mob/living/carbon/human/dummy
|
||||
real_name = "Test Dummy"
|
||||
status_flags = GODMODE|CANPUSH
|
||||
mouse_drag_pointer = MOUSE_INACTIVE_POINTER
|
||||
var/in_use = FALSE
|
||||
no_vore = TRUE
|
||||
|
||||
INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
|
||||
|
||||
/mob/living/carbon/human/dummy/Destroy()
|
||||
in_use = FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/dummy/Life()
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/dummy/proc/wipe_state()
|
||||
delete_equipment()
|
||||
cut_overlays(TRUE)
|
||||
|
||||
//Inefficient pooling/caching way.
|
||||
GLOBAL_LIST_EMPTY(human_dummy_list)
|
||||
GLOBAL_LIST_EMPTY(dummy_mob_list)
|
||||
|
||||
/proc/generate_or_wait_for_human_dummy(slotkey)
|
||||
if(!slotkey)
|
||||
return new /mob/living/carbon/human/dummy
|
||||
var/mob/living/carbon/human/dummy/D = GLOB.human_dummy_list[slotkey]
|
||||
if(istype(D))
|
||||
UNTIL(!D.in_use)
|
||||
else
|
||||
pass()
|
||||
if(QDELETED(D))
|
||||
D = new
|
||||
GLOB.human_dummy_list[slotkey] = D
|
||||
GLOB.dummy_mob_list += D
|
||||
D.in_use = TRUE
|
||||
return D
|
||||
|
||||
/proc/unset_busy_human_dummy(slotnumber)
|
||||
if(!slotnumber)
|
||||
return
|
||||
var/mob/living/carbon/human/dummy/D = GLOB.human_dummy_list[slotnumber]
|
||||
if(istype(D))
|
||||
D.wipe_state()
|
||||
D.in_use = FALSE
|
||||
@@ -1,413 +0,0 @@
|
||||
/mob/living/carbon/human/examine(mob/user)
|
||||
//this is very slightly better than it was because you can use it more places. still can't do \his[src] though.
|
||||
var/t_He = p_they(TRUE)
|
||||
var/t_His = p_their(TRUE)
|
||||
var/t_his = p_their()
|
||||
var/t_him = p_them()
|
||||
var/t_has = p_have()
|
||||
var/t_is = p_are()
|
||||
var/obscure_name
|
||||
|
||||
if(isliving(user))
|
||||
var/mob/living/L = user
|
||||
if(HAS_TRAIT(L, TRAIT_PROSOPAGNOSIA))
|
||||
obscure_name = TRUE
|
||||
|
||||
var/msg = "<span class='info'>*---------*\nThis is <EM>[!obscure_name ? name : "Unknown"]</EM>!\n"
|
||||
|
||||
var/list/obscured = check_obscured_slots()
|
||||
var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))
|
||||
|
||||
if(ishuman(src)) //user just returned, y'know, the user's own species. dumb.
|
||||
var/mob/living/carbon/human/H = src
|
||||
var/datum/species/pref_species = H.dna.species
|
||||
if(get_visible_name() == "Unknown") // same as flavor text, but hey it works.
|
||||
msg += "You can't make out what species they are.\n"
|
||||
else if(skipface)
|
||||
msg += "You can't make out what species they are.\n"
|
||||
else
|
||||
msg += "[t_He] [t_is] a [H.dna.custom_species ? H.dna.custom_species : pref_species.name]!\n"
|
||||
|
||||
//uniform
|
||||
if(w_uniform && !(SLOT_W_UNIFORM in obscured))
|
||||
//accessory
|
||||
var/accessory_msg
|
||||
if(istype(w_uniform, /obj/item/clothing/under))
|
||||
var/obj/item/clothing/under/U = w_uniform
|
||||
if(U.attached_accessory)
|
||||
accessory_msg += " with [icon2html(U.attached_accessory, user)] \a [U.attached_accessory]"
|
||||
|
||||
msg += "[t_He] [t_is] wearing [w_uniform.get_examine_string(user)][accessory_msg].\n"
|
||||
//head
|
||||
if(head)
|
||||
msg += "[t_He] [t_is] wearing [head.get_examine_string(user)] on [t_his] head.\n"
|
||||
//suit/armor
|
||||
if(wear_suit)
|
||||
msg += "[t_He] [t_is] wearing [wear_suit.get_examine_string(user)].\n"
|
||||
//suit/armor storage
|
||||
if(s_store && !(SLOT_S_STORE in obscured))
|
||||
msg += "[t_He] [t_is] carrying [s_store.get_examine_string(user)] on [t_his] [wear_suit.name].\n"
|
||||
//back
|
||||
if(back)
|
||||
msg += "[t_He] [t_has] [back.get_examine_string(user)] on [t_his] back.\n"
|
||||
|
||||
//Hands
|
||||
for(var/obj/item/I in held_items)
|
||||
if(!(I.item_flags & ABSTRACT))
|
||||
msg += "[t_He] [t_is] holding [I.get_examine_string(user)] in [t_his] [get_held_index_name(get_held_index_of_item(I))].\n"
|
||||
|
||||
//gloves
|
||||
if(gloves && !(SLOT_GLOVES in obscured))
|
||||
msg += "[t_He] [t_has] [gloves.get_examine_string(user)] on [t_his] hands.\n"
|
||||
else if(length(blood_DNA))
|
||||
var/hand_number = get_num_arms(FALSE)
|
||||
if(hand_number)
|
||||
msg += "<span class='warning'>[t_He] [t_has] [hand_number > 1 ? "" : "a"] blood-stained hand[hand_number > 1 ? "s" : ""]!</span>\n"
|
||||
|
||||
//handcuffed?
|
||||
|
||||
//handcuffed?
|
||||
if(handcuffed)
|
||||
if(istype(handcuffed, /obj/item/restraints/handcuffs/cable))
|
||||
msg += "<span class='warning'>[t_He] [t_is] [icon2html(handcuffed, user)] restrained with cable!</span>\n"
|
||||
else
|
||||
msg += "<span class='warning'>[t_He] [t_is] [icon2html(handcuffed, user)] handcuffed!</span>\n"
|
||||
|
||||
//belt
|
||||
if(belt)
|
||||
msg += "[t_He] [t_has] [belt.get_examine_string(user)] about [t_his] waist.\n"
|
||||
|
||||
//shoes
|
||||
if(shoes && !(SLOT_SHOES in obscured))
|
||||
msg += "[t_He] [t_is] wearing [shoes.get_examine_string(user)] on [t_his] feet.\n"
|
||||
|
||||
//mask
|
||||
if(wear_mask && !(SLOT_WEAR_MASK in obscured))
|
||||
msg += "[t_He] [t_has] [wear_mask.get_examine_string(user)] on [t_his] face.\n"
|
||||
|
||||
if(wear_neck && !(SLOT_NECK in obscured))
|
||||
msg += "[t_He] [t_is] wearing [wear_neck.get_examine_string(user)] around [t_his] neck.\n"
|
||||
|
||||
//eyes
|
||||
if(!(SLOT_GLASSES in obscured))
|
||||
if(glasses)
|
||||
msg += "[t_He] [t_has] [glasses.get_examine_string(user)] covering [t_his] eyes.\n"
|
||||
else if(eye_color == BLOODCULT_EYE && iscultist(src) && HAS_TRAIT(src, TRAIT_CULT_EYES))
|
||||
msg += "<span class='warning'><B>[t_His] eyes are glowing an unnatural red!</B></span>\n"
|
||||
|
||||
//ears
|
||||
if(ears && !(SLOT_EARS in obscured))
|
||||
msg += "[t_He] [t_has] [ears.get_examine_string(user)] on [t_his] ears.\n"
|
||||
|
||||
//ID
|
||||
if(wear_id)
|
||||
msg += "[t_He] [t_is] wearing [wear_id.get_examine_string(user)].\n"
|
||||
|
||||
//Status effects
|
||||
msg += status_effect_examines()
|
||||
|
||||
//CIT CHANGES START HERE - adds genital details to examine text
|
||||
if(LAZYLEN(internal_organs))
|
||||
for(var/obj/item/organ/genital/dicc in internal_organs)
|
||||
if(istype(dicc) && dicc.is_exposed())
|
||||
msg += "[dicc.desc]\n"
|
||||
|
||||
msg += attempt_vr(src,"examine_bellies",args) //vore Code
|
||||
//END OF CIT CHANGES
|
||||
|
||||
//Jitters
|
||||
switch(jitteriness)
|
||||
if(300 to INFINITY)
|
||||
msg += "<span class='warning'><B>[t_He] [t_is] convulsing violently!</B></span>\n"
|
||||
if(200 to 300)
|
||||
msg += "<span class='warning'>[t_He] [t_is] extremely jittery.</span>\n"
|
||||
if(100 to 200)
|
||||
msg += "<span class='warning'>[t_He] [t_is] twitching ever so slightly.</span>\n"
|
||||
|
||||
var/appears_dead = 0
|
||||
if(stat == DEAD || (HAS_TRAIT(src, TRAIT_FAKEDEATH)))
|
||||
appears_dead = 1
|
||||
if(suiciding)
|
||||
msg += "<span class='warning'>[t_He] appear[p_s()] to have committed suicide... there is no hope of recovery.</span>\n"
|
||||
if(hellbound)
|
||||
msg += "<span class='warning'>[t_His] soul seems to have been ripped out of [t_his] body. Revival is impossible.</span>\n"
|
||||
msg += "<span class='deadsay'>[t_He] [t_is] limp and unresponsive; there are no signs of life"
|
||||
if(getorgan(/obj/item/organ/brain))
|
||||
if(!key)
|
||||
var/foundghost = 0
|
||||
if(mind)
|
||||
for(var/mob/dead/observer/G in GLOB.player_list)
|
||||
if(G.mind == mind)
|
||||
foundghost = 1
|
||||
if (G.can_reenter_corpse == 0)
|
||||
foundghost = 0
|
||||
break
|
||||
if(!foundghost)
|
||||
msg += " and [t_his] soul has departed"
|
||||
msg += "...</span>\n"
|
||||
|
||||
if(get_bodypart(BODY_ZONE_HEAD) && !getorgan(/obj/item/organ/brain))
|
||||
msg += "<span class='deadsay'>It appears that [t_his] brain is missing...</span>\n"
|
||||
|
||||
var/temp = getBruteLoss() //no need to calculate each of these twice
|
||||
|
||||
msg += "<span class='warning'>" //Everything below gets this 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)
|
||||
var/list/disabled = list()
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
if(BP.disabled)
|
||||
disabled += BP
|
||||
missing -= BP.body_zone
|
||||
for(var/obj/item/I in BP.embedded_objects)
|
||||
msg += "<B>[t_He] [t_has] \a [icon2html(I, user)] [I] embedded in [t_his] [BP.name]!</B>\n"
|
||||
|
||||
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
|
||||
var/more_brute = BP.brute_dam >= BP.burn_dam
|
||||
damage_text = more_brute ? "broken and mangled" : "burnt and blistered"
|
||||
msg += "<B>[capitalize(t_his)] [BP.name] is [damage_text]!</B>\n"
|
||||
|
||||
//stores missing limbs
|
||||
var/l_limbs_missing = 0
|
||||
var/r_limbs_missing = 0
|
||||
for(var/t in missing)
|
||||
if(t==BODY_ZONE_HEAD)
|
||||
msg += "<span class='deadsay'><B>[t_His] [parse_zone(t)] is missing!</B><span class='warning'>\n"
|
||||
continue
|
||||
if(t == BODY_ZONE_L_ARM || t == BODY_ZONE_L_LEG)
|
||||
l_limbs_missing++
|
||||
else if(t == BODY_ZONE_R_ARM || t == BODY_ZONE_R_LEG)
|
||||
r_limbs_missing++
|
||||
|
||||
msg += "<B>[capitalize(t_his)] [parse_zone(t)] is missing!</B>\n"
|
||||
|
||||
if(l_limbs_missing >= 2 && r_limbs_missing == 0)
|
||||
msg += "[t_He] look[p_s()] all right now.\n"
|
||||
else if(l_limbs_missing == 0 && r_limbs_missing >= 2)
|
||||
msg += "[t_He] really keeps to the left.\n"
|
||||
else if(l_limbs_missing >= 2 && r_limbs_missing >= 2)
|
||||
msg += "[t_He] [p_do()]n't seem all there.\n"
|
||||
|
||||
if(!(user == src && src.hal_screwyhud == SCREWYHUD_HEALTHY)) //fake healthy
|
||||
if(temp)
|
||||
if(temp < 25)
|
||||
msg += "[t_He] [t_has] minor bruising.\n"
|
||||
else if(temp < 50)
|
||||
msg += "[t_He] [t_has] <b>moderate</b> bruising!\n"
|
||||
else
|
||||
msg += "<B>[t_He] [t_has] severe bruising!</B>\n"
|
||||
|
||||
temp = getFireLoss()
|
||||
if(temp)
|
||||
if(temp < 25)
|
||||
msg += "[t_He] [t_has] minor burns.\n"
|
||||
else if (temp < 50)
|
||||
msg += "[t_He] [t_has] <b>moderate</b> burns!\n"
|
||||
else
|
||||
msg += "<B>[t_He] [t_has] severe burns!</B>\n"
|
||||
|
||||
temp = getCloneLoss()
|
||||
if(temp)
|
||||
if(temp < 25)
|
||||
msg += "[t_He] [t_has] minor cellular damage.\n"
|
||||
else if(temp < 50)
|
||||
msg += "[t_He] [t_has] <b>moderate</b> cellular damage!\n"
|
||||
else
|
||||
msg += "<b>[t_He] [t_has] severe cellular damage!</b>\n"
|
||||
|
||||
|
||||
if(fire_stacks > 0)
|
||||
msg += "[t_He] [t_is] covered in something flammable.\n"
|
||||
if(fire_stacks < 0)
|
||||
msg += "[t_He] look[p_s()] a little soaked.\n"
|
||||
|
||||
|
||||
if(pulledby && pulledby.grab_state)
|
||||
msg += "[t_He] [t_is] restrained by [pulledby]'s grip.\n"
|
||||
|
||||
if(nutrition < NUTRITION_LEVEL_STARVING - 50)
|
||||
msg += "[t_He] [t_is] severely malnourished.\n"
|
||||
else if(nutrition >= NUTRITION_LEVEL_FAT)
|
||||
if(user.nutrition < NUTRITION_LEVEL_STARVING - 50)
|
||||
msg += "[t_He] [t_is] plump and delicious looking - Like a fat little piggy. A tasty piggy.\n"
|
||||
else
|
||||
msg += "[t_He] [t_is] quite chubby.\n"
|
||||
switch(disgust)
|
||||
if(DISGUST_LEVEL_GROSS to DISGUST_LEVEL_VERYGROSS)
|
||||
msg += "[t_He] look[p_s()] a bit grossed out.\n"
|
||||
if(DISGUST_LEVEL_VERYGROSS to DISGUST_LEVEL_DISGUSTED)
|
||||
msg += "[t_He] look[p_s()] really grossed out.\n"
|
||||
if(DISGUST_LEVEL_DISGUSTED to INFINITY)
|
||||
msg += "[t_He] look[p_s()] extremely disgusted.\n"
|
||||
|
||||
if(blood_volume < (BLOOD_VOLUME_SAFE*blood_ratio))
|
||||
msg += "[t_He] [t_has] pale skin.\n"
|
||||
|
||||
if(bleedsuppress)
|
||||
msg += "[t_He] [t_is] bandaged with something.\n"
|
||||
else if(bleed_rate)
|
||||
if(reagents.has_reagent("heparin"))
|
||||
msg += "<b>[t_He] [t_is] bleeding uncontrollably!</b>\n"
|
||||
else
|
||||
msg += "<B>[t_He] [t_is] bleeding!</B>\n"
|
||||
|
||||
if(reagents.has_reagent("teslium"))
|
||||
msg += "[t_He] [t_is] emitting a gentle blue glow!\n"
|
||||
|
||||
if(islist(stun_absorption))
|
||||
for(var/i in stun_absorption)
|
||||
if(stun_absorption[i]["end_time"] > world.time && stun_absorption[i]["examine_message"])
|
||||
msg += "[t_He] [t_is][stun_absorption[i]["examine_message"]]\n"
|
||||
|
||||
if(drunkenness && !skipface && !appears_dead) //Drunkenness
|
||||
switch(drunkenness)
|
||||
if(11 to 21)
|
||||
msg += "[t_He] [t_is] slightly flushed.\n"
|
||||
if(21.01 to 41) //.01s are used in case drunkenness ends up to be a small decimal
|
||||
msg += "[t_He] [t_is] flushed.\n"
|
||||
if(41.01 to 51)
|
||||
msg += "[t_He] [t_is] quite flushed and [t_his] breath smells of alcohol.\n"
|
||||
if(51.01 to 61)
|
||||
msg += "[t_He] [t_is] very flushed and [t_his] movements jerky, with breath reeking of alcohol.\n"
|
||||
if(61.01 to 91)
|
||||
msg += "[t_He] look[p_s()] like a drunken mess.\n"
|
||||
if(91.01 to INFINITY)
|
||||
msg += "[t_He] [t_is] a shitfaced, slobbering wreck.\n"
|
||||
|
||||
if(reagents.has_reagent("astral"))
|
||||
msg += "[t_He] have wild, spacey eyes"
|
||||
if(mind)
|
||||
msg += " and have a strange, abnormal look to them.\n"
|
||||
else
|
||||
msg += " and don't look like they're all there.\n"
|
||||
|
||||
if(isliving(user))
|
||||
var/mob/living/L = user
|
||||
if(src != user && HAS_TRAIT(L, TRAIT_EMPATH) && !appears_dead)
|
||||
if (a_intent != INTENT_HELP)
|
||||
msg += "[t_He] seem[p_s()] to be on guard.\n"
|
||||
if (getOxyLoss() >= 10)
|
||||
msg += "[t_He] seem[p_s()] winded.\n"
|
||||
if (getToxLoss() >= 10)
|
||||
msg += "[t_He] seem[p_s()] sickly.\n"
|
||||
var/datum/component/mood/mood = src.GetComponent(/datum/component/mood)
|
||||
if(mood.sanity <= SANITY_DISTURBED)
|
||||
msg += "[t_He] seem[p_s()] distressed.\n"
|
||||
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "empath", /datum/mood_event/sad_empath, src)
|
||||
if(mood.shown_mood >= 6) //So roundstart people aren't all "happy" and that antags don't show their true happiness.
|
||||
msg += "[t_He] seem[p_s()] to have had something nice happen to them recently.\n"
|
||||
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "empathH", /datum/mood_event/happy_empath, src)
|
||||
if (HAS_TRAIT(src, TRAIT_BLIND))
|
||||
msg += "[t_He] appear[p_s()] to be staring off into space.\n"
|
||||
if (HAS_TRAIT(src, TRAIT_DEAF))
|
||||
msg += "[t_He] appear[p_s()] to not be responding to noises.\n"
|
||||
|
||||
msg += "</span>"
|
||||
|
||||
var/obj/item/organ/vocal_cords/Vc = user.getorganslot(ORGAN_SLOT_VOICE)
|
||||
if(Vc)
|
||||
if(istype(Vc, /obj/item/organ/vocal_cords/velvet))
|
||||
if(client?.prefs.lewdchem)
|
||||
msg += "<span class='velvet'><i>You feel your chords resonate looking at them.</i></span>\n"
|
||||
|
||||
|
||||
if(!appears_dead)
|
||||
if(stat == UNCONSCIOUS)
|
||||
msg += "[t_He] [t_is]n't responding to anything around [t_him] and seem[p_s()] to be asleep.\n"
|
||||
else
|
||||
if(HAS_TRAIT(src, TRAIT_DUMB))
|
||||
msg += "[t_He] [t_has] a stupid expression on [t_his] face.\n"
|
||||
if(InCritical())
|
||||
msg += "[t_He] [t_is] barely conscious.\n"
|
||||
if(getorgan(/obj/item/organ/brain))
|
||||
if(!key)
|
||||
msg += "<span class='deadsay'>[t_He] [t_is] totally catatonic. The stresses of life in deep-space must have been too much for [t_him]. Any recovery is unlikely.</span>\n"
|
||||
else if(!client)
|
||||
msg += "[t_He] [t_has] a blank, absent-minded stare and appears completely unresponsive to anything. [t_He] may snap out of it soon.\n"
|
||||
|
||||
if(digitalcamo)
|
||||
msg += "[t_He] [t_is] moving [t_his] body in an unnatural and blatantly inhuman manner.\n"
|
||||
|
||||
msg += common_trait_examine()
|
||||
|
||||
var/traitstring = get_trait_string()
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/obj/item/organ/cyberimp/eyes/hud/CIH = H.getorgan(/obj/item/organ/cyberimp/eyes/hud)
|
||||
if(istype(H.glasses, /obj/item/clothing/glasses/hud) || CIH)
|
||||
var/perpname = get_face_name(get_id_name(""))
|
||||
if(perpname)
|
||||
var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.general)
|
||||
if(R)
|
||||
msg += "<span class='deptradio'>Rank:</span> [R.fields["rank"]]<br>"
|
||||
msg += "<a href='?src=[REF(src)];hud=1;photo_front=1'>\[Front photo\]</a> "
|
||||
msg += "<a href='?src=[REF(src)];hud=1;photo_side=1'>\[Side photo\]</a><br>"
|
||||
if(istype(H.glasses, /obj/item/clothing/glasses/hud/health) || istype(CIH, /obj/item/organ/cyberimp/eyes/hud/medical))
|
||||
var/cyberimp_detect
|
||||
for(var/obj/item/organ/cyberimp/CI in internal_organs)
|
||||
if(CI.status == ORGAN_ROBOTIC && !CI.syndicate_implant)
|
||||
cyberimp_detect += "[name] is modified with a [CI.name].<br>"
|
||||
if(cyberimp_detect)
|
||||
msg += "Detected cybernetic modifications:<br>"
|
||||
msg += cyberimp_detect
|
||||
if(R)
|
||||
var/health_r = R.fields["p_stat"]
|
||||
msg += "<a href='?src=[REF(src)];hud=m;p_stat=1'>\[[health_r]\]</a>"
|
||||
health_r = R.fields["m_stat"]
|
||||
msg += "<a href='?src=[REF(src)];hud=m;m_stat=1'>\[[health_r]\]</a><br>"
|
||||
R = find_record("name", perpname, GLOB.data_core.medical)
|
||||
if(R)
|
||||
msg += "<a href='?src=[REF(src)];hud=m;evaluation=1'>\[Medical evaluation\]</a><br>"
|
||||
if(traitstring)
|
||||
msg += "<span class='info'>Detected physiological traits:<br></span>"
|
||||
msg += "<span class='info'>[traitstring]</span><br>"
|
||||
|
||||
|
||||
|
||||
if(istype(H.glasses, /obj/item/clothing/glasses/hud/security) || istype(CIH, /obj/item/organ/cyberimp/eyes/hud/security))
|
||||
if(!user.stat && user != src)
|
||||
//|| !user.canmove || user.restrained()) Fluff: Sechuds have eye-tracking technology and sets 'arrest' to people that the wearer looks and blinks at.
|
||||
var/criminal = "None"
|
||||
|
||||
R = find_record("name", perpname, GLOB.data_core.security)
|
||||
if(R)
|
||||
criminal = R.fields["criminal"]
|
||||
|
||||
msg += "<span class='deptradio'>Criminal status:</span> <a href='?src=[REF(src)];hud=s;status=1'>\[[criminal]\]</a>\n"
|
||||
msg += "<span class='deptradio'>Security record:</span> <a href='?src=[REF(src)];hud=s;view=1'>\[View\]</a> "
|
||||
msg += "<a href='?src=[REF(src)];hud=s;add_crime=1'>\[Add crime\]</a> "
|
||||
msg += "<a href='?src=[REF(src)];hud=s;view_comment=1'>\[View comment log\]</a> "
|
||||
msg += "<a href='?src=[REF(src)];hud=s;add_comment=1'>\[Add comment\]</a>\n"
|
||||
else if(isobserver(user) && traitstring)
|
||||
msg += "<span class='info'><b>Traits:</b> [traitstring]</span><br>"
|
||||
|
||||
if(print_flavor_text())
|
||||
if(get_visible_name() == "Unknown") //Are we sure we know who this is? Don't show flavor text unless we can recognize them. Prevents certain metagaming with impersonation.
|
||||
msg += "...?<br>"
|
||||
else if(skipface) //Sometimes we're not unknown, but impersonating someone in a hardsuit, let's not reveal our flavor text then either.
|
||||
msg += "...?<br>"
|
||||
else
|
||||
msg += "[print_flavor_text()]\n"
|
||||
msg += "*---------*</span>"
|
||||
|
||||
to_chat(user, msg)
|
||||
return msg
|
||||
|
||||
/mob/living/proc/status_effect_examines(pronoun_replacement) //You can include this in any mob's examine() to show the examine texts of status effects!
|
||||
var/list/dat = list()
|
||||
if(!pronoun_replacement)
|
||||
pronoun_replacement = p_they(TRUE)
|
||||
for(var/V in status_effects)
|
||||
var/datum/status_effect/E = V
|
||||
if(E.examine_text)
|
||||
var/new_text = replacetext(E.examine_text, "SUBJECTPRONOUN", pronoun_replacement)
|
||||
new_text = replacetext(new_text, "[pronoun_replacement] is", "[pronoun_replacement] [p_are()]") //To make sure something become "They are" or "She is", not "They are" and "She are"
|
||||
dat += "[new_text]\n" //dat.Join("\n") doesn't work here, for some reason
|
||||
if(dat.len)
|
||||
return dat.Join()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,869 +0,0 @@
|
||||
/mob/living/carbon/human/getarmor(def_zone, type)
|
||||
var/armorval = 0
|
||||
var/organnum = 0
|
||||
|
||||
if(def_zone)
|
||||
if(isbodypart(def_zone))
|
||||
var/obj/item/bodypart/bp = def_zone
|
||||
if(bp.body_part)
|
||||
return checkarmor(def_zone, type)
|
||||
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(def_zone))
|
||||
return checkarmor(affecting, type)
|
||||
//If a specific bodypart is targetted, check how that bodypart is protected and return the value.
|
||||
|
||||
//If you don't specify a bodypart, it checks ALL your bodyparts for protection, and averages out the values
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
armorval += checkarmor(BP, type)
|
||||
organnum++
|
||||
return (armorval/max(organnum, 1))
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/checkarmor(obj/item/bodypart/def_zone, d_type)
|
||||
if(!d_type)
|
||||
return 0
|
||||
var/protection = 0
|
||||
var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform, back, gloves, shoes, belt, s_store, glasses, ears, wear_id) //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(istype(bp, /obj/item/clothing))
|
||||
var/obj/item/clothing/C = bp
|
||||
if(C.body_parts_covered & def_zone.body_part)
|
||||
protection += C.armor.getRating(d_type)
|
||||
protection += physiology.armor.getRating(d_type)
|
||||
return protection
|
||||
|
||||
/mob/living/carbon/human/on_hit(obj/item/projectile/P)
|
||||
if(dna && dna.species)
|
||||
dna.species.on_hit(P, src)
|
||||
|
||||
|
||||
/mob/living/carbon/human/bullet_act(obj/item/projectile/P, def_zone)
|
||||
if(dna && dna.species)
|
||||
var/spec_return = dna.species.bullet_act(P, src)
|
||||
if(spec_return)
|
||||
return spec_return
|
||||
|
||||
if(mind)
|
||||
if(mind.martial_art && !incapacitated(FALSE, TRUE) && mind.martial_art.can_use(src) && mind.martial_art.deflection_chance) //Some martial arts users can deflect projectiles!
|
||||
if(prob(mind.martial_art.deflection_chance))
|
||||
if(!lying && dna && !dna.check_mutation(HULK)) //But only if they're not lying down, and hulks can't do it
|
||||
if(mind.martial_art.deflection_chance >= 100) //if they can NEVER be hit, lets clue sec in ;)
|
||||
visible_message("<span class='danger'>[src] deflects the projectile; [p_they()] can't be hit with ranged weapons!</span>", "<span class='userdanger'>You deflect the projectile!</span>")
|
||||
else
|
||||
visible_message("<span class='danger'>[src] deflects the projectile!</span>", "<span class='userdanger'>You deflect the projectile!</span>")
|
||||
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, 1)
|
||||
if(!mind.martial_art.reroute_deflection)
|
||||
return FALSE
|
||||
else
|
||||
P.firer = src
|
||||
P.setAngle(rand(0, 360))//SHING
|
||||
return FALSE
|
||||
|
||||
if(!(P.original == src && P.firer == src)) //can't block or reflect when shooting yourself
|
||||
if(P.is_reflectable)
|
||||
if(check_reflect(def_zone)) // Checks if you've passed a reflection% check
|
||||
visible_message("<span class='danger'>The [P.name] gets reflected by [src]!</span>", \
|
||||
"<span class='userdanger'>The [P.name] gets reflected by [src]!</span>")
|
||||
// Find a turf near or on the original location to bounce to
|
||||
if(P.starting)
|
||||
var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
|
||||
var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
|
||||
var/turf/curloc = get_turf(src)
|
||||
|
||||
// redirect the projectile
|
||||
P.original = locate(new_x, new_y, P.z)
|
||||
P.starting = curloc
|
||||
P.firer = src
|
||||
P.yo = new_y - curloc.y
|
||||
P.xo = new_x - curloc.x
|
||||
var/new_angle_s = P.Angle + rand(120,240)
|
||||
while(new_angle_s > 180) // Translate to regular projectile degrees
|
||||
new_angle_s -= 360
|
||||
P.setAngle(new_angle_s)
|
||||
|
||||
return -1 // complete projectile permutation
|
||||
|
||||
if(check_shields(P, P.damage, "the [P.name]", PROJECTILE_ATTACK, P.armour_penetration))
|
||||
P.on_hit(src, 100, def_zone)
|
||||
return 2
|
||||
|
||||
return (..(P , def_zone))
|
||||
|
||||
/mob/living/carbon/human/proc/check_reflect(def_zone) //Reflection checks for anything in your l_hand, r_hand, or wear_suit based on the reflection chance of the object
|
||||
if(wear_suit)
|
||||
if(wear_suit.IsReflect(def_zone) == 1)
|
||||
return 1
|
||||
for(var/obj/item/I in held_items)
|
||||
if(I.IsReflect(def_zone) == 1)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/human/proc/check_shields(atom/AM, var/damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0)
|
||||
var/block_chance_modifier = round(damage / -3)
|
||||
|
||||
for(var/obj/item/I in held_items)
|
||||
if(!istype(I, /obj/item/clothing))
|
||||
var/final_block_chance = I.block_chance - (CLAMP((armour_penetration-I.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
|
||||
if(I.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
|
||||
return 1
|
||||
if(wear_suit)
|
||||
var/final_block_chance = wear_suit.block_chance - (CLAMP((armour_penetration-wear_suit.armour_penetration)/2,0,100)) + block_chance_modifier
|
||||
if(wear_suit.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
|
||||
return 1
|
||||
if(w_uniform)
|
||||
var/final_block_chance = w_uniform.block_chance - (CLAMP((armour_penetration-w_uniform.armour_penetration)/2,0,100)) + block_chance_modifier
|
||||
if(w_uniform.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/human/proc/check_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))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/human/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE)
|
||||
if(dna && dna.species)
|
||||
var/spec_return = dna.species.spec_hitby(AM, src)
|
||||
if(spec_return)
|
||||
return spec_return
|
||||
var/obj/item/I
|
||||
var/throwpower = 30
|
||||
if(istype(AM, /obj/item))
|
||||
I = AM
|
||||
throwpower = I.throwforce
|
||||
if(I.thrownby == src) //No throwing stuff at yourself to trigger hit reactions
|
||||
return ..()
|
||||
if(check_shields(AM, throwpower, "\the [AM.name]", THROWN_PROJECTILE_ATTACK))
|
||||
hitpush = FALSE
|
||||
skipcatch = TRUE
|
||||
blocked = TRUE
|
||||
else if(I)
|
||||
if(I.throw_speed >= EMBED_THROWSPEED_THRESHOLD)
|
||||
if(can_embed(I))
|
||||
if(prob(I.embedding.embed_chance) && !HAS_TRAIT(src, TRAIT_PIERCEIMMUNE))
|
||||
throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
|
||||
var/obj/item/bodypart/L = pick(bodyparts)
|
||||
L.embedded_objects |= I
|
||||
I.add_mob_blood(src)//it embedded itself in you, of course it's bloody!
|
||||
I.forceMove(src)
|
||||
L.receive_damage(I.w_class*I.embedding.embedded_impact_pain_multiplier)
|
||||
visible_message("<span class='danger'>[I] embeds itself in [src]'s [L.name]!</span>","<span class='userdanger'>[I] embeds itself in your [L.name]!</span>")
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
|
||||
hitpush = FALSE
|
||||
skipcatch = TRUE //can't catch the now embedded item
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/grabbedby(mob/living/carbon/user, supress_message = 0)
|
||||
if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && (HAS_TRAIT(src, TRAIT_FAT)) && ismonkey(pulling))
|
||||
devour_mob(pulling)
|
||||
else
|
||||
..()
|
||||
|
||||
/mob/living/carbon/human/grippedby(mob/living/user, instant = FALSE)
|
||||
if(w_uniform)
|
||||
w_uniform.add_fingerprint(user)
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/carbon/human/attacked_by(obj/item/I, mob/living/user)
|
||||
if(!I || !user)
|
||||
return 0
|
||||
|
||||
var/obj/item/bodypart/affecting
|
||||
if(user == src)
|
||||
affecting = get_bodypart(check_zone(user.zone_selected)) //stabbing yourself always hits the right target
|
||||
else
|
||||
affecting = get_bodypart(ran_zone(user.zone_selected))
|
||||
var/target_area = parse_zone(check_zone(user.zone_selected)) //our intended target
|
||||
|
||||
SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting)
|
||||
|
||||
SSblackbox.record_feedback("nested tally", "item_used_for_combat", 1, list("[I.force]", "[I.type]"))
|
||||
SSblackbox.record_feedback("tally", "zone_targeted", 1, target_area)
|
||||
|
||||
// the attacked_by code varies among species
|
||||
return dna.species.spec_attacked_by(I, user, affecting, a_intent, src)
|
||||
|
||||
|
||||
/mob/living/carbon/human/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
|
||||
if(user.a_intent == INTENT_HARM)
|
||||
var/hulk_verb = pick("smash","pummel")
|
||||
if(check_shields(user, 15, "the [hulk_verb]ing"))
|
||||
return
|
||||
..(user, 1)
|
||||
playsound(loc, user.dna.species.attack_sound, 25, 1, -1)
|
||||
var/message = "[user] has [hulk_verb]ed [src]!"
|
||||
visible_message("<span class='danger'>[message]</span>", \
|
||||
"<span class='userdanger'>[message]</span>")
|
||||
adjustBruteLoss(15)
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/attack_hand(mob/user)
|
||||
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)
|
||||
|
||||
/mob/living/carbon/human/attack_paw(mob/living/carbon/monkey/M)
|
||||
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)
|
||||
affecting = get_bodypart(BODY_ZONE_CHEST)
|
||||
if(M.a_intent == INTENT_HELP)
|
||||
..() //shaking
|
||||
return 0
|
||||
|
||||
if(M.a_intent == INTENT_DISARM) //Always drop item in hand, if no item, get stunned instead.
|
||||
var/obj/item/I = get_active_held_item()
|
||||
if(I && dropItemToGround(I))
|
||||
playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1)
|
||||
visible_message("<span class='danger'>[M] disarmed [src]!</span>", \
|
||||
"<span class='userdanger'>[M] disarmed [src]!</span>")
|
||||
else if(!M.client || prob(5)) // only natural monkeys get to stun reliably, (they only do it occasionaly)
|
||||
playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
|
||||
Knockdown(100)
|
||||
log_combat(M, src, "tackled")
|
||||
visible_message("<span class='danger'>[M] has tackled down [src]!</span>", \
|
||||
"<span class='userdanger'>[M] has tackled down [src]!</span>")
|
||||
|
||||
if(M.limb_destroyer)
|
||||
dismembering_strike(M, affecting.body_zone)
|
||||
|
||||
if(can_inject(M, 1, affecting))//Thick suits can stop monkey bites.
|
||||
if(..()) //successful monkey bite, this handles disease contraction.
|
||||
var/damage = rand(1, 3)
|
||||
if(check_shields(M, damage, "the [M.name]"))
|
||||
return 0
|
||||
if(stat != DEAD)
|
||||
apply_damage(damage, BRUTE, affecting, run_armor_check(affecting, "melee"))
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/attack_alien(mob/living/carbon/alien/humanoid/M)
|
||||
if(check_shields(M, 0, "the M.name"))
|
||||
visible_message("<span class='danger'>[M] attempted to touch [src]!</span>")
|
||||
return 0
|
||||
|
||||
if(..())
|
||||
if(M.a_intent == INTENT_HARM)
|
||||
if (w_uniform)
|
||||
w_uniform.add_fingerprint(M)
|
||||
var/damage = prob(90) ? 20 : 0
|
||||
if(!damage)
|
||||
playsound(loc, 'sound/weapons/slashmiss.ogg', 50, 1, -1)
|
||||
visible_message("<span class='danger'>[M] has lunged at [src]!</span>", \
|
||||
"<span class='userdanger'>[M] has lunged at [src]!</span>")
|
||||
return 0
|
||||
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
|
||||
if(!affecting)
|
||||
affecting = get_bodypart(BODY_ZONE_CHEST)
|
||||
var/armor_block = run_armor_check(affecting, "melee", null, null,10)
|
||||
|
||||
playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
|
||||
visible_message("<span class='danger'>[M] has slashed at [src]!</span>", \
|
||||
"<span class='userdanger'>[M] has slashed at [src]!</span>")
|
||||
log_combat(M, src, "attacked")
|
||||
if(!dismembering_strike(M, M.zone_selected)) //Dismemberment successful
|
||||
return 1
|
||||
apply_damage(damage, BRUTE, affecting, armor_block)
|
||||
|
||||
if(M.a_intent == INTENT_DISARM) //Always drop item in hand, if no item, get stun instead.
|
||||
var/obj/item/I = get_active_held_item()
|
||||
if(I && dropItemToGround(I))
|
||||
playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1)
|
||||
visible_message("<span class='danger'>[M] disarmed [src]!</span>", \
|
||||
"<span class='userdanger'>[M] disarmed [src]!</span>")
|
||||
else
|
||||
playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
|
||||
if(!lying) //CITADEL EDIT
|
||||
Knockdown(100, TRUE, FALSE, 30, 25)
|
||||
else
|
||||
Knockdown(100)
|
||||
log_combat(M, src, "tackled")
|
||||
visible_message("<span class='danger'>[M] has tackled down [src]!</span>", \
|
||||
"<span class='userdanger'>[M] has tackled down [src]!</span>")
|
||||
|
||||
|
||||
/mob/living/carbon/human/attack_larva(mob/living/carbon/alien/larva/L)
|
||||
|
||||
if(..()) //successful larva bite.
|
||||
var/damage = rand(1, 3)
|
||||
if(check_shields(L, damage, "the [L.name]"))
|
||||
return 0
|
||||
if(stat != DEAD)
|
||||
L.amount_grown = min(L.amount_grown + damage, L.max_grown)
|
||||
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.zone_selected))
|
||||
if(!affecting)
|
||||
affecting = get_bodypart(BODY_ZONE_CHEST)
|
||||
var/armor_block = run_armor_check(affecting, "melee")
|
||||
apply_damage(damage, BRUTE, affecting, armor_block)
|
||||
|
||||
|
||||
/mob/living/carbon/human/attack_animal(mob/living/simple_animal/M)
|
||||
. = ..()
|
||||
if(.)
|
||||
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
|
||||
if(check_shields(M, damage, "the [M.name]", MELEE_ATTACK, M.armour_penetration))
|
||||
return FALSE
|
||||
var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
|
||||
if(!dam_zone) //Dismemberment successful
|
||||
return TRUE
|
||||
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
|
||||
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)
|
||||
|
||||
|
||||
/mob/living/carbon/human/attack_slime(mob/living/simple_animal/slime/M)
|
||||
if(..()) //successful slime attack
|
||||
var/damage = rand(5, 25)
|
||||
if(M.is_adult)
|
||||
damage = rand(10, 35)
|
||||
|
||||
if(check_shields(M, damage, "the [M.name]"))
|
||||
return 0
|
||||
|
||||
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
|
||||
return 1
|
||||
|
||||
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
|
||||
if(!affecting)
|
||||
affecting = get_bodypart(BODY_ZONE_CHEST)
|
||||
var/armor_block = run_armor_check(affecting, "melee")
|
||||
apply_damage(damage, BRUTE, affecting, armor_block)
|
||||
|
||||
/mob/living/carbon/human/mech_melee_attack(obj/mecha/M)
|
||||
|
||||
if(M.occupant.a_intent == INTENT_HARM)
|
||||
M.do_attack_animation(src)
|
||||
if(M.damtype == "brute")
|
||||
step_away(src,M,15)
|
||||
var/obj/item/bodypart/temp = get_bodypart(pick(BODY_ZONE_CHEST, BODY_ZONE_CHEST, BODY_ZONE_CHEST, BODY_ZONE_HEAD))
|
||||
if(temp)
|
||||
var/update = 0
|
||||
var/dmg = rand(M.force/2, M.force)
|
||||
var/atom/throw_target = get_edge_target_turf(src, M.dir)
|
||||
switch(M.damtype)
|
||||
if("brute")
|
||||
if(M.force > 35) // durand and other heavy mechas
|
||||
Knockdown(50)
|
||||
src.throw_at(throw_target, rand(1,5), 7)
|
||||
else if(M.force >= 20 && !IsKnockdown()) // lightweight mechas like gygax
|
||||
Knockdown(30)
|
||||
src.throw_at(throw_target, rand(1,3), 7)
|
||||
update |= temp.receive_damage(dmg, 0)
|
||||
playsound(src, 'sound/weapons/punch4.ogg', 50, 1)
|
||||
if("fire")
|
||||
update |= temp.receive_damage(0, dmg)
|
||||
playsound(src, 'sound/items/welder.ogg', 50, 1)
|
||||
if("tox")
|
||||
M.mech_toxin_damage(src)
|
||||
else
|
||||
return
|
||||
if(update)
|
||||
update_damage_overlays()
|
||||
updatehealth()
|
||||
|
||||
visible_message("<span class='danger'>[M.name] has hit [src]!</span>", \
|
||||
"<span class='userdanger'>[M.name] has hit [src]!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
log_combat(M.occupant, src, "attacked", M, "(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])")
|
||||
|
||||
else
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/carbon/human/ex_act(severity, target, origin)
|
||||
if(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src))
|
||||
return
|
||||
..()
|
||||
if (!severity)
|
||||
return
|
||||
var/b_loss = 0
|
||||
var/f_loss = 0
|
||||
var/bomb_armor = getarmor(null, "bomb")
|
||||
|
||||
switch (severity)
|
||||
if (1)
|
||||
if(prob(bomb_armor))
|
||||
b_loss = 500
|
||||
var/atom/throw_target = get_edge_target_turf(src, get_dir(src, get_step_away(src, src)))
|
||||
throw_at(throw_target, 200, 4)
|
||||
damage_clothes(400 - bomb_armor, BRUTE, "bomb")
|
||||
else
|
||||
for(var/I in contents)
|
||||
var/atom/A = I
|
||||
A.ex_act(severity)
|
||||
gib()
|
||||
return
|
||||
|
||||
if (2)
|
||||
b_loss = 60
|
||||
f_loss = 60
|
||||
if(bomb_armor)
|
||||
b_loss = 30*(2 - round(bomb_armor*0.01, 0.05))
|
||||
f_loss = b_loss
|
||||
damage_clothes(200 - bomb_armor, BRUTE, "bomb")
|
||||
if (!istype(ears, /obj/item/clothing/ears/earmuffs))
|
||||
adjustEarDamage(30, 120)
|
||||
if (prob(max(70 - (bomb_armor * 0.5), 0)))
|
||||
Unconscious(200)
|
||||
|
||||
if(3)
|
||||
b_loss = 30
|
||||
if(bomb_armor)
|
||||
b_loss = 15*(2 - round(bomb_armor*0.01, 0.05))
|
||||
damage_clothes(max(50 - bomb_armor, 0), BRUTE, "bomb")
|
||||
if (!istype(ears, /obj/item/clothing/ears/earmuffs))
|
||||
adjustEarDamage(15,60)
|
||||
if (prob(max(50 - (bomb_armor * 0.5), 0)))
|
||||
Unconscious(160)
|
||||
|
||||
take_overall_damage(b_loss,f_loss)
|
||||
|
||||
//attempt to dismember bodyparts
|
||||
if(severity <= 2 || !bomb_armor)
|
||||
var/max_limb_loss = round(4/severity) //so you don't lose four limbs at severity 3.
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
if(prob(50/severity) && !prob(getarmor(BP, "bomb")) && BP.body_zone != BODY_ZONE_HEAD && BP.body_zone != BODY_ZONE_CHEST)
|
||||
BP.brute_dam = BP.max_damage
|
||||
BP.dismember()
|
||||
max_limb_loss--
|
||||
if(!max_limb_loss)
|
||||
break
|
||||
|
||||
|
||||
/mob/living/carbon/human/blob_act(obj/structure/blob/B)
|
||||
if(stat == DEAD)
|
||||
return
|
||||
show_message("<span class='userdanger'>The blob attacks you!</span>")
|
||||
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))
|
||||
apply_damage(5, BRUTE, affecting, run_armor_check(affecting, "melee"))
|
||||
|
||||
|
||||
//Added a safety check in case you want to shock a human mob directly through electrocute_act.
|
||||
/mob/living/carbon/human/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
|
||||
if(tesla_shock)
|
||||
var/total_coeff = 1
|
||||
if(gloves)
|
||||
var/obj/item/clothing/gloves/G = gloves
|
||||
if(G.siemens_coefficient <= 0)
|
||||
total_coeff -= 0.5
|
||||
if(wear_suit)
|
||||
var/obj/item/clothing/suit/S = wear_suit
|
||||
if(S.siemens_coefficient <= 0)
|
||||
total_coeff -= 0.95
|
||||
else if(S.siemens_coefficient == (-1))
|
||||
total_coeff -= 1
|
||||
siemens_coeff = total_coeff
|
||||
if(flags_1 & TESLA_IGNORE_1)
|
||||
siemens_coeff = 0
|
||||
else if(!safety)
|
||||
var/gloves_siemens_coeff = 1
|
||||
if(gloves)
|
||||
var/obj/item/clothing/gloves/G = gloves
|
||||
gloves_siemens_coeff = G.siemens_coefficient
|
||||
siemens_coeff = gloves_siemens_coeff
|
||||
if(undergoing_cardiac_arrest() && !illusion)
|
||||
if(shock_damage * siemens_coeff >= 1 && prob(25))
|
||||
var/obj/item/organ/heart/heart = getorganslot(ORGAN_SLOT_HEART)
|
||||
heart.beating = TRUE
|
||||
if(stat == CONSCIOUS)
|
||||
to_chat(src, "<span class='notice'>You feel your heart beating again!</span>")
|
||||
siemens_coeff *= physiology.siemens_coeff
|
||||
. = ..(shock_damage,source,siemens_coeff,safety,override,tesla_shock, illusion, stun)
|
||||
if(.)
|
||||
electrocution_animation(40)
|
||||
|
||||
|
||||
/mob/living/carbon/human/emp_act(severity)
|
||||
. = ..()
|
||||
if(. & EMP_PROTECT_CONTENTS)
|
||||
return
|
||||
var/informed = FALSE
|
||||
for(var/obj/item/bodypart/L in src.bodyparts)
|
||||
if(L.status == BODYPART_ROBOTIC)
|
||||
if(!informed)
|
||||
to_chat(src, "<span class='userdanger'>You feel a sharp pain as your robotic limbs overload.</span>")
|
||||
informed = TRUE
|
||||
switch(severity)
|
||||
if(1)
|
||||
L.receive_damage(0,10)
|
||||
Stun(200)
|
||||
if(2)
|
||||
L.receive_damage(0,5)
|
||||
Stun(100)
|
||||
|
||||
/mob/living/carbon/human/acid_act(acidpwr, acid_volume, bodyzone_hit)
|
||||
var/list/damaged = list()
|
||||
var/list/inventory_items_to_kill = list()
|
||||
var/acidity = acidpwr * min(acid_volume*0.005, 0.1)
|
||||
//HEAD//
|
||||
if(!bodyzone_hit || bodyzone_hit == BODY_ZONE_HEAD) //only if we didn't specify a zone or if that zone is the head.
|
||||
var/obj/item/clothing/head_clothes = null
|
||||
if(glasses)
|
||||
head_clothes = glasses
|
||||
if(wear_mask)
|
||||
head_clothes = wear_mask
|
||||
if(wear_neck)
|
||||
head_clothes = wear_neck
|
||||
if(head)
|
||||
head_clothes = head
|
||||
if(head_clothes)
|
||||
if(!(head_clothes.resistance_flags & UNACIDABLE))
|
||||
head_clothes.acid_act(acidpwr, acid_volume)
|
||||
update_inv_glasses()
|
||||
update_inv_wear_mask()
|
||||
update_inv_neck()
|
||||
update_inv_head()
|
||||
else
|
||||
to_chat(src, "<span class='notice'>Your [head_clothes.name] protects your head and face from the acid!</span>")
|
||||
else
|
||||
. = get_bodypart(BODY_ZONE_HEAD)
|
||||
if(.)
|
||||
damaged += .
|
||||
if(ears)
|
||||
inventory_items_to_kill += ears
|
||||
|
||||
//CHEST//
|
||||
if(!bodyzone_hit || bodyzone_hit == BODY_ZONE_CHEST)
|
||||
var/obj/item/clothing/chest_clothes = null
|
||||
if(w_uniform)
|
||||
chest_clothes = w_uniform
|
||||
if(wear_suit)
|
||||
chest_clothes = wear_suit
|
||||
if(chest_clothes)
|
||||
if(!(chest_clothes.resistance_flags & UNACIDABLE))
|
||||
chest_clothes.acid_act(acidpwr, acid_volume)
|
||||
update_inv_w_uniform()
|
||||
update_inv_wear_suit()
|
||||
else
|
||||
to_chat(src, "<span class='notice'>Your [chest_clothes.name] protects your body from the acid!</span>")
|
||||
else
|
||||
. = get_bodypart(BODY_ZONE_CHEST)
|
||||
if(.)
|
||||
damaged += .
|
||||
if(wear_id)
|
||||
inventory_items_to_kill += wear_id
|
||||
if(r_store)
|
||||
inventory_items_to_kill += r_store
|
||||
if(l_store)
|
||||
inventory_items_to_kill += l_store
|
||||
if(s_store)
|
||||
inventory_items_to_kill += s_store
|
||||
|
||||
|
||||
//ARMS & HANDS//
|
||||
if(!bodyzone_hit || bodyzone_hit == BODY_ZONE_L_ARM || bodyzone_hit == BODY_ZONE_R_ARM)
|
||||
var/obj/item/clothing/arm_clothes = null
|
||||
if(gloves)
|
||||
arm_clothes = gloves
|
||||
if(w_uniform && ((w_uniform.body_parts_covered & HANDS) || (w_uniform.body_parts_covered & ARMS)))
|
||||
arm_clothes = w_uniform
|
||||
if(wear_suit && ((wear_suit.body_parts_covered & HANDS) || (wear_suit.body_parts_covered & ARMS)))
|
||||
arm_clothes = wear_suit
|
||||
|
||||
if(arm_clothes)
|
||||
if(!(arm_clothes.resistance_flags & UNACIDABLE))
|
||||
arm_clothes.acid_act(acidpwr, acid_volume)
|
||||
update_inv_gloves()
|
||||
update_inv_w_uniform()
|
||||
update_inv_wear_suit()
|
||||
else
|
||||
to_chat(src, "<span class='notice'>Your [arm_clothes.name] protects your arms and hands from the acid!</span>")
|
||||
else
|
||||
. = get_bodypart(BODY_ZONE_R_ARM)
|
||||
if(.)
|
||||
damaged += .
|
||||
. = get_bodypart(BODY_ZONE_L_ARM)
|
||||
if(.)
|
||||
damaged += .
|
||||
|
||||
|
||||
//LEGS & FEET//
|
||||
if(!bodyzone_hit || bodyzone_hit == BODY_ZONE_L_LEG || bodyzone_hit == BODY_ZONE_R_LEG || bodyzone_hit == "feet")
|
||||
var/obj/item/clothing/leg_clothes = null
|
||||
if(shoes)
|
||||
leg_clothes = shoes
|
||||
if(w_uniform && ((w_uniform.body_parts_covered & FEET) || (bodyzone_hit != "feet" && (w_uniform.body_parts_covered & LEGS))))
|
||||
leg_clothes = w_uniform
|
||||
if(wear_suit && ((wear_suit.body_parts_covered & FEET) || (bodyzone_hit != "feet" && (wear_suit.body_parts_covered & LEGS))))
|
||||
leg_clothes = wear_suit
|
||||
if(leg_clothes)
|
||||
if(!(leg_clothes.resistance_flags & UNACIDABLE))
|
||||
leg_clothes.acid_act(acidpwr, acid_volume)
|
||||
update_inv_shoes()
|
||||
update_inv_w_uniform()
|
||||
update_inv_wear_suit()
|
||||
else
|
||||
to_chat(src, "<span class='notice'>Your [leg_clothes.name] protects your legs and feet from the acid!</span>")
|
||||
else
|
||||
. = get_bodypart(BODY_ZONE_R_LEG)
|
||||
if(.)
|
||||
damaged += .
|
||||
. = get_bodypart(BODY_ZONE_L_LEG)
|
||||
if(.)
|
||||
damaged += .
|
||||
|
||||
|
||||
//DAMAGE//
|
||||
for(var/obj/item/bodypart/affecting in damaged)
|
||||
affecting.receive_damage(acidity, 2*acidity)
|
||||
|
||||
if(affecting.name == BODY_ZONE_HEAD)
|
||||
if(prob(min(acidpwr*acid_volume/10, 90))) //Applies disfigurement
|
||||
affecting.receive_damage(acidity, 2*acidity)
|
||||
emote("scream")
|
||||
facial_hair_style = "Shaved"
|
||||
hair_style = "Bald"
|
||||
update_hair()
|
||||
ADD_TRAIT(src, TRAIT_DISFIGURED, TRAIT_GENERIC)
|
||||
|
||||
update_damage_overlays()
|
||||
|
||||
//MELTING INVENTORY ITEMS//
|
||||
//these items are all outside of armour visually, so melt regardless.
|
||||
if(!bodyzone_hit)
|
||||
if(back)
|
||||
inventory_items_to_kill += back
|
||||
if(belt)
|
||||
inventory_items_to_kill += belt
|
||||
|
||||
inventory_items_to_kill += held_items
|
||||
|
||||
for(var/obj/item/I in inventory_items_to_kill)
|
||||
I.acid_act(acidpwr, acid_volume)
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/singularity_act()
|
||||
var/gain = 20
|
||||
if(mind)
|
||||
if((mind.assigned_role == "Station Engineer") || (mind.assigned_role == "Chief Engineer") )
|
||||
gain = 100
|
||||
if(mind.assigned_role == "Clown")
|
||||
gain = rand(-300, 300)
|
||||
investigate_log("([key_name(src)]) has been consumed by the singularity.", INVESTIGATE_SINGULO) //Oh that's where the clown ended up!
|
||||
gib()
|
||||
return(gain)
|
||||
|
||||
/mob/living/carbon/human/help_shake_act(mob/living/carbon/M)
|
||||
if(!istype(M))
|
||||
return
|
||||
|
||||
if(health >= 0)
|
||||
if(src == M)
|
||||
var/to_send = ""
|
||||
visible_message("[src] examines [p_them()]self.", \
|
||||
"<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/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
|
||||
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/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"
|
||||
|
||||
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(getStaminaLoss())
|
||||
if(getStaminaLoss() > 30)
|
||||
to_send += "<span class='info'>You're completely exhausted.</span>\n"
|
||||
else
|
||||
to_send += "<span class='info'>You feel fatigued.</span>\n"
|
||||
if(HAS_TRAIT(src, TRAIT_SELF_AWARE))
|
||||
if(toxloss)
|
||||
if(toxloss > 10)
|
||||
to_send += "<span class='danger'>You feel sick.</span>\n"
|
||||
else if(toxloss > 20)
|
||||
to_send += "<span class='danger'>You feel nauseated.</span>\n"
|
||||
else if(toxloss > 40)
|
||||
to_send += "<span class='danger'>You feel very unwell!</span>\n"
|
||||
if(oxyloss)
|
||||
if(oxyloss > 10)
|
||||
to_send += "<span class='danger'>You feel lightheaded.</span>\n"
|
||||
else if(oxyloss > 20)
|
||||
to_send += "<span class='danger'>Your thinking is clouded and distant.</span>\n"
|
||||
else if(oxyloss > 30)
|
||||
to_send += "<span class='danger'>You're choking!</span>\n"
|
||||
|
||||
switch(nutrition)
|
||||
if(NUTRITION_LEVEL_FULL to INFINITY)
|
||||
to_send += "<span class='info'>You're completely stuffed!</span>\n"
|
||||
if(NUTRITION_LEVEL_WELL_FED to NUTRITION_LEVEL_FULL)
|
||||
to_send += "<span class='info'>You're well fed!</span>\n"
|
||||
if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED)
|
||||
to_send += "<span class='info'>You're not hungry.</span>\n"
|
||||
if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED)
|
||||
to_send += "<span class='info'>You could use a bite to eat.</span>\n"
|
||||
if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
|
||||
to_send += "<span class='info'>You feel quite hungry.</span>\n"
|
||||
if(0 to NUTRITION_LEVEL_STARVING)
|
||||
to_send += "<span class='danger'>You're starving!</span>\n"
|
||||
|
||||
|
||||
//TODO: Convert these messages into vague messages, thereby encouraging actual dignosis.
|
||||
//Compiles then shows the list of damaged organs and broken organs
|
||||
var/list/broken = list()
|
||||
var/list/damaged = list()
|
||||
var/broken_message
|
||||
var/damaged_message
|
||||
var/broken_plural
|
||||
var/damaged_plural
|
||||
//Sets organs into their proper list
|
||||
for(var/O in internal_organs)
|
||||
var/obj/item/organ/organ = O
|
||||
if(organ.organ_flags & ORGAN_FAILING)
|
||||
if(broken.len)
|
||||
broken += ", "
|
||||
broken += organ.name
|
||||
else if(organ.damage > organ.low_threshold)
|
||||
if(damaged.len)
|
||||
damaged += ", "
|
||||
damaged += organ.name
|
||||
//Checks to enforce proper grammar, inserts words as necessary into the list
|
||||
if(broken.len)
|
||||
if(broken.len > 1)
|
||||
broken.Insert(broken.len, "and ")
|
||||
broken_plural = TRUE
|
||||
else
|
||||
var/holder = broken[1] //our one and only element
|
||||
if(holder[length(holder)] == "s")
|
||||
broken_plural = TRUE
|
||||
//Put the items in that list into a string of text
|
||||
for(var/B in broken)
|
||||
broken_message += B
|
||||
to_chat(src, "<span class='warning'> Your [broken_message] [broken_plural ? "are" : "is"] non-functional!</span>")
|
||||
if(damaged.len)
|
||||
if(damaged.len > 1)
|
||||
damaged.Insert(damaged.len, "and ")
|
||||
damaged_plural = TRUE
|
||||
else
|
||||
var/holder = damaged[1]
|
||||
if(holder[length(holder)] == "s")
|
||||
damaged_plural = TRUE
|
||||
for(var/D in damaged)
|
||||
damaged_message += D
|
||||
to_chat(src, "<span class='info'>Your [damaged_message] [damaged_plural ? "are" : "is"] hurt.</span>")
|
||||
|
||||
if(roundstart_quirks.len)
|
||||
to_send += "<span class='notice'>You have these quirks: [get_trait_string()].</span>\n"
|
||||
|
||||
to_chat(src, to_send)
|
||||
else
|
||||
if(wear_suit)
|
||||
wear_suit.add_fingerprint(M)
|
||||
else if(w_uniform)
|
||||
w_uniform.add_fingerprint(M)
|
||||
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/carbon/human/damage_clothes(damage_amount, damage_type = BRUTE, damage_flag = 0, def_zone)
|
||||
if(damage_type != BRUTE && damage_type != BURN)
|
||||
return
|
||||
damage_amount *= 0.5 //0.5 multiplier for balance reason, we don't want clothes to be too easily destroyed
|
||||
var/list/torn_items = list()
|
||||
|
||||
//HEAD//
|
||||
if(!def_zone || def_zone == BODY_ZONE_HEAD)
|
||||
var/obj/item/clothing/head_clothes = null
|
||||
if(glasses)
|
||||
head_clothes = glasses
|
||||
if(wear_mask)
|
||||
head_clothes = wear_mask
|
||||
if(wear_neck)
|
||||
head_clothes = wear_neck
|
||||
if(head)
|
||||
head_clothes = head
|
||||
if(head_clothes)
|
||||
torn_items += head_clothes
|
||||
else if(ears)
|
||||
torn_items += ears
|
||||
|
||||
//CHEST//
|
||||
if(!def_zone || def_zone == BODY_ZONE_CHEST)
|
||||
var/obj/item/clothing/chest_clothes = null
|
||||
if(w_uniform)
|
||||
chest_clothes = w_uniform
|
||||
if(wear_suit)
|
||||
chest_clothes = wear_suit
|
||||
if(chest_clothes)
|
||||
torn_items += chest_clothes
|
||||
|
||||
//ARMS & HANDS//
|
||||
if(!def_zone || def_zone == BODY_ZONE_L_ARM || def_zone == BODY_ZONE_R_ARM)
|
||||
var/obj/item/clothing/arm_clothes = null
|
||||
if(gloves)
|
||||
arm_clothes = gloves
|
||||
if(w_uniform && ((w_uniform.body_parts_covered & HANDS) || (w_uniform.body_parts_covered & ARMS)))
|
||||
arm_clothes = w_uniform
|
||||
if(wear_suit && ((wear_suit.body_parts_covered & HANDS) || (wear_suit.body_parts_covered & ARMS)))
|
||||
arm_clothes = wear_suit
|
||||
if(arm_clothes)
|
||||
torn_items |= arm_clothes
|
||||
|
||||
//LEGS & FEET//
|
||||
if(!def_zone || def_zone == BODY_ZONE_L_LEG || def_zone == BODY_ZONE_R_LEG)
|
||||
var/obj/item/clothing/leg_clothes = null
|
||||
if(shoes)
|
||||
leg_clothes = shoes
|
||||
if(w_uniform && ((w_uniform.body_parts_covered & FEET) || (w_uniform.body_parts_covered & LEGS)))
|
||||
leg_clothes = w_uniform
|
||||
if(wear_suit && ((wear_suit.body_parts_covered & FEET) || (wear_suit.body_parts_covered & LEGS)))
|
||||
leg_clothes = wear_suit
|
||||
if(leg_clothes)
|
||||
torn_items |= leg_clothes
|
||||
|
||||
for(var/obj/item/I in torn_items)
|
||||
I.take_damage(damage_amount, damage_type, damage_flag, 0)
|
||||
@@ -1,72 +0,0 @@
|
||||
/mob/living/carbon/human
|
||||
hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD,IMPLOYAL_HUD,IMPCHEM_HUD,IMPTRACK_HUD, NANITE_HUD, DIAG_NANITE_FULL_HUD,ANTAG_HUD,GLAND_HUD,SENTIENT_DISEASE_HUD,RAD_HUD)
|
||||
hud_type = /datum/hud/human
|
||||
possible_a_intents = list(INTENT_HELP, INTENT_DISARM, INTENT_GRAB, INTENT_HARM)
|
||||
pressure_resistance = 25
|
||||
can_buckle = TRUE
|
||||
buckle_lying = FALSE
|
||||
mob_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
|
||||
//Hair colour and style
|
||||
var/hair_color = "000"
|
||||
var/hair_style = "Bald"
|
||||
|
||||
//Facial hair colour and style
|
||||
var/facial_hair_color = "000"
|
||||
var/facial_hair_style = "Shaved"
|
||||
|
||||
//Eye colour
|
||||
var/eye_color = "000"
|
||||
|
||||
var/horn_color = "85615a" //specific horn colors, because why not?
|
||||
|
||||
var/wing_color = "fff" //wings too
|
||||
|
||||
var/skin_tone = "caucasian1" //Skin tone
|
||||
|
||||
var/lip_style = null //no lipstick by default- arguably misleading, as it could be used for general makeup
|
||||
var/lip_color = "white"
|
||||
|
||||
var/age = 30 //Player's age
|
||||
|
||||
var/underwear = "Nude" //Which underwear the player wants
|
||||
var/undie_color = "FFFFFF"
|
||||
var/undershirt = "Nude" //Which undershirt the player wants
|
||||
var/shirt_color = "FFFFFF"
|
||||
var/socks = "Nude" //Which socks the player wants
|
||||
var/socks_color = "FFFFFF"
|
||||
var/backbag = DBACKPACK //Which backpack type the player has chosen.
|
||||
var/jumpsuit_style = PREF_SUIT //suit/skirt
|
||||
|
||||
//Equipment slots
|
||||
var/obj/item/wear_suit = null
|
||||
var/obj/item/w_uniform = null
|
||||
var/obj/item/belt = null
|
||||
var/obj/item/wear_id = null
|
||||
var/obj/item/r_store = null
|
||||
var/obj/item/l_store = null
|
||||
var/obj/item/s_store = null
|
||||
|
||||
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
|
||||
var/list/blood_smear = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0)
|
||||
|
||||
var/name_override //For temporary visible name changes
|
||||
var/genital_override = FALSE //Force genitals on things incase of chems
|
||||
|
||||
var/nameless = FALSE //For drones of both the insectoid and robotic kind. And other types of nameless critters.
|
||||
|
||||
var/custom_species = null
|
||||
|
||||
var/datum/personal_crafting/handcrafting
|
||||
var/datum/physiology/physiology
|
||||
|
||||
var/list/datum/bioware = list()
|
||||
|
||||
var/creamed = FALSE //to use with creampie overlays
|
||||
var/static/list/can_ride_typecache = typecacheof(list(/mob/living/carbon/human, /mob/living/simple_animal/slime, /mob/living/simple_animal/parrot))
|
||||
var/lastpuke = 0
|
||||
var/last_fire_update
|
||||
@@ -1,139 +0,0 @@
|
||||
|
||||
/mob/living/carbon/human/restrained(ignore_grab)
|
||||
. = ((wear_suit && wear_suit.breakouttime) || ..())
|
||||
|
||||
|
||||
/mob/living/carbon/human/canBeHandcuffed()
|
||||
if(get_num_arms(FALSE) >= 2)
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
//gets assignment from ID or ID inside PDA or PDA itself
|
||||
//Useful when player do something with computers
|
||||
/mob/living/carbon/human/proc/get_assignment(if_no_id = "No id", if_no_job = "No job", hand_first = TRUE)
|
||||
var/obj/item/card/id/id = get_idcard(hand_first)
|
||||
if(id)
|
||||
. = id.assignment
|
||||
else
|
||||
var/obj/item/pda/pda = wear_id
|
||||
if(istype(pda))
|
||||
. = pda.ownjob
|
||||
else
|
||||
return if_no_id
|
||||
if(!.)
|
||||
return if_no_job
|
||||
|
||||
//gets name from ID or ID inside PDA or PDA itself
|
||||
//Useful when player do something with computers
|
||||
/mob/living/carbon/human/proc/get_authentification_name(if_no_id = "Unknown")
|
||||
var/obj/item/card/id/id = get_idcard(FALSE)
|
||||
if(id)
|
||||
return id.registered_name
|
||||
var/obj/item/pda/pda = wear_id
|
||||
if(istype(pda))
|
||||
return pda.owner
|
||||
return if_no_id
|
||||
|
||||
//repurposed proc. Now it combines get_id_name() and get_face_name() to determine a mob's name variable. Made into a separate proc as it'll be useful elsewhere
|
||||
/mob/living/carbon/human/get_visible_name()
|
||||
var/face_name = get_face_name("")
|
||||
var/id_name = get_id_name("")
|
||||
if(name_override)
|
||||
return name_override
|
||||
if(face_name)
|
||||
if(id_name && (id_name != face_name))
|
||||
return "[face_name] (as [id_name])"
|
||||
return face_name
|
||||
if(id_name)
|
||||
return id_name
|
||||
return "Unknown"
|
||||
|
||||
//Returns "Unknown" if facially disfigured and real_name if not. Useful for setting name when Fluacided or when updating a human's name variable
|
||||
/mob/living/carbon/human/proc/get_face_name(if_no_face="Unknown")
|
||||
if( wear_mask && (wear_mask.flags_inv&HIDEFACE) ) //Wearing a mask which hides our face, use id-name if possible
|
||||
return if_no_face
|
||||
if( head && (head.flags_inv&HIDEFACE) )
|
||||
return if_no_face //Likewise for hats
|
||||
var/obj/item/bodypart/O = get_bodypart(BODY_ZONE_HEAD)
|
||||
if( !O || (HAS_TRAIT(src, TRAIT_DISFIGURED)) || (O.brutestate+O.burnstate)>2 || cloneloss>50 || !real_name || nameless) //disfigured. use id-name if possible
|
||||
return if_no_face
|
||||
return real_name
|
||||
|
||||
//gets name from ID or PDA itself, ID inside PDA doesn't matter
|
||||
//Useful when player is being seen by other mobs
|
||||
/mob/living/carbon/human/proc/get_id_name(if_no_id = "Unknown")
|
||||
var/obj/item/storage/wallet/wallet = wear_id
|
||||
var/obj/item/pda/pda = wear_id
|
||||
var/obj/item/card/id/id = wear_id
|
||||
var/obj/item/modular_computer/tablet/tablet = wear_id
|
||||
if(istype(wallet))
|
||||
id = wallet.front_id
|
||||
if(istype(id))
|
||||
. = id.registered_name
|
||||
else if(istype(pda))
|
||||
. = pda.owner
|
||||
else if(istype(tablet))
|
||||
var/obj/item/computer_hardware/card_slot/card_slot = tablet.all_components[MC_CARD]
|
||||
if(card_slot && (card_slot.stored_card2 || card_slot.stored_card))
|
||||
if(card_slot.stored_card2) //The second card is the one used for authorization in the ID changing program, so we prioritize it here for consistency
|
||||
. = card_slot.stored_card2.registered_name
|
||||
else
|
||||
if(card_slot.stored_card)
|
||||
. = card_slot.stored_card.registered_name
|
||||
if(!.)
|
||||
. = if_no_id //to prevent null-names making the mob unclickable
|
||||
return
|
||||
|
||||
//gets ID card object from special clothes slot or null.
|
||||
/mob/living/carbon/human/get_idcard(hand_first = TRUE)
|
||||
. = ..()
|
||||
if(. && hand_first)
|
||||
return
|
||||
//Check inventory slots
|
||||
var/obj/item/card/id/id_card = wear_id?.GetID()
|
||||
if(!id_card)
|
||||
id_card = belt?.GetID()
|
||||
return id_card || .
|
||||
|
||||
/mob/living/carbon/human/IsAdvancedToolUser()
|
||||
if(HAS_TRAIT(src, TRAIT_MONKEYLIKE))
|
||||
return FALSE
|
||||
return TRUE//Humans can use guns and such
|
||||
|
||||
/mob/living/carbon/human/reagent_check(datum/reagent/R)
|
||||
return dna.species.handle_chemicals(R,src)
|
||||
// if it returns 0, it will run the usual on_mob_life for that reagent. otherwise, it will stop after running handle_chemicals for the species.
|
||||
|
||||
/mob/living/carbon/human/can_track(mob/living/user)
|
||||
if(wear_id && istype(wear_id.GetID(), /obj/item/card/id/syndicate))
|
||||
return 0
|
||||
if(istype(head, /obj/item/clothing/head))
|
||||
var/obj/item/clothing/head/hat = head
|
||||
if(hat.blockTracking)
|
||||
return 0
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/can_use_guns(obj/item/G)
|
||||
. = ..()
|
||||
|
||||
if(G.trigger_guard == TRIGGER_GUARD_NORMAL)
|
||||
if(src.dna.check_mutation(HULK))
|
||||
to_chat(src, "<span class='warning'>Your meaty finger is much too large for the trigger guard!</span>")
|
||||
return FALSE
|
||||
if(HAS_TRAIT(src, TRAIT_NOGUNS))
|
||||
to_chat(src, "<span class='warning'>Your fingers don't fit in the trigger guard!</span>")
|
||||
return FALSE
|
||||
if(mind)
|
||||
if(mind.martial_art && mind.martial_art.no_guns) //great dishonor to famiry
|
||||
to_chat(src, "<span class='warning'>Use of ranged weaponry would bring dishonor to the clan.</span>")
|
||||
return FALSE
|
||||
|
||||
return .
|
||||
/*
|
||||
/mob/living/carbon/human/transfer_blood_dna(list/blood_dna)
|
||||
..()
|
||||
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]*/
|
||||
@@ -1,78 +0,0 @@
|
||||
/mob/living/carbon/human/get_movespeed_modifiers()
|
||||
var/list/considering = ..()
|
||||
. = considering
|
||||
if(HAS_TRAIT(src, TRAIT_IGNORESLOWDOWN))
|
||||
for(var/id in .)
|
||||
var/list/data = .[id]
|
||||
if(data[MOVESPEED_DATA_INDEX_FLAGS] & IGNORE_NOSLOW)
|
||||
.[id] = data
|
||||
|
||||
/mob/living/carbon/human/movement_delay()
|
||||
. = ..()
|
||||
if(dna && dna.species)
|
||||
. += dna.species.movement_delay(src)
|
||||
|
||||
/mob/living/carbon/human/slip(knockdown_amount, obj/O, lube)
|
||||
if(HAS_TRAIT(src, TRAIT_NOSLIPALL))
|
||||
return 0
|
||||
if (!(lube&GALOSHES_DONT_HELP))
|
||||
if(HAS_TRAIT(src, TRAIT_NOSLIPWATER))
|
||||
return 0
|
||||
if(shoes && istype(shoes, /obj/item/clothing))
|
||||
var/obj/item/clothing/CS = shoes
|
||||
if (CS.clothing_flags & NOSLIP)
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/experience_pressure_difference()
|
||||
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)
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/mob_has_gravity()
|
||||
. = ..()
|
||||
if(!.)
|
||||
if(mob_negates_gravity())
|
||||
. = 1
|
||||
|
||||
/mob/living/carbon/human/mob_negates_gravity()
|
||||
return ((shoes && shoes.negates_gravity()) || (dna.species.negates_gravity(src)))
|
||||
|
||||
/mob/living/carbon/human/Move(NewLoc, direct)
|
||||
. = ..()
|
||||
for(var/datum/mutation/human/HM in dna.mutations)
|
||||
HM.on_move(src, NewLoc)
|
||||
|
||||
if(shoes)
|
||||
if(!lying && !buckled)
|
||||
if(loc == NewLoc)
|
||||
if(!has_gravity(loc))
|
||||
return
|
||||
var/obj/item/clothing/shoes/S = shoes
|
||||
|
||||
//Bloody footprints
|
||||
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)))
|
||||
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)
|
||||
FP.blood_state = S.blood_state
|
||||
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.update_icon()
|
||||
update_inv_shoes()
|
||||
//End bloody footprints
|
||||
|
||||
S.step_action()
|
||||
|
||||
/mob/living/carbon/human/Process_Spacemove(movement_dir = 0) //Temporary laziness thing. Will change to handles by species reee.
|
||||
if(dna.species.space_move(src))
|
||||
return TRUE
|
||||
return ..()
|
||||
@@ -1,274 +0,0 @@
|
||||
/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)
|
||||
|
||||
// Return the item currently in the slot ID
|
||||
/mob/living/carbon/human/get_item_by_slot(slot_id)
|
||||
switch(slot_id)
|
||||
if(SLOT_BACK)
|
||||
return back
|
||||
if(SLOT_WEAR_MASK)
|
||||
return wear_mask
|
||||
if(SLOT_NECK)
|
||||
return wear_neck
|
||||
if(SLOT_HANDCUFFED)
|
||||
return handcuffed
|
||||
if(SLOT_LEGCUFFED)
|
||||
return legcuffed
|
||||
if(SLOT_BELT)
|
||||
return belt
|
||||
if(SLOT_WEAR_ID)
|
||||
return wear_id
|
||||
if(SLOT_EARS)
|
||||
return ears
|
||||
if(SLOT_GLASSES)
|
||||
return glasses
|
||||
if(SLOT_GLOVES)
|
||||
return gloves
|
||||
if(SLOT_HEAD)
|
||||
return head
|
||||
if(SLOT_SHOES)
|
||||
return shoes
|
||||
if(SLOT_WEAR_SUIT)
|
||||
return wear_suit
|
||||
if(SLOT_W_UNIFORM)
|
||||
return w_uniform
|
||||
if(SLOT_L_STORE)
|
||||
return l_store
|
||||
if(SLOT_R_STORE)
|
||||
return r_store
|
||||
if(SLOT_S_STORE)
|
||||
return s_store
|
||||
return null
|
||||
|
||||
/mob/living/carbon/human/proc/get_all_slots()
|
||||
. = get_head_slots() | get_body_slots()
|
||||
|
||||
/mob/living/carbon/human/proc/get_body_slots()
|
||||
return list(
|
||||
back,
|
||||
s_store,
|
||||
handcuffed,
|
||||
legcuffed,
|
||||
wear_suit,
|
||||
gloves,
|
||||
shoes,
|
||||
belt,
|
||||
wear_id,
|
||||
l_store,
|
||||
r_store,
|
||||
w_uniform
|
||||
)
|
||||
|
||||
/mob/living/carbon/human/proc/get_head_slots()
|
||||
return list(
|
||||
head,
|
||||
wear_mask,
|
||||
wear_neck,
|
||||
glasses,
|
||||
ears,
|
||||
)
|
||||
|
||||
/mob/living/carbon/human/proc/get_storage_slots()
|
||||
return list(
|
||||
back,
|
||||
belt,
|
||||
l_store,
|
||||
r_store,
|
||||
s_store,
|
||||
)
|
||||
|
||||
//This is an UNSAFE proc. Use mob_can_equip() before calling this one! Or rather use equip_to_slot_if_possible() or advanced_equip_to_slot_if_possible()
|
||||
/mob/living/carbon/human/equip_to_slot(obj/item/I, slot)
|
||||
. = ..()
|
||||
if(!.) //a check failed or the item has already found its slot
|
||||
return
|
||||
|
||||
var/not_handled = FALSE //Added in case we make this type path deeper one day
|
||||
switch(slot)
|
||||
if(SLOT_BELT)
|
||||
belt = I
|
||||
update_inv_belt()
|
||||
if(SLOT_WEAR_ID)
|
||||
wear_id = I
|
||||
sec_hud_set_ID()
|
||||
update_inv_wear_id()
|
||||
if(SLOT_EARS)
|
||||
ears = I
|
||||
update_inv_ears()
|
||||
if(SLOT_GLASSES)
|
||||
glasses = I
|
||||
var/obj/item/clothing/glasses/G = I
|
||||
if(G.glass_colour_type)
|
||||
update_glasses_color(G, 1)
|
||||
if(G.tint)
|
||||
update_tint()
|
||||
if(G.vision_correction)
|
||||
clear_fullscreen("nearsighted")
|
||||
clear_fullscreen("eye_damage")
|
||||
if(G.vision_flags || G.darkness_view || G.invis_override || G.invis_view || !isnull(G.lighting_alpha))
|
||||
update_sight()
|
||||
update_inv_glasses()
|
||||
if(SLOT_GLOVES)
|
||||
gloves = I
|
||||
update_inv_gloves()
|
||||
if(SLOT_SHOES)
|
||||
shoes = I
|
||||
update_inv_shoes()
|
||||
if(SLOT_WEAR_SUIT)
|
||||
wear_suit = I
|
||||
if(I.flags_inv & HIDEJUMPSUIT)
|
||||
update_inv_w_uniform()
|
||||
if(wear_suit.breakouttime) //when equipping a straightjacket
|
||||
stop_pulling() //can't pull if restrained
|
||||
update_action_buttons_icon() //certain action buttons will no longer be usable.
|
||||
update_inv_wear_suit()
|
||||
if(SLOT_W_UNIFORM)
|
||||
w_uniform = I
|
||||
update_suit_sensors()
|
||||
update_inv_w_uniform()
|
||||
if(SLOT_L_STORE)
|
||||
l_store = I
|
||||
update_inv_pockets()
|
||||
if(SLOT_R_STORE)
|
||||
r_store = I
|
||||
update_inv_pockets()
|
||||
if(SLOT_S_STORE)
|
||||
s_store = I
|
||||
update_inv_s_store()
|
||||
else
|
||||
to_chat(src, "<span class='danger'>You are trying to equip this item to an unsupported inventory slot. Report this to a coder!</span>")
|
||||
not_handled = TRUE
|
||||
|
||||
//Item is handled and in slot, valid to call callback, for this proc should always be true
|
||||
if(!not_handled)
|
||||
I.equipped(src, slot)
|
||||
|
||||
return not_handled //For future deeper overrides
|
||||
|
||||
/mob/living/carbon/human/doUnEquip(obj/item/I, force, newloc, no_move, invdrop = TRUE)
|
||||
var/index = get_held_index_of_item(I)
|
||||
. = ..() //See mob.dm for an explanation on this and some rage about people copypasting instead of calling ..() like they should.
|
||||
if(!. || !I)
|
||||
return
|
||||
if(index && !QDELETED(src) && dna.species.mutanthands) //hand freed, fill with claws, skip if we're getting deleted.
|
||||
put_in_hand(new dna.species.mutanthands(), index)
|
||||
if(I == wear_suit)
|
||||
if(s_store && invdrop)
|
||||
dropItemToGround(s_store, TRUE) //It makes no sense for your suit storage to stay on you if you drop your suit.
|
||||
if(wear_suit.breakouttime) //when unequipping a straightjacket
|
||||
drop_all_held_items() //suit is restraining
|
||||
update_action_buttons_icon() //certain action buttons may be usable again.
|
||||
wear_suit = null
|
||||
if(!QDELETED(src)) //no need to update we're getting deleted anyway
|
||||
if(I.flags_inv & HIDEJUMPSUIT)
|
||||
update_inv_w_uniform()
|
||||
update_inv_wear_suit()
|
||||
else if(I == w_uniform)
|
||||
if(invdrop)
|
||||
if(r_store)
|
||||
dropItemToGround(r_store, TRUE) //Again, makes sense for pockets to drop.
|
||||
if(l_store)
|
||||
dropItemToGround(l_store, TRUE)
|
||||
if(wear_id && !CHECK_BITFIELD(wear_id.item_flags, NO_UNIFORM_REQUIRED))
|
||||
dropItemToGround(wear_id)
|
||||
if(belt && !CHECK_BITFIELD(belt.item_flags, NO_UNIFORM_REQUIRED))
|
||||
dropItemToGround(belt)
|
||||
w_uniform = null
|
||||
update_suit_sensors()
|
||||
if(!QDELETED(src))
|
||||
update_inv_w_uniform()
|
||||
else if(I == gloves)
|
||||
gloves = null
|
||||
if(!QDELETED(src))
|
||||
update_inv_gloves()
|
||||
else if(I == glasses)
|
||||
glasses = null
|
||||
var/obj/item/clothing/glasses/G = I
|
||||
if(G.glass_colour_type)
|
||||
update_glasses_color(G, 0)
|
||||
if(G.tint)
|
||||
update_tint()
|
||||
if(G.vision_correction)
|
||||
if(HAS_TRAIT(src, TRAIT_NEARSIGHT))
|
||||
overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1)
|
||||
adjust_eye_damage(0)
|
||||
if(G.vision_flags || G.darkness_view || G.invis_override || G.invis_view || !isnull(G.lighting_alpha))
|
||||
update_sight()
|
||||
if(!QDELETED(src))
|
||||
update_inv_glasses()
|
||||
else if(I == ears)
|
||||
ears = null
|
||||
if(!QDELETED(src))
|
||||
update_inv_ears()
|
||||
else if(I == shoes)
|
||||
shoes = null
|
||||
if(!QDELETED(src))
|
||||
update_inv_shoes()
|
||||
else if(I == belt)
|
||||
belt = null
|
||||
if(!QDELETED(src))
|
||||
update_inv_belt()
|
||||
else if(I == wear_id)
|
||||
wear_id = null
|
||||
sec_hud_set_ID()
|
||||
if(!QDELETED(src))
|
||||
update_inv_wear_id()
|
||||
else if(I == r_store)
|
||||
r_store = null
|
||||
if(!QDELETED(src))
|
||||
update_inv_pockets()
|
||||
else if(I == l_store)
|
||||
l_store = null
|
||||
if(!QDELETED(src))
|
||||
update_inv_pockets()
|
||||
else if(I == s_store)
|
||||
s_store = null
|
||||
if(!QDELETED(src))
|
||||
update_inv_s_store()
|
||||
|
||||
/mob/living/carbon/human/wear_mask_update(obj/item/clothing/C, toggle_off = 1)
|
||||
if((C.flags_inv & (HIDEHAIR|HIDEFACIALHAIR)) || (initial(C.flags_inv) & (HIDEHAIR|HIDEFACIALHAIR)))
|
||||
update_hair()
|
||||
if(toggle_off && internal && !getorganslot(ORGAN_SLOT_BREATHING_TUBE))
|
||||
update_internals_hud_icon(0)
|
||||
internal = null
|
||||
if(C.flags_inv & HIDEEYES)
|
||||
update_inv_glasses()
|
||||
sec_hud_set_security_status()
|
||||
..()
|
||||
|
||||
/mob/living/carbon/human/head_update(obj/item/I, forced)
|
||||
if((I.flags_inv & (HIDEHAIR|HIDEFACIALHAIR)) || forced)
|
||||
update_hair()
|
||||
else
|
||||
var/obj/item/clothing/C = I
|
||||
if(istype(C) && C.dynamic_hair_suffix)
|
||||
update_hair()
|
||||
if(I.flags_inv & HIDEEYES || forced)
|
||||
update_inv_glasses()
|
||||
if(I.flags_inv & HIDEEARS || forced)
|
||||
update_body()
|
||||
sec_hud_set_security_status()
|
||||
..()
|
||||
|
||||
/mob/living/carbon/human/proc/equipOutfit(outfit, visualsOnly = FALSE)
|
||||
var/datum/outfit/O = null
|
||||
|
||||
if(ispath(outfit))
|
||||
O = new outfit
|
||||
else
|
||||
O = outfit
|
||||
if(!istype(O))
|
||||
return 0
|
||||
if(!O)
|
||||
return 0
|
||||
|
||||
return O.equip(src, visualsOnly)
|
||||
|
||||
|
||||
//delete all equipment without dropping anything
|
||||
/mob/living/carbon/human/proc/delete_equipment()
|
||||
for(var/slot in get_all_slots())//order matters, dependant slots go first
|
||||
qdel(slot)
|
||||
for(var/obj/item/I in held_items)
|
||||
qdel(I)
|
||||
@@ -1,357 +0,0 @@
|
||||
|
||||
|
||||
//NOTE: Breathing happens once per FOUR TICKS, unless the last breath fails. In which case it happens once per ONE TICK! So oxyloss healing is done once per 4 ticks while oxyloss damage is applied once per tick!
|
||||
|
||||
// bitflags for the percentual amount of protection a piece of clothing which covers the body part offers.
|
||||
// Used with human/proc/get_thermal_protection()
|
||||
// The values here should add up to 1.
|
||||
// Hands and feet have 2.5%, arms and legs 7.5%, each of the torso parts has 15% and the head has 30%
|
||||
#define THERMAL_PROTECTION_HEAD 0.3
|
||||
#define THERMAL_PROTECTION_CHEST 0.15
|
||||
#define THERMAL_PROTECTION_GROIN 0.15
|
||||
#define THERMAL_PROTECTION_LEG_LEFT 0.075
|
||||
#define THERMAL_PROTECTION_LEG_RIGHT 0.075
|
||||
#define THERMAL_PROTECTION_FOOT_LEFT 0.025
|
||||
#define THERMAL_PROTECTION_FOOT_RIGHT 0.025
|
||||
#define THERMAL_PROTECTION_ARM_LEFT 0.075
|
||||
#define THERMAL_PROTECTION_ARM_RIGHT 0.075
|
||||
#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)
|
||||
return
|
||||
|
||||
. = ..()
|
||||
|
||||
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()
|
||||
|
||||
if(stat != DEAD)
|
||||
//process your dick energy
|
||||
handle_arousal(times_fired)
|
||||
|
||||
//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))))
|
||||
var/obj/item/clothing/CS = wear_suit
|
||||
var/obj/item/clothing/CH = head
|
||||
if (CS.clothing_flags & STOPSPRESSUREDAMAGE && (headless || (CH.clothing_flags & STOPSPRESSUREDAMAGE)))
|
||||
return ONE_ATMOSPHERE
|
||||
if(isbelly(loc)) //START OF CIT CHANGES - Makes it so you don't suffocate while inside vore organs. Remind me to modularize this some time - Bhijn
|
||||
return ONE_ATMOSPHERE
|
||||
if(istype(loc, /obj/item/dogborg/sleeper))
|
||||
return ONE_ATMOSPHERE //END OF CIT CHANGES
|
||||
return ..()
|
||||
|
||||
|
||||
/mob/living/carbon/human/handle_traits()
|
||||
if(eye_blind) //blindness, heals slowly over time
|
||||
if(HAS_TRAIT_FROM(src, TRAIT_BLIND, EYES_COVERED)) //covering your eyes heals blurry eyes faster
|
||||
adjust_blindness(-3)
|
||||
else
|
||||
adjust_blindness(-1)
|
||||
else if(eye_blurry) //blurry eyes heal slowly
|
||||
adjust_blurriness(-1)
|
||||
|
||||
if (getOrganLoss(ORGAN_SLOT_BRAIN) >= 30) //Citadel change to make memes more often.
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "brain_damage", /datum/mood_event/brain_damage)
|
||||
if(prob(3))
|
||||
if(prob(25))
|
||||
emote("drool")
|
||||
else
|
||||
say(pick_list_replacements(BRAIN_DAMAGE_FILE, "brain_damage"))
|
||||
else
|
||||
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "brain_damage")
|
||||
|
||||
/mob/living/carbon/human/handle_mutations_and_radiation()
|
||||
if(!dna || !dna.species.handle_mutations_and_radiation(src))
|
||||
..()
|
||||
|
||||
/mob/living/carbon/human/breathe()
|
||||
if(!dna.species.breathe(src))
|
||||
..()
|
||||
|
||||
/mob/living/carbon/human/check_breath(datum/gas_mixture/breath)
|
||||
|
||||
var/L = getorganslot(ORGAN_SLOT_LUNGS)
|
||||
|
||||
if(!L)
|
||||
if(health >= crit_threshold)
|
||||
adjustOxyLoss(HUMAN_MAX_OXYLOSS + 1)
|
||||
else if(!HAS_TRAIT(src, TRAIT_NOCRITDAMAGE))
|
||||
adjustOxyLoss(HUMAN_CRIT_MAX_OXYLOSS)
|
||||
|
||||
failed_last_breath = 1
|
||||
|
||||
var/datum/species/S = dna.species
|
||||
|
||||
if(S.breathid == "o2")
|
||||
throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy)
|
||||
else if(S.breathid == "tox")
|
||||
throw_alert("not_enough_tox", /obj/screen/alert/not_enough_tox)
|
||||
else if(S.breathid == "co2")
|
||||
throw_alert("not_enough_co2", /obj/screen/alert/not_enough_co2)
|
||||
else if(S.breathid == "n2")
|
||||
throw_alert("not_enough_nitro", /obj/screen/alert/not_enough_nitro)
|
||||
|
||||
return FALSE
|
||||
else
|
||||
if(istype(L, /obj/item/organ/lungs))
|
||||
var/obj/item/organ/lungs/lun = L
|
||||
lun.check_breath(breath,src)
|
||||
|
||||
/mob/living/carbon/human/handle_environment(datum/gas_mixture/environment)
|
||||
dna.species.handle_environment(environment, src)
|
||||
|
||||
///FIRE CODE
|
||||
/mob/living/carbon/human/handle_fire()
|
||||
if(!last_fire_update)
|
||||
last_fire_update = fire_stacks
|
||||
if((fire_stacks > HUMAN_FIRE_STACK_ICON_NUM && last_fire_update <= HUMAN_FIRE_STACK_ICON_NUM) || (fire_stacks <= HUMAN_FIRE_STACK_ICON_NUM && last_fire_update > HUMAN_FIRE_STACK_ICON_NUM))
|
||||
last_fire_update = fire_stacks
|
||||
update_fire()
|
||||
|
||||
..()
|
||||
if(dna)
|
||||
dna.species.handle_fire(src)
|
||||
|
||||
/mob/living/carbon/human/proc/easy_thermal_protection()
|
||||
var/thermal_protection = 0 //Simple check to estimate how protected we are against multiple temperatures
|
||||
//CITADEL EDIT Vore code required overrides
|
||||
if(istype(loc, /obj/item/dogborg/sleeper))
|
||||
return FIRE_IMMUNITY_MAX_TEMP_PROTECT
|
||||
if(ismob(loc))
|
||||
return FIRE_IMMUNITY_MAX_TEMP_PROTECT
|
||||
if(isbelly(loc))
|
||||
return FIRE_IMMUNITY_MAX_TEMP_PROTECT
|
||||
//END EDIT
|
||||
if(wear_suit)
|
||||
if(wear_suit.max_heat_protection_temperature >= FIRE_SUIT_MAX_TEMP_PROTECT)
|
||||
thermal_protection += (wear_suit.max_heat_protection_temperature*0.7)
|
||||
if(head)
|
||||
if(head.max_heat_protection_temperature >= FIRE_HELM_MAX_TEMP_PROTECT)
|
||||
thermal_protection += (head.max_heat_protection_temperature*THERMAL_PROTECTION_HEAD)
|
||||
thermal_protection = round(thermal_protection)
|
||||
return thermal_protection
|
||||
|
||||
/mob/living/carbon/human/IgniteMob()
|
||||
//If have no DNA or can be Ignited, call parent handling to light user
|
||||
//If firestacks are high enough
|
||||
if(!dna || dna.species.CanIgniteMob(src))
|
||||
return ..()
|
||||
. = FALSE //No ignition
|
||||
|
||||
/mob/living/carbon/human/ExtinguishMob()
|
||||
if(!dna || !dna.species.ExtinguishMob(src))
|
||||
last_fire_update = null
|
||||
..()
|
||||
//END FIRE CODE
|
||||
|
||||
//This proc returns a number made up of the flags for body parts which you are protected on. (such as HEAD, CHEST, GROIN, etc. See setup.dm for the full list)
|
||||
/mob/living/carbon/human/proc/get_heat_protection_flags(temperature) //Temperature is the temperature you're being exposed to.
|
||||
var/thermal_protection_flags = 0
|
||||
//Handle normal clothing
|
||||
if(head)
|
||||
if(head.max_heat_protection_temperature && head.max_heat_protection_temperature >= temperature)
|
||||
thermal_protection_flags |= head.heat_protection
|
||||
if(wear_suit)
|
||||
if(wear_suit.max_heat_protection_temperature && wear_suit.max_heat_protection_temperature >= temperature)
|
||||
thermal_protection_flags |= wear_suit.heat_protection
|
||||
if(w_uniform)
|
||||
if(w_uniform.max_heat_protection_temperature && w_uniform.max_heat_protection_temperature >= temperature)
|
||||
thermal_protection_flags |= w_uniform.heat_protection
|
||||
if(shoes)
|
||||
if(shoes.max_heat_protection_temperature && shoes.max_heat_protection_temperature >= temperature)
|
||||
thermal_protection_flags |= shoes.heat_protection
|
||||
if(gloves)
|
||||
if(gloves.max_heat_protection_temperature && gloves.max_heat_protection_temperature >= temperature)
|
||||
thermal_protection_flags |= gloves.heat_protection
|
||||
if(wear_mask)
|
||||
if(wear_mask.max_heat_protection_temperature && wear_mask.max_heat_protection_temperature >= temperature)
|
||||
thermal_protection_flags |= wear_mask.heat_protection
|
||||
|
||||
return thermal_protection_flags
|
||||
|
||||
//See proc/get_heat_protection_flags(temperature) for the description of this proc.
|
||||
/mob/living/carbon/human/proc/get_cold_protection_flags(temperature)
|
||||
var/thermal_protection_flags = 0
|
||||
//Handle normal clothing
|
||||
|
||||
if(head)
|
||||
if(head.min_cold_protection_temperature && head.min_cold_protection_temperature <= temperature)
|
||||
thermal_protection_flags |= head.cold_protection
|
||||
if(wear_suit)
|
||||
if(wear_suit.min_cold_protection_temperature && wear_suit.min_cold_protection_temperature <= temperature)
|
||||
thermal_protection_flags |= wear_suit.cold_protection
|
||||
if(w_uniform)
|
||||
if(w_uniform.min_cold_protection_temperature && w_uniform.min_cold_protection_temperature <= temperature)
|
||||
thermal_protection_flags |= w_uniform.cold_protection
|
||||
if(shoes)
|
||||
if(shoes.min_cold_protection_temperature && shoes.min_cold_protection_temperature <= temperature)
|
||||
thermal_protection_flags |= shoes.cold_protection
|
||||
if(gloves)
|
||||
if(gloves.min_cold_protection_temperature && gloves.min_cold_protection_temperature <= temperature)
|
||||
thermal_protection_flags |= gloves.cold_protection
|
||||
if(wear_mask)
|
||||
if(wear_mask.min_cold_protection_temperature && wear_mask.min_cold_protection_temperature <= temperature)
|
||||
thermal_protection_flags |= wear_mask.cold_protection
|
||||
|
||||
return thermal_protection_flags
|
||||
|
||||
/mob/living/carbon/human/proc/get_thermal_protection(temperature, cold = FALSE)
|
||||
if(cold)
|
||||
//CITADEL EDIT Mandatory for vore code.
|
||||
if(istype(loc, /obj/item/dogborg/sleeper) || isbelly(loc) || ismob(loc))
|
||||
return 1 //freezing to death in sleepers ruins fun.
|
||||
//END EDIT
|
||||
temperature = max(temperature, 2.7) //There is an occasional bug where the temperature is miscalculated in ares with a small amount of gas on them, so this is necessary to ensure that that bug does not affect this calculation. Space's temperature is 2.7K and most suits that are intended to protect against any cold, protect down to 2.0K.
|
||||
var/thermal_protection_flags = cold ? get_cold_protection_flags(temperature) : get_heat_protection_flags(temperature)
|
||||
var/missing_body_parts_flags = ~get_body_parts_flags()
|
||||
var/max_protection = 1
|
||||
if(missing_body_parts_flags) //I don't like copypasta as much as proc overhead. Do you want me to make these into a macro?
|
||||
DISABLE_BITFIELD(thermal_protection_flags, missing_body_parts_flags)
|
||||
if(missing_body_parts_flags & HEAD)
|
||||
max_protection -= THERMAL_PROTECTION_HEAD
|
||||
if(missing_body_parts_flags & CHEST)
|
||||
max_protection -= THERMAL_PROTECTION_CHEST
|
||||
if(missing_body_parts_flags & GROIN)
|
||||
max_protection -= THERMAL_PROTECTION_GROIN
|
||||
if(missing_body_parts_flags & LEG_LEFT)
|
||||
max_protection -= THERMAL_PROTECTION_LEG_LEFT
|
||||
if(missing_body_parts_flags & LEG_RIGHT)
|
||||
max_protection -= THERMAL_PROTECTION_LEG_RIGHT
|
||||
if(missing_body_parts_flags & FOOT_LEFT)
|
||||
max_protection -= THERMAL_PROTECTION_FOOT_LEFT
|
||||
if(missing_body_parts_flags & FOOT_RIGHT)
|
||||
max_protection -= THERMAL_PROTECTION_FOOT_RIGHT
|
||||
if(missing_body_parts_flags & ARM_LEFT)
|
||||
max_protection -= THERMAL_PROTECTION_ARM_LEFT
|
||||
if(missing_body_parts_flags & ARM_RIGHT)
|
||||
max_protection -= THERMAL_PROTECTION_ARM_RIGHT
|
||||
if(missing_body_parts_flags & HAND_LEFT)
|
||||
max_protection -= THERMAL_PROTECTION_HAND_LEFT
|
||||
if(missing_body_parts_flags & HAND_RIGHT)
|
||||
max_protection -= THERMAL_PROTECTION_HAND_RIGHT
|
||||
if(max_protection == 0) //Is it even a man if it doesn't have a body at all? Early return to avoid division by zero.
|
||||
return 1
|
||||
|
||||
var/thermal_protection = 0
|
||||
if(thermal_protection_flags)
|
||||
if(thermal_protection_flags & HEAD)
|
||||
thermal_protection += THERMAL_PROTECTION_HEAD
|
||||
if(thermal_protection_flags & CHEST)
|
||||
thermal_protection += THERMAL_PROTECTION_CHEST
|
||||
if(thermal_protection_flags & GROIN)
|
||||
thermal_protection += THERMAL_PROTECTION_GROIN
|
||||
if(thermal_protection_flags & LEG_LEFT)
|
||||
thermal_protection += THERMAL_PROTECTION_LEG_LEFT
|
||||
if(thermal_protection_flags & LEG_RIGHT)
|
||||
thermal_protection += THERMAL_PROTECTION_LEG_RIGHT
|
||||
if(thermal_protection_flags & FOOT_LEFT)
|
||||
thermal_protection += THERMAL_PROTECTION_FOOT_LEFT
|
||||
if(thermal_protection_flags & FOOT_RIGHT)
|
||||
thermal_protection += THERMAL_PROTECTION_FOOT_RIGHT
|
||||
if(thermal_protection_flags & ARM_LEFT)
|
||||
thermal_protection += THERMAL_PROTECTION_ARM_LEFT
|
||||
if(thermal_protection_flags & ARM_RIGHT)
|
||||
thermal_protection += THERMAL_PROTECTION_ARM_RIGHT
|
||||
if(thermal_protection_flags & HAND_LEFT)
|
||||
thermal_protection += THERMAL_PROTECTION_HAND_LEFT
|
||||
if(thermal_protection_flags & HAND_RIGHT)
|
||||
thermal_protection += THERMAL_PROTECTION_HAND_RIGHT
|
||||
|
||||
return round(thermal_protection/max_protection, 0.001)
|
||||
|
||||
/mob/living/carbon/human/handle_random_events()
|
||||
//Puke if toxloss is too high
|
||||
if(!stat)
|
||||
if(getToxLoss() >= 45 && nutrition > 20)
|
||||
lastpuke += prob(50)
|
||||
if(lastpuke >= 50) // about 25 second delay I guess
|
||||
vomit(20, toxic = TRUE)
|
||||
lastpuke = 0
|
||||
|
||||
|
||||
/mob/living/carbon/human/has_smoke_protection()
|
||||
if(wear_mask)
|
||||
if(wear_mask.clothing_flags & BLOCK_GAS_SMOKE_EFFECT)
|
||||
return TRUE
|
||||
if(glasses)
|
||||
if(glasses.clothing_flags & BLOCK_GAS_SMOKE_EFFECT)
|
||||
return TRUE
|
||||
if(head && istype(head, /obj/item/clothing))
|
||||
var/obj/item/clothing/CH = head
|
||||
if(CH.clothing_flags & BLOCK_GAS_SMOKE_EFFECT)
|
||||
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())
|
||||
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()
|
||||
for(var/datum/mutation/human/HM in dna.mutations)
|
||||
HM.on_life(src)
|
||||
|
||||
/mob/living/carbon/human/proc/handle_heart()
|
||||
var/we_breath = !HAS_TRAIT_FROM(src, TRAIT_NOBREATH, SPECIES_TRAIT)
|
||||
|
||||
if(!undergoing_cardiac_arrest())
|
||||
return
|
||||
|
||||
if(we_breath)
|
||||
adjustOxyLoss(8)
|
||||
Unconscious(80)
|
||||
// Tissues die without blood circulation
|
||||
adjustBruteLoss(2)
|
||||
|
||||
|
||||
|
||||
|
||||
#undef THERMAL_PROTECTION_HEAD
|
||||
#undef THERMAL_PROTECTION_CHEST
|
||||
#undef THERMAL_PROTECTION_GROIN
|
||||
#undef THERMAL_PROTECTION_LEG_LEFT
|
||||
#undef THERMAL_PROTECTION_LEG_RIGHT
|
||||
#undef THERMAL_PROTECTION_FOOT_LEFT
|
||||
#undef THERMAL_PROTECTION_FOOT_RIGHT
|
||||
#undef THERMAL_PROTECTION_ARM_LEFT
|
||||
#undef THERMAL_PROTECTION_ARM_RIGHT
|
||||
#undef THERMAL_PROTECTION_HAND_LEFT
|
||||
#undef THERMAL_PROTECTION_HAND_RIGHT
|
||||
@@ -1,29 +0,0 @@
|
||||
//Stores several modifiers in a way that isn't cleared by changing species
|
||||
|
||||
/datum/physiology
|
||||
var/brute_mod = 1 // % of brute damage taken from all sources
|
||||
var/burn_mod = 1 // % of burn damage taken from all sources
|
||||
var/tox_mod = 1 // % of toxin damage taken from all sources
|
||||
var/oxy_mod = 1 // % of oxygen damage taken from all sources
|
||||
var/clone_mod = 1 // % of clone damage taken from all sources
|
||||
var/stamina_mod = 1 // % of stamina damage taken from all sources
|
||||
var/brain_mod = 1 // % of brain damage taken from all sources
|
||||
|
||||
var/pressure_mod = 1 // % of brute damage taken from low or high pressure (stacks with brute_mod)
|
||||
var/heat_mod = 1 // % of burn damage taken from heat (stacks with burn_mod)
|
||||
var/cold_mod = 1 // % of burn damage taken from cold (stacks with burn_mod)
|
||||
|
||||
var/damage_resistance = 0 // %damage reduction from all sources
|
||||
|
||||
var/siemens_coeff = 1 // resistance to shocks
|
||||
|
||||
var/stun_mod = 1 // % stun modifier
|
||||
var/bleed_mod = 1 // % bleeding modifier
|
||||
var/datum/armor/armor // internal armor datum
|
||||
|
||||
var/hunger_mod = 1 //% of hunger rate taken per tick.
|
||||
|
||||
var/do_after_speed = 1 //Speed mod for do_after. Lower is better. If temporarily adjusting, please only modify using *= and /=, so you don't interrupt other calculations.
|
||||
|
||||
/datum/physiology/New()
|
||||
armor = new
|
||||
@@ -1,116 +0,0 @@
|
||||
/mob/living/carbon/human/say_mod(input, message_mode)
|
||||
verb_say = dna.species.say_mod
|
||||
. = ..()
|
||||
if(message_mode != MODE_CUSTOM_SAY && message_mode != MODE_WHISPER_CRIT)
|
||||
switch(slurring)
|
||||
if(10 to 25)
|
||||
return "jumbles"
|
||||
if(25 to 50)
|
||||
return "slurs"
|
||||
if(50 to INFINITY)
|
||||
return "garbles"
|
||||
|
||||
/mob/living/carbon/human/GetVoice()
|
||||
if(istype(wear_mask, /obj/item/clothing/mask/chameleon))
|
||||
var/obj/item/clothing/mask/chameleon/V = wear_mask
|
||||
if(V.vchange && wear_id)
|
||||
var/obj/item/card/id/idcard = wear_id.GetID()
|
||||
if(istype(idcard))
|
||||
return idcard.registered_name
|
||||
else
|
||||
return real_name
|
||||
else
|
||||
return real_name
|
||||
if(mind)
|
||||
var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(changeling && changeling.mimicing )
|
||||
return changeling.mimicing
|
||||
if(GetSpecialVoice())
|
||||
return GetSpecialVoice()
|
||||
return real_name
|
||||
|
||||
/mob/living/carbon/human/IsVocal()
|
||||
// how do species that don't breathe talk? magic, that's what.
|
||||
if(!HAS_TRAIT_FROM(src, TRAIT_NOBREATH, SPECIES_TRAIT) && !getorganslot(ORGAN_SLOT_LUNGS))
|
||||
return FALSE
|
||||
if(mind)
|
||||
return !mind.miming
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/proc/SetSpecialVoice(new_voice)
|
||||
if(new_voice)
|
||||
special_voice = new_voice
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/proc/UnsetSpecialVoice()
|
||||
special_voice = ""
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/proc/GetSpecialVoice()
|
||||
return special_voice
|
||||
|
||||
/mob/living/carbon/human/binarycheck()
|
||||
if(ears)
|
||||
var/obj/item/radio/headset/dongle = ears
|
||||
if(!istype(dongle))
|
||||
return FALSE
|
||||
if(dongle.translate_binary)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/radio(message, message_mode, list/spans, language)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
switch(message_mode)
|
||||
if(MODE_HEADSET)
|
||||
if (ears)
|
||||
ears.talk_into(src, message, , spans, language)
|
||||
return ITALICS | REDUCE_RANGE
|
||||
|
||||
if(MODE_DEPARTMENT)
|
||||
if (ears)
|
||||
ears.talk_into(src, message, message_mode, spans, language)
|
||||
return ITALICS | REDUCE_RANGE
|
||||
|
||||
if(message_mode in GLOB.radiochannels)
|
||||
if(ears)
|
||||
ears.talk_into(src, message, message_mode, spans, language)
|
||||
return ITALICS | REDUCE_RANGE
|
||||
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/human/get_alt_name()
|
||||
if(name != GetVoice())
|
||||
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
|
||||
if(stat == CONSCIOUS)
|
||||
if(client)
|
||||
var/virgin = 1 //has the text been modified yet?
|
||||
var/temp = winget(client, "input", "text")
|
||||
if(findtextEx(temp, "Say \"", 1, 7) && length(temp) > 5) //"case sensitive means
|
||||
|
||||
temp = replacetext(temp, ";", "") //general radio
|
||||
|
||||
if(findtext(trim_left(temp), ":", 6, 7)) //dept radio
|
||||
temp = copytext(trim_left(temp), 8)
|
||||
virgin = 0
|
||||
|
||||
if(virgin)
|
||||
temp = copytext(trim_left(temp), 6) //normal speech
|
||||
virgin = 0
|
||||
|
||||
while(findtext(trim_left(temp), ":", 1, 2)) //dept radio again (necessary)
|
||||
temp = copytext(trim_left(temp), 3)
|
||||
|
||||
if(findtext(temp, "*", 1, 2)) //emotes
|
||||
return
|
||||
|
||||
var/trimmed = trim_left(temp)
|
||||
if(length(trimmed))
|
||||
if(append)
|
||||
temp += pick(append)
|
||||
|
||||
say(temp)
|
||||
winset(client, "input", "text=[null]")
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,18 +0,0 @@
|
||||
/datum/species/abductor
|
||||
name = "Abductor"
|
||||
id = "abductor"
|
||||
say_mod = "gibbers"
|
||||
sexes = FALSE
|
||||
species_traits = list(NOBLOOD,NOEYES,NOGENITALS,NOAROUSAL)
|
||||
inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NOGUNS,TRAIT_NOHUNGER,TRAIT_NOBREATH)
|
||||
mutanttongue = /obj/item/organ/tongue/abductor
|
||||
|
||||
/datum/species/abductor/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
. = ..()
|
||||
var/datum/atom_hud/abductor_hud = GLOB.huds[DATA_HUD_ABDUCTOR]
|
||||
abductor_hud.add_hud_to(C)
|
||||
|
||||
/datum/species/abductor/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
var/datum/atom_hud/abductor_hud = GLOB.huds[DATA_HUD_ABDUCTOR]
|
||||
abductor_hud.remove_hud_from(C)
|
||||
@@ -1,24 +0,0 @@
|
||||
/datum/species/android
|
||||
name = "Android"
|
||||
id = "android"
|
||||
say_mod = "states"
|
||||
species_traits = list(NOBLOOD,NOGENITALS,NOAROUSAL)
|
||||
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_NOFIRE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_LIMBATTACHMENT)
|
||||
inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID)
|
||||
meat = null
|
||||
gib_types = /obj/effect/gibspawner/robot
|
||||
damage_overlay_type = "synth"
|
||||
mutanttongue = /obj/item/organ/tongue/robot
|
||||
limbs_id = "synth"
|
||||
|
||||
/datum/species/android/on_species_gain(mob/living/carbon/C)
|
||||
. = ..()
|
||||
for(var/X in C.bodyparts)
|
||||
var/obj/item/bodypart/O = X
|
||||
O.change_bodypart_status(BODYPART_ROBOTIC, FALSE, TRUE)
|
||||
|
||||
/datum/species/android/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
for(var/X in C.bodyparts)
|
||||
var/obj/item/bodypart/O = X
|
||||
O.change_bodypart_status(BODYPART_ORGANIC,FALSE, TRUE)
|
||||
@@ -1,145 +0,0 @@
|
||||
/datum/species/angel
|
||||
name = "Angel"
|
||||
id = "angel"
|
||||
default_color = "FFFFFF"
|
||||
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS)
|
||||
mutant_bodyparts = list("wings")
|
||||
default_features = list("mcolor" = "FFF", "tail_human" = "None", "ears" = "None", "wings" = "Angel")
|
||||
use_skintones = 1
|
||||
no_equip = list(SLOT_BACK)
|
||||
blacklisted = 1
|
||||
limbs_id = "human"
|
||||
skinned_type = /obj/item/stack/sheet/animalhide/human
|
||||
|
||||
var/datum/action/innate/flight/fly
|
||||
|
||||
/datum/species/angel/on_species_gain(mob/living/carbon/human/H, datum/species/old_species)
|
||||
..()
|
||||
if(H.dna && H.dna.species && (H.dna.features["wings"] != "Angel"))
|
||||
if(!("wings" in H.dna.species.mutant_bodyparts))
|
||||
H.dna.species.mutant_bodyparts |= "wings"
|
||||
H.dna.features["wings"] = "Angel"
|
||||
H.update_body()
|
||||
if(ishuman(H) && !fly)
|
||||
fly = new
|
||||
fly.Grant(H)
|
||||
ADD_TRAIT(H, TRAIT_HOLY, SPECIES_TRAIT)
|
||||
|
||||
/datum/species/angel/on_species_loss(mob/living/carbon/human/H)
|
||||
if(fly)
|
||||
fly.Remove(H)
|
||||
if(H.movement_type & FLYING)
|
||||
H.setMovetype(H.movement_type & ~FLYING)
|
||||
ToggleFlight(H,0)
|
||||
if(H.dna && H.dna.species && (H.dna.features["wings"] == "Angel"))
|
||||
if("wings" in H.dna.species.mutant_bodyparts)
|
||||
H.dna.species.mutant_bodyparts -= "wings"
|
||||
H.dna.features["wings"] = "None"
|
||||
H.update_body()
|
||||
REMOVE_TRAIT(H, TRAIT_HOLY, SPECIES_TRAIT)
|
||||
..()
|
||||
|
||||
/datum/species/angel/spec_life(mob/living/carbon/human/H)
|
||||
HandleFlight(H)
|
||||
|
||||
/datum/species/angel/proc/HandleFlight(mob/living/carbon/human/H)
|
||||
if(H.movement_type & FLYING)
|
||||
if(!CanFly(H))
|
||||
ToggleFlight(H,0)
|
||||
return 0
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
|
||||
/datum/species/angel/proc/CanFly(mob/living/carbon/human/H)
|
||||
if(H.stat || H.IsStun() || H.IsKnockdown())
|
||||
return 0
|
||||
if(H.wear_suit && ((H.wear_suit.flags_inv & HIDEJUMPSUIT) && (!H.wear_suit.species_exception || !is_type_in_list(src, H.wear_suit.species_exception)))) //Jumpsuits have tail holes, so it makes sense they have wing holes too
|
||||
to_chat(H, "Your suit blocks your wings from extending!")
|
||||
return 0
|
||||
var/turf/T = get_turf(H)
|
||||
if(!T)
|
||||
return 0
|
||||
|
||||
var/datum/gas_mixture/environment = T.return_air()
|
||||
if(environment && !(environment.return_pressure() > 30))
|
||||
to_chat(H, "<span class='warning'>The atmosphere is too thin for you to fly!</span>")
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
|
||||
/datum/action/innate/flight
|
||||
name = "Toggle Flight"
|
||||
check_flags = AB_CHECK_CONSCIOUS|AB_CHECK_STUN
|
||||
icon_icon = 'icons/mob/actions/actions_items.dmi'
|
||||
button_icon_state = "flight"
|
||||
|
||||
/datum/action/innate/flight/Activate()
|
||||
var/mob/living/carbon/human/H = owner
|
||||
var/datum/species/angel/A = H.dna.species
|
||||
if(A.CanFly(H))
|
||||
if(H.movement_type & FLYING)
|
||||
to_chat(H, "<span class='notice'>You settle gently back onto the ground...</span>")
|
||||
A.ToggleFlight(H,0)
|
||||
H.update_canmove()
|
||||
else
|
||||
to_chat(H, "<span class='notice'>You beat your wings and begin to hover gently above the ground...</span>")
|
||||
H.resting = 0
|
||||
A.ToggleFlight(H,1)
|
||||
H.update_canmove()
|
||||
|
||||
/datum/species/angel/proc/flyslip(mob/living/carbon/human/H)
|
||||
var/obj/buckled_obj
|
||||
if(H.buckled)
|
||||
buckled_obj = H.buckled
|
||||
|
||||
to_chat(H, "<span class='notice'>Your wings spazz out and launch you!</span>")
|
||||
|
||||
playsound(H.loc, 'sound/misc/slip.ogg', 50, 1, -3)
|
||||
|
||||
for(var/obj/item/I in H.held_items)
|
||||
H.accident(I)
|
||||
|
||||
var/olddir = H.dir
|
||||
|
||||
H.stop_pulling()
|
||||
if(buckled_obj)
|
||||
buckled_obj.unbuckle_mob(H)
|
||||
step(buckled_obj, olddir)
|
||||
else
|
||||
for(var/i=1, i<5, i++)
|
||||
spawn (i)
|
||||
step(H, olddir)
|
||||
H.spin(1,1)
|
||||
return 1
|
||||
|
||||
|
||||
/datum/species/angel/spec_stun(mob/living/carbon/human/H,amount)
|
||||
if(H.movement_type & FLYING)
|
||||
ToggleFlight(H,0)
|
||||
flyslip(H)
|
||||
. = ..()
|
||||
|
||||
/datum/species/angel/negates_gravity(mob/living/carbon/human/H)
|
||||
if(H.movement_type & FLYING)
|
||||
return 1
|
||||
|
||||
/datum/species/angel/space_move(mob/living/carbon/human/H)
|
||||
if(H.movement_type & FLYING)
|
||||
return 1
|
||||
|
||||
/datum/species/angel/proc/ToggleFlight(mob/living/carbon/human/H,flight)
|
||||
if(flight && CanFly(H))
|
||||
stunmod = 2
|
||||
speedmod = -0.35
|
||||
H.setMovetype(H.movement_type | FLYING)
|
||||
override_float = TRUE
|
||||
H.pass_flags |= PASSTABLE
|
||||
H.OpenWings()
|
||||
else
|
||||
stunmod = 1
|
||||
speedmod = 0
|
||||
H.setMovetype(H.movement_type & ~FLYING)
|
||||
override_float = FALSE
|
||||
H.pass_flags &= ~PASSTABLE
|
||||
H.CloseWings()
|
||||
@@ -1,65 +0,0 @@
|
||||
/datum/species/insect
|
||||
name = "Anthromorphic Insect"
|
||||
id = "insect"
|
||||
say_mod = "flutters"
|
||||
default_color = "00FF00"
|
||||
species_traits = list(LIPS,NOEYES,HAIR,FACEHAIR,MUTCOLORS,HORNCOLOR,WINGCOLOR)
|
||||
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_BUG)
|
||||
mutant_bodyparts = list("mam_ears", "mam_snout", "mam_tail", "taur", "insect_wings", "mam_snouts", "insect_fluff","horns")
|
||||
default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None",
|
||||
"insect_wings" = "None", "insect_fluff" = "None", "mam_snouts" = "None", "taur" = "None","horns" = "None")
|
||||
attack_verb = "slash"
|
||||
attack_sound = 'sound/weapons/slash.ogg'
|
||||
miss_sound = 'sound/weapons/slashmiss.ogg'
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/insect
|
||||
liked_food = VEGETABLES | DAIRY
|
||||
disliked_food = FRUIT | GROSS
|
||||
toxic_food = MEAT | RAW
|
||||
mutanteyes = /obj/item/organ/eyes/insect
|
||||
should_draw_citadel = TRUE
|
||||
exotic_bloodtype = "BUG"
|
||||
|
||||
/datum/species/insect/on_species_gain(mob/living/carbon/C)
|
||||
. = ..()
|
||||
if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
if(!H.dna.features["insect_wings"])
|
||||
H.dna.features["insect_wings"] = "[(H.client && H.client.prefs && LAZYLEN(H.client.prefs.features) && H.client.prefs.features["insect_wings"]) ? H.client.prefs.features["insect_wings"] : "None"]"
|
||||
handle_mutant_bodyparts(H)
|
||||
|
||||
/datum/species/insect/random_name(gender,unique,lastname)
|
||||
if(unique)
|
||||
return random_unique_moth_name()
|
||||
|
||||
var/randname = moth_name()
|
||||
|
||||
if(lastname)
|
||||
randname += " [lastname]"
|
||||
|
||||
return randname
|
||||
|
||||
/datum/species/insect/handle_fire(mob/living/carbon/human/H, no_protection = FALSE)
|
||||
..()
|
||||
if(H.dna.features["insect_wings"] != "Burnt Off" && H.dna.features["insect_wings"] != "None" && H.bodytemperature >= 800 && H.fire_stacks > 0) //do not go into the extremely hot light. you will not survive
|
||||
to_chat(H, "<span class='danger'>Your precious wings burn to a crisp!</span>")
|
||||
if(H.dna.features["insect_wings"] != "None")
|
||||
H.dna.features["insect_wings"] = "Burnt Off"
|
||||
handle_mutant_bodyparts(H)
|
||||
|
||||
/datum/species/insect/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
|
||||
. = ..()
|
||||
if(chem.id == "pestkiller")
|
||||
H.adjustToxLoss(3)
|
||||
H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
|
||||
|
||||
/datum/species/insect/check_weakness(obj/item/weapon, mob/living/attacker)
|
||||
if(istype(weapon, /obj/item/melee/flyswatter))
|
||||
return 9 //flyswatters deal 10x damage to insects
|
||||
return 0
|
||||
|
||||
/datum/species/insect/space_move(mob/living/carbon/human/H)
|
||||
. = ..()
|
||||
if(H.loc && !isspaceturf(H.loc) && (H.dna.features["insect_wings"] != "Burnt Off" && H.dna.features["insect_wings"] != "None"))
|
||||
var/datum/gas_mixture/current = H.loc.return_air()
|
||||
if(current && (current.return_pressure() >= ONE_ATMOSPHERE*0.85)) //as long as there's reasonable pressure and no gravity, flight is possible
|
||||
return TRUE
|
||||
@@ -1,21 +0,0 @@
|
||||
/datum/species/corporate
|
||||
name = "Corporate Agent"
|
||||
id = "agent"
|
||||
hair_alpha = 0
|
||||
say_mod = "declares"
|
||||
speedmod = -2//Fast
|
||||
brutemod = 0.7//Tough against firearms
|
||||
burnmod = 0.65//Tough against lasers
|
||||
coldmod = 0
|
||||
heatmod = 0.5//it's a little tough to burn them to death not as hard though.
|
||||
punchdamagelow = 20
|
||||
punchdamagehigh = 30//they are inhumanly strong
|
||||
punchstunthreshold = 25
|
||||
attack_verb = "smash"
|
||||
attack_sound = 'sound/weapons/resonator_blast.ogg'
|
||||
blacklisted = 1
|
||||
use_skintones = 0
|
||||
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
|
||||
@@ -1,171 +0,0 @@
|
||||
/datum/species/dullahan
|
||||
name = "Dullahan"
|
||||
id = "dullahan"
|
||||
default_color = "FFFFFF"
|
||||
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS)
|
||||
inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH)
|
||||
default_features = list("mcolor" = "FFF", "tail_human" = "None", "ears" = "None", "wings" = "None")
|
||||
use_skintones = TRUE
|
||||
mutant_brain = /obj/item/organ/brain/dullahan
|
||||
mutanteyes = /obj/item/organ/eyes/dullahan
|
||||
mutanttongue = /obj/item/organ/tongue/dullahan
|
||||
mutantears = /obj/item/organ/ears/dullahan
|
||||
blacklisted = TRUE
|
||||
limbs_id = "human"
|
||||
skinned_type = /obj/item/stack/sheet/animalhide/human
|
||||
var/pumpkin = FALSE
|
||||
|
||||
var/obj/item/dullahan_relay/myhead
|
||||
|
||||
/datum/species/dullahan/pumpkin
|
||||
name = "Pumpkin Head Dullahan"
|
||||
id = "pumpkindullahan"
|
||||
pumpkin = TRUE
|
||||
|
||||
/datum/species/dullahan/check_roundstart_eligible()
|
||||
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/species/dullahan/on_species_gain(mob/living/carbon/human/H, datum/species/old_species)
|
||||
. = ..()
|
||||
DISABLE_BITFIELD(H.flags_1, HEAR_1)
|
||||
var/obj/item/bodypart/head/head = H.get_bodypart(BODY_ZONE_HEAD)
|
||||
if(head)
|
||||
if(pumpkin)//Pumpkinhead!
|
||||
head.animal_origin = 100
|
||||
head.icon = 'icons/obj/clothing/hats.dmi'
|
||||
head.icon_state = "hardhat1_pumpkin_j"
|
||||
head.custom_head = TRUE
|
||||
head.drop_limb()
|
||||
if(!QDELETED(head)) //drop_limb() deletes the limb if it's no drop location and dummy humans used for rendering icons are located in nullspace. Do the math.
|
||||
head.throwforce = 25
|
||||
myhead = new /obj/item/dullahan_relay (head, H)
|
||||
H.put_in_hands(head)
|
||||
var/obj/item/organ/eyes/E = H.getorganslot(ORGAN_SLOT_EYES)
|
||||
for(var/datum/action/item_action/organ_action/OA in E.actions)
|
||||
OA.Trigger()
|
||||
|
||||
/datum/species/dullahan/on_species_loss(mob/living/carbon/human/H)
|
||||
ENABLE_BITFIELD(H.flags_1, HEAR_1)
|
||||
H.reset_perspective(H)
|
||||
if(myhead)
|
||||
var/obj/item/dullahan_relay/DR = myhead
|
||||
myhead = null
|
||||
DR.owner = null
|
||||
qdel(DR)
|
||||
H.regenerate_limb(BODY_ZONE_HEAD,FALSE)
|
||||
..()
|
||||
|
||||
/datum/species/dullahan/spec_life(mob/living/carbon/human/H)
|
||||
if(QDELETED(myhead))
|
||||
myhead = null
|
||||
H.gib()
|
||||
var/obj/item/bodypart/head/head2 = H.get_bodypart(BODY_ZONE_HEAD)
|
||||
if(head2)
|
||||
myhead = null
|
||||
H.gib()
|
||||
|
||||
/datum/species/dullahan/proc/update_vision_perspective(mob/living/carbon/human/H)
|
||||
var/obj/item/organ/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES)
|
||||
if(eyes)
|
||||
H.update_tint()
|
||||
if(eyes.tint)
|
||||
H.reset_perspective(H)
|
||||
else
|
||||
H.reset_perspective(myhead)
|
||||
|
||||
/obj/item/organ/brain/dullahan
|
||||
decoy_override = TRUE
|
||||
organ_flags = ORGAN_NO_SPOIL//Do not decay
|
||||
|
||||
/obj/item/organ/tongue/dullahan
|
||||
zone = "abstract"
|
||||
modifies_speech = TRUE
|
||||
|
||||
/obj/item/organ/tongue/dullahan/handle_speech(datum/source, list/speech_args)
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if(isdullahan(H))
|
||||
var/datum/species/dullahan/D = H.dna.species
|
||||
if(isobj(D.myhead.loc))
|
||||
var/obj/O = D.myhead.loc
|
||||
O.say(speech_args[SPEECH_MESSAGE])
|
||||
speech_args[SPEECH_MESSAGE] = ""
|
||||
|
||||
/obj/item/organ/ears/dullahan
|
||||
zone = "abstract"
|
||||
|
||||
/obj/item/organ/eyes/dullahan
|
||||
name = "head vision"
|
||||
desc = "An abstraction."
|
||||
actions_types = list(/datum/action/item_action/organ_action/dullahan)
|
||||
zone = "abstract"
|
||||
tint = INFINITY // used to switch the vision perspective to the head on species_gain().
|
||||
|
||||
/datum/action/item_action/organ_action/dullahan
|
||||
name = "Toggle Perspective"
|
||||
desc = "Switch between seeing normally from your head, or blindly from your body."
|
||||
|
||||
/datum/action/item_action/organ_action/dullahan/Trigger()
|
||||
. = ..()
|
||||
var/obj/item/organ/eyes/dullahan/DE = target
|
||||
if(DE.tint)
|
||||
DE.tint = 0
|
||||
else
|
||||
DE.tint = INFINITY
|
||||
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if(isdullahan(H))
|
||||
var/datum/species/dullahan/D = H.dna.species
|
||||
D.update_vision_perspective(H)
|
||||
|
||||
/obj/item/dullahan_relay
|
||||
name = "dullahan relay"
|
||||
var/mob/living/owner
|
||||
flags_1 = HEAR_1
|
||||
|
||||
/obj/item/dullahan_relay/Initialize(mapload, mob/living/carbon/human/new_owner)
|
||||
. = ..()
|
||||
if(!new_owner)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
owner = new_owner
|
||||
START_PROCESSING(SSobj, src)
|
||||
RegisterSignal(owner, COMSIG_MOB_EXAMINATE, .proc/examinate_check)
|
||||
RegisterSignal(src, COMSIG_ATOM_HEARER_IN_VIEW, .proc/include_owner)
|
||||
RegisterSignal(owner, COMSIG_LIVING_REGENERATE_LIMBS, .proc/unlist_head)
|
||||
RegisterSignal(owner, COMSIG_LIVING_FULLY_HEAL, .proc/retrieve_head)
|
||||
|
||||
/obj/item/dullahan_relay/proc/examinate_check(mob/source, atom/A)
|
||||
if(source.client.eye == src && ((A in view(source.client.view, src)) || (isturf(A) && source.sight & SEE_TURFS) || (ismob(A) && source.sight & SEE_MOBS) || (isobj(A) && source.sight & SEE_OBJS)))
|
||||
return COMPONENT_ALLOW_EXAMINE
|
||||
|
||||
/obj/item/dullahan_relay/proc/include_owner(datum/source, list/processing_list, list/hearers)
|
||||
if(!QDELETED(owner))
|
||||
hearers += owner
|
||||
|
||||
/obj/item/dullahan_relay/proc/unlist_head(datum/source, noheal = FALSE, list/excluded_limbs)
|
||||
excluded_limbs |= BODY_ZONE_HEAD // So we don't gib when regenerating limbs.
|
||||
|
||||
/obj/item/dullahan_relay/proc/retrieve_head(datum/source, admin_revive = FALSE)
|
||||
if(admin_revive) //retrieving the owner's head for ahealing purposes.
|
||||
var/obj/item/bodypart/head/H = loc
|
||||
var/turf/T = get_turf(owner)
|
||||
if(H && istype(H) && T && !(H in owner.GetAllContents()))
|
||||
H.forceMove(T)
|
||||
|
||||
/obj/item/dullahan_relay/process()
|
||||
if(!istype(loc, /obj/item/bodypart/head) || QDELETED(owner))
|
||||
. = PROCESS_KILL
|
||||
qdel(src)
|
||||
|
||||
/obj/item/dullahan_relay/Destroy()
|
||||
if(!QDELETED(owner))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if(isdullahan(H))
|
||||
var/datum/species/dullahan/D = H.dna.species
|
||||
D.myhead = null
|
||||
owner.gib()
|
||||
owner = null
|
||||
..()
|
||||
@@ -1,131 +0,0 @@
|
||||
//Subtype of human
|
||||
/datum/species/human/felinid
|
||||
name = "Felinid"
|
||||
id = "felinid"
|
||||
limbs_id = "human"
|
||||
|
||||
mutant_bodyparts = list("mam_ears", "mam_tail", "deco_wings")
|
||||
default_features = list("mcolor" = "FFF", "mam_tail" = "Cat", "mam_ears" = "Cat", "wings" = "None", "deco_wings" = "None")
|
||||
|
||||
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 ("mam_tail" in mutant_bodyparts) || ("mam_waggingtail" in mutant_bodyparts)
|
||||
|
||||
/datum/species/human/felinid/is_wagging_tail(mob/living/carbon/human/H)
|
||||
return ("mam_waggingtail" in mutant_bodyparts)
|
||||
|
||||
/datum/species/human/felinid/start_wagging_tail(mob/living/carbon/human/H)
|
||||
if("mam_tail" in mutant_bodyparts)
|
||||
mutant_bodyparts -= "mam_tail"
|
||||
mutant_bodyparts |= "mam_waggingtail"
|
||||
H.update_body()
|
||||
|
||||
/datum/species/human/felinid/stop_wagging_tail(mob/living/carbon/human/H)
|
||||
if("mam_waggingtail" in mutant_bodyparts)
|
||||
mutant_bodyparts -= "mam_waggingtail"
|
||||
mutant_bodyparts |= "mam_tail"
|
||||
H.update_body()
|
||||
|
||||
/datum/species/human/felinid/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load)
|
||||
if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
if(!pref_load) //Hah! They got forcefully purrbation'd. Force default felinid parts on them if they have no mutant parts in those areas!
|
||||
if(H.dna.features["mam_tail"] == "None")
|
||||
H.dna.features["mam_tail"] = "Cat"
|
||||
if(H.dna.features["mam_ears"] == "None")
|
||||
H.dna.features["mam_ears"] = "Cat"
|
||||
if(H.dna.features["mam_ears"] == "Cat")
|
||||
var/obj/item/organ/ears/cat/ears = new
|
||||
ears.Insert(H, drop_if_replaced = FALSE)
|
||||
else
|
||||
mutantears = /obj/item/organ/ears
|
||||
if(H.dna.features["mam_tail"] == "Cat")
|
||||
var/obj/item/organ/tail/cat/tail = new
|
||||
tail.Insert(H, drop_if_replaced = FALSE)
|
||||
else
|
||||
mutanttail = null
|
||||
return ..()
|
||||
|
||||
/datum/species/human/felinid/on_species_loss(mob/living/carbon/H, datum/species/new_species, pref_load)
|
||||
var/obj/item/organ/ears/cat/ears = H.getorgan(/obj/item/organ/ears/cat)
|
||||
var/obj/item/organ/tail/cat/tail = H.getorgan(/obj/item/organ/tail/cat)
|
||||
|
||||
if(ears)
|
||||
var/obj/item/organ/ears/NE
|
||||
if(new_species && new_species.mutantears)
|
||||
// Roundstart cat ears override new_species.mutantears, reset it here.
|
||||
new_species.mutantears = initial(new_species.mutantears)
|
||||
if(new_species.mutantears)
|
||||
NE = new new_species.mutantears
|
||||
if(!NE)
|
||||
// Go with default ears
|
||||
NE = new /obj/item/organ/ears
|
||||
NE.Insert(H, drop_if_replaced = FALSE)
|
||||
|
||||
if(tail)
|
||||
var/obj/item/organ/tail/NT
|
||||
if(new_species && new_species.mutanttail)
|
||||
// Roundstart cat tail overrides new_species.mutanttail, reset it here.
|
||||
new_species.mutanttail = initial(new_species.mutanttail)
|
||||
if(new_species.mutanttail)
|
||||
NT = new new_species.mutanttail
|
||||
if(NT)
|
||||
NT.Insert(H, drop_if_replaced = FALSE)
|
||||
else
|
||||
tail.Remove(H)
|
||||
|
||||
/proc/mass_purrbation()
|
||||
for(var/M in GLOB.mob_list)
|
||||
if(ishumanbasic(M))
|
||||
purrbation_apply(M)
|
||||
CHECK_TICK
|
||||
|
||||
/proc/mass_remove_purrbation()
|
||||
for(var/M in GLOB.mob_list)
|
||||
if(ishumanbasic(M))
|
||||
purrbation_remove(M)
|
||||
CHECK_TICK
|
||||
|
||||
/proc/purrbation_toggle(mob/living/carbon/human/H, silent = FALSE)
|
||||
if(!ishumanbasic(H))
|
||||
return
|
||||
if(!iscatperson(H))
|
||||
purrbation_apply(H, silent)
|
||||
. = TRUE
|
||||
else
|
||||
purrbation_remove(H, silent)
|
||||
. = FALSE
|
||||
|
||||
/proc/purrbation_apply(mob/living/carbon/human/H, silent = FALSE)
|
||||
if(!ishuman(H) || iscatperson(H))
|
||||
return
|
||||
H.set_species(/datum/species/human/felinid)
|
||||
|
||||
if(!silent)
|
||||
to_chat(H, "Something is nya~t right.")
|
||||
playsound(get_turf(H), 'sound/effects/meow1.ogg', 50, 1, -1)
|
||||
|
||||
/proc/purrbation_remove(mob/living/carbon/human/H, silent = FALSE)
|
||||
if(!ishuman(H) || !iscatperson(H))
|
||||
return
|
||||
|
||||
H.set_species(/datum/species/human)
|
||||
|
||||
if(!silent)
|
||||
to_chat(H, "You are no longer a cat.")
|
||||
@@ -1,36 +0,0 @@
|
||||
/datum/species/fly
|
||||
name = "Anthromorphic Fly"
|
||||
id = "fly"
|
||||
say_mod = "buzzes"
|
||||
species_traits = list(NOEYES)
|
||||
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_BUG)
|
||||
mutanttongue = /obj/item/organ/tongue/fly
|
||||
mutantliver = /obj/item/organ/liver/fly
|
||||
mutantstomach = /obj/item/organ/stomach/fly
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/fly
|
||||
disliked_food = null
|
||||
liked_food = GROSS
|
||||
exotic_bloodtype = "BUG"
|
||||
|
||||
/datum/species/fly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
|
||||
if(chem.id == "pestkiller")
|
||||
H.adjustToxLoss(3)
|
||||
H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
|
||||
return 1
|
||||
|
||||
|
||||
/datum/species/fly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
|
||||
if(istype(chem, /datum/reagent/consumable))
|
||||
var/datum/reagent/consumable/nutri_check = chem
|
||||
if(nutri_check.nutriment_factor > 0)
|
||||
var/turf/pos = get_turf(H)
|
||||
H.vomit(0, FALSE, FALSE, 2, TRUE)
|
||||
playsound(pos, 'sound/effects/splat.ogg', 50, 1)
|
||||
H.visible_message("<span class='danger'>[H] vomits on the floor!</span>", \
|
||||
"<span class='userdanger'>You throw up on the floor!</span>")
|
||||
..()
|
||||
|
||||
/datum/species/fly/check_weakness(obj/item/weapon, mob/living/attacker)
|
||||
if(istype(weapon, /obj/item/melee/flyswatter))
|
||||
return 29 //Flyswatters deal 30x damage to flypeople.
|
||||
return 0
|
||||
@@ -1,99 +0,0 @@
|
||||
/datum/species/mammal
|
||||
name = "Anthromorph"
|
||||
id = "mammal"
|
||||
default_color = "4B4B4B"
|
||||
should_draw_citadel = TRUE
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR,HORNCOLOR,WINGCOLOR)
|
||||
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
|
||||
mutant_bodyparts = list("mam_tail", "mam_ears", "mam_body_markings", "mam_snouts", "deco_wings", "taur", "horns", "legs")
|
||||
default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "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'
|
||||
miss_sound = 'sound/weapons/slashmiss.ogg'
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/mammal
|
||||
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 ("mam_tail" in mutant_bodyparts) || ("mam_waggingtail" in mutant_bodyparts)
|
||||
|
||||
/datum/species/mammal/is_wagging_tail(mob/living/carbon/human/H)
|
||||
return ("mam_waggingtail" in mutant_bodyparts)
|
||||
|
||||
/datum/species/mammal/start_wagging_tail(mob/living/carbon/human/H)
|
||||
if("mam_tail" in mutant_bodyparts)
|
||||
mutant_bodyparts -= "mam_tail"
|
||||
mutant_bodyparts |= "mam_waggingtail"
|
||||
H.update_body()
|
||||
|
||||
/datum/species/mammal/stop_wagging_tail(mob/living/carbon/human/H)
|
||||
if("mam_waggingtail" in mutant_bodyparts)
|
||||
mutant_bodyparts -= "mam_waggingtail"
|
||||
mutant_bodyparts |= "mam_tail"
|
||||
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"
|
||||
should_draw_citadel = TRUE
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,LIPS)
|
||||
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
|
||||
mutant_bodyparts = list("xenotail", "xenohead", "xenodorsal", "mam_body_markings", "taur", "legs")
|
||||
default_features = 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
|
||||
|
||||
/datum/species/xeno/on_species_gain(mob/living/carbon/human/C, datum/species/old_species)
|
||||
if(("legs" in C.dna.species.mutant_bodyparts) && (C.dna.features["legs"] == "Digitigrade" || C.dna.features["legs"] == "Avian"))
|
||||
species_traits += DIGITIGRADE
|
||||
if(DIGITIGRADE in species_traits)
|
||||
C.Digitigrade_Leg_Swap(FALSE)
|
||||
. = ..()
|
||||
|
||||
/datum/species/xeno/on_species_loss(mob/living/carbon/human/C, datum/species/new_species)
|
||||
if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Plantigrade")
|
||||
species_traits -= DIGITIGRADE
|
||||
if(DIGITIGRADE in species_traits)
|
||||
C.Digitigrade_Leg_Swap(TRUE)
|
||||
. = ..()
|
||||
|
||||
//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
|
||||
no_vore = TRUE
|
||||
|
||||
/mob/living/carbon/human/vore
|
||||
devourable = TRUE
|
||||
digestable = TRUE
|
||||
feeding = TRUE
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,42 +0,0 @@
|
||||
/datum/species/human
|
||||
name = "Human"
|
||||
id = "human"
|
||||
default_color = "FFFFFF"
|
||||
|
||||
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS_PARTSONLY,WINGCOLOR)
|
||||
mutant_bodyparts = list("ears", "tail_human", "wings", "taur", "deco_wings") // CITADEL EDIT gives humans snowflake parts
|
||||
default_features = list("mcolor" = "FFF", "mcolor2" = "FFF","mcolor3" = "FFF","tail_human" = "None", "ears" = "None", "wings" = "None", "taur" = "None", "deco_wings" = "None")
|
||||
use_skintones = 1
|
||||
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.
|
||||
|
||||
/datum/species/human/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
|
||||
/datum/species/human/spec_stun(mob/living/carbon/human/H,amount)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
. = ..()
|
||||
|
||||
/datum/species/human/can_wag_tail(mob/living/carbon/human/H)
|
||||
return ("tail_human" in mutant_bodyparts) || ("waggingtail_human" in mutant_bodyparts)
|
||||
|
||||
/datum/species/human/is_wagging_tail(mob/living/carbon/human/H)
|
||||
return ("waggingtail_human" in mutant_bodyparts)
|
||||
|
||||
/datum/species/human/start_wagging_tail(mob/living/carbon/human/H)
|
||||
if("tail_human" in mutant_bodyparts)
|
||||
mutant_bodyparts -= "tail_human"
|
||||
mutant_bodyparts |= "waggingtail_human"
|
||||
H.update_body()
|
||||
|
||||
/datum/species/human/stop_wagging_tail(mob/living/carbon/human/H)
|
||||
if("waggingtail_human" in mutant_bodyparts)
|
||||
mutant_bodyparts -= "waggingtail_human"
|
||||
mutant_bodyparts |= "tail_human"
|
||||
H.update_body()
|
||||
@@ -1,44 +0,0 @@
|
||||
/datum/species/ipc
|
||||
name = "I.P.C."
|
||||
id = "ipc"
|
||||
say_mod = "beeps"
|
||||
default_color = "00FF00"
|
||||
should_draw_citadel = TRUE
|
||||
blacklisted = 0
|
||||
sexes = 0
|
||||
species_traits = list(MUTCOLORS,NOEYES,NOTRANSSTING)
|
||||
inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID)
|
||||
mutant_bodyparts = list("ipc_screen", "ipc_antenna")
|
||||
default_features = list("ipc_screen" = "Blank", "ipc_antenna" = "None")
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ipc
|
||||
gib_types = list(/obj/effect/gibspawner/ipc, /obj/effect/gibspawner/ipc/bodypartless)
|
||||
mutanttongue = /obj/item/organ/tongue/robot/ipc
|
||||
mutant_heart = /obj/item/organ/heart/ipc
|
||||
exotic_bloodtype = "HF"
|
||||
|
||||
var/datum/action/innate/monitor_change/screen
|
||||
|
||||
/datum/species/ipc/on_species_gain(mob/living/carbon/human/C)
|
||||
if(isipcperson(C) && !screen)
|
||||
screen = new
|
||||
screen.Grant(C)
|
||||
..()
|
||||
|
||||
/datum/species/ipc/on_species_loss(mob/living/carbon/human/C)
|
||||
if(screen)
|
||||
screen.Remove(C)
|
||||
..()
|
||||
|
||||
/datum/action/innate/monitor_change
|
||||
name = "Screen Change"
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
icon_icon = 'icons/mob/actions/actions_silicon.dmi'
|
||||
button_icon_state = "drone_vision"
|
||||
|
||||
/datum/action/innate/monitor_change/Activate()
|
||||
var/mob/living/carbon/human/H = owner
|
||||
var/new_ipc_screen = input(usr, "Choose your character's screen:", "Monitor Display") as null|anything in GLOB.ipc_screens_list
|
||||
if(!new_ipc_screen)
|
||||
return
|
||||
H.dna.features["ipc_screen"] = new_ipc_screen
|
||||
H.update_body()
|
||||
@@ -1,986 +0,0 @@
|
||||
/datum/species/jelly
|
||||
// Entirely alien beings that seem to be made entirely out of gel. They have three eyes and a skeleton visible within them.
|
||||
name = "Xenobiological Jelly Entity"
|
||||
id = "jelly"
|
||||
default_color = "00FF90"
|
||||
say_mod = "chirps"
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,WINGCOLOR)
|
||||
mutantlungs = /obj/item/organ/lungs/slime
|
||||
mutant_heart = /obj/item/organ/heart/slime
|
||||
mutant_bodyparts = list("mam_tail", "mam_ears", "mam_snouts", "taur", "deco_wings") //CIT CHANGE
|
||||
default_features = list("mcolor" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_snouts" = "None", "taur" = "None", "deco_wings" = "None") //CIT CHANGE
|
||||
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 = "jellyblood"
|
||||
exotic_bloodtype = "GEL"
|
||||
damage_overlay_type = ""
|
||||
var/datum/action/innate/regenerate_limbs/regenerate_limbs
|
||||
var/datum/action/innate/slime_change/slime_change //CIT CHANGE
|
||||
liked_food = TOXIC | MEAT
|
||||
toxic_food = null
|
||||
coldmod = 6 // = 3x cold damage
|
||||
heatmod = 0.5 // = 1/4x heat damage
|
||||
burnmod = 0.5 // = 1/2x generic burn damage
|
||||
|
||||
/datum/species/jelly/on_species_loss(mob/living/carbon/C)
|
||||
if(regenerate_limbs)
|
||||
regenerate_limbs.Remove(C)
|
||||
if(slime_change) //CIT CHANGE
|
||||
slime_change.Remove(C) //CIT CHANGE
|
||||
C.remove_language(/datum/language/slime)
|
||||
C.faction -= "slime"
|
||||
..()
|
||||
C.faction -= "slime"
|
||||
|
||||
/datum/species/jelly/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
..()
|
||||
C.grant_language(/datum/language/slime)
|
||||
if(ishuman(C))
|
||||
regenerate_limbs = new
|
||||
regenerate_limbs.Grant(C)
|
||||
slime_change = new //CIT CHANGE
|
||||
slime_change.Grant(C) //CIT CHANGE
|
||||
C.faction |= "slime"
|
||||
|
||||
/datum/species/jelly/spec_life(mob/living/carbon/human/H)
|
||||
if(H.stat == DEAD) //can't farm slime jelly from a dead slime/jelly person indefinitely
|
||||
return
|
||||
if(!H.blood_volume)
|
||||
H.blood_volume += 5
|
||||
H.adjustBruteLoss(5)
|
||||
to_chat(H, "<span class='danger'>You feel empty!</span>")
|
||||
|
||||
if(H.blood_volume < (BLOOD_VOLUME_NORMAL * H.blood_ratio))
|
||||
if(H.nutrition >= NUTRITION_LEVEL_STARVING)
|
||||
H.blood_volume += 3
|
||||
H.nutrition -= 2.5
|
||||
if(H.blood_volume < (BLOOD_VOLUME_OKAY*H.blood_ratio))
|
||||
if(prob(5))
|
||||
to_chat(H, "<span class='danger'>You feel drained!</span>")
|
||||
if(H.blood_volume < (BLOOD_VOLUME_BAD*H.blood_ratio))
|
||||
Cannibalize_Body(H)
|
||||
if(regenerate_limbs)
|
||||
regenerate_limbs.UpdateButtonIcon()
|
||||
|
||||
/datum/species/jelly/proc/Cannibalize_Body(mob/living/carbon/human/H)
|
||||
var/list/limbs_to_consume = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) - H.get_missing_limbs()
|
||||
var/obj/item/bodypart/consumed_limb
|
||||
if(!limbs_to_consume.len)
|
||||
H.losebreath++
|
||||
return
|
||||
if(H.get_num_legs(FALSE)) //Legs go before arms
|
||||
limbs_to_consume -= list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM)
|
||||
consumed_limb = H.get_bodypart(pick(limbs_to_consume))
|
||||
consumed_limb.drop_limb()
|
||||
to_chat(H, "<span class='userdanger'>Your [consumed_limb] is drawn back into your body, unable to maintain its shape!</span>")
|
||||
qdel(consumed_limb)
|
||||
H.blood_volume += 20
|
||||
|
||||
/datum/action/innate/regenerate_limbs
|
||||
name = "Regenerate Limbs"
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
button_icon_state = "slimeheal"
|
||||
icon_icon = 'icons/mob/actions/actions_slime.dmi'
|
||||
background_icon_state = "bg_alien"
|
||||
|
||||
/datum/action/innate/regenerate_limbs/IsAvailable()
|
||||
if(..())
|
||||
var/mob/living/carbon/human/H = owner
|
||||
var/list/limbs_to_heal = H.get_missing_limbs()
|
||||
if(limbs_to_heal.len < 1)
|
||||
return 0
|
||||
if(H.blood_volume >= (BLOOD_VOLUME_OKAY*H.blood_ratio)+40)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/action/innate/regenerate_limbs/Activate()
|
||||
var/mob/living/carbon/human/H = owner
|
||||
var/list/limbs_to_heal = H.get_missing_limbs()
|
||||
if(limbs_to_heal.len < 1)
|
||||
to_chat(H, "<span class='notice'>You feel intact enough as it is.</span>")
|
||||
return
|
||||
to_chat(H, "<span class='notice'>You focus intently on your missing [limbs_to_heal.len >= 2 ? "limbs" : "limb"]...</span>")
|
||||
if(H.blood_volume >= 40*limbs_to_heal.len+(BLOOD_VOLUME_OKAY*H.blood_ratio))
|
||||
H.regenerate_limbs()
|
||||
H.blood_volume -= 40*limbs_to_heal.len
|
||||
to_chat(H, "<span class='notice'>...and after a moment you finish reforming!</span>")
|
||||
return
|
||||
else if(H.blood_volume >= 40)//We can partially heal some limbs
|
||||
while(H.blood_volume >= (BLOOD_VOLUME_OKAY*H.blood_ratio)+40)
|
||||
var/healed_limb = pick(limbs_to_heal)
|
||||
H.regenerate_limb(healed_limb)
|
||||
limbs_to_heal -= healed_limb
|
||||
H.blood_volume -= 40
|
||||
to_chat(H, "<span class='warning'>...but there is not enough of you to fix everything! You must attain more mass to heal completely!</span>")
|
||||
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>")
|
||||
|
||||
////////////////////////////////////////////////////////SLIMEPEOPLE///////////////////////////////////////////////////////////////////
|
||||
|
||||
//Slime people are able to split like slimes, retaining a single mind that can swap between bodies at will, even after death.
|
||||
|
||||
/datum/species/jelly/slime
|
||||
name = "Xenobiological Slime Entity"
|
||||
id = "slime"
|
||||
default_color = "00FFFF"
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR)
|
||||
say_mod = "says"
|
||||
hair_color = "mutcolor"
|
||||
hair_alpha = 150
|
||||
ignored_by = list(/mob/living/simple_animal/slime)
|
||||
var/datum/action/innate/split_body/slime_split
|
||||
var/list/mob/living/carbon/bodies
|
||||
var/datum/action/innate/swap_body/swap_body
|
||||
|
||||
/datum/species/jelly/slime/on_species_loss(mob/living/carbon/C)
|
||||
if(slime_split)
|
||||
slime_split.Remove(C)
|
||||
if(swap_body)
|
||||
swap_body.Remove(C)
|
||||
bodies -= C // This means that the other bodies maintain a link
|
||||
// so if someone mindswapped into them, they'd still be shared.
|
||||
bodies = null
|
||||
C.blood_volume = min(C.blood_volume, (BLOOD_VOLUME_NORMAL*C.blood_ratio))
|
||||
..()
|
||||
|
||||
/datum/species/jelly/slime/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
..()
|
||||
if(ishuman(C))
|
||||
slime_split = new
|
||||
slime_split.Grant(C)
|
||||
swap_body = new
|
||||
swap_body.Grant(C)
|
||||
|
||||
if(!bodies || !bodies.len)
|
||||
bodies = list(C)
|
||||
else
|
||||
bodies |= C
|
||||
|
||||
/datum/species/jelly/slime/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
if(slime_split)
|
||||
if(!H.mind || !H.mind.active)
|
||||
return
|
||||
|
||||
var/list/available_bodies = (bodies - H)
|
||||
for(var/mob/living/L in available_bodies)
|
||||
if(!swap_body.can_swap(L))
|
||||
available_bodies -= L
|
||||
|
||||
if(!LAZYLEN(available_bodies))
|
||||
return
|
||||
|
||||
swap_body.swap_to_dupe(H.mind, pick(available_bodies))
|
||||
|
||||
//If you're cloned you get your body pool back
|
||||
/datum/species/jelly/slime/copy_properties_from(datum/species/jelly/slime/old_species)
|
||||
bodies = old_species.bodies
|
||||
|
||||
/datum/species/jelly/slime/spec_life(mob/living/carbon/human/H)
|
||||
if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
|
||||
if(prob(5))
|
||||
to_chat(H, "<span class='notice'>You feel very bloated!</span>")
|
||||
else if(H.nutrition >= NUTRITION_LEVEL_WELL_FED)
|
||||
H.blood_volume += 3
|
||||
H.nutrition -= 2.5
|
||||
|
||||
..()
|
||||
|
||||
/datum/action/innate/split_body
|
||||
name = "Split Body"
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
button_icon_state = "slimesplit"
|
||||
icon_icon = 'icons/mob/actions/actions_slime.dmi'
|
||||
background_icon_state = "bg_alien"
|
||||
|
||||
/datum/action/innate/split_body/IsAvailable()
|
||||
if(..())
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/action/innate/split_body/Activate()
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if(!isslimeperson(H))
|
||||
return
|
||||
CHECK_DNA_AND_SPECIES(H)
|
||||
H.visible_message("<span class='notice'>[owner] gains a look of \
|
||||
concentration while standing perfectly still.</span>",
|
||||
"<span class='notice'>You focus intently on moving your body while \
|
||||
standing perfectly still...</span>")
|
||||
|
||||
H.notransform = TRUE
|
||||
|
||||
if(do_after(owner, delay=60, needhand=FALSE, target=owner, progress=TRUE))
|
||||
if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
|
||||
make_dupe()
|
||||
else
|
||||
to_chat(H, "<span class='warning'>...but there is not enough of you to go around! You must attain more mass to split!</span>")
|
||||
else
|
||||
to_chat(H, "<span class='warning'>...but fail to stand perfectly still!</span>")
|
||||
|
||||
H.notransform = FALSE
|
||||
|
||||
/datum/action/innate/split_body/proc/make_dupe()
|
||||
var/mob/living/carbon/human/H = owner
|
||||
CHECK_DNA_AND_SPECIES(H)
|
||||
|
||||
var/mob/living/carbon/human/spare = new /mob/living/carbon/human(H.loc)
|
||||
|
||||
spare.underwear = "Nude"
|
||||
H.dna.transfer_identity(spare, transfer_SE=1)
|
||||
spare.dna.features["mcolor"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F")
|
||||
spare.real_name = spare.dna.real_name
|
||||
spare.name = spare.dna.real_name
|
||||
spare.updateappearance(mutcolor_update=1)
|
||||
spare.domutcheck()
|
||||
spare.Move(get_step(H.loc, pick(NORTH,SOUTH,EAST,WEST)))
|
||||
|
||||
H.blood_volume *= 0.45
|
||||
H.notransform = 0
|
||||
|
||||
var/datum/species/jelly/slime/origin_datum = H.dna.species
|
||||
origin_datum.bodies |= spare
|
||||
|
||||
var/datum/species/jelly/slime/spare_datum = spare.dna.species
|
||||
spare_datum.bodies = origin_datum.bodies
|
||||
|
||||
H.transfer_trait_datums(spare)
|
||||
H.mind.transfer_to(spare)
|
||||
spare.visible_message("<span class='warning'>[H] distorts as a new body \
|
||||
\"steps out\" of [H.p_them()].</span>",
|
||||
"<span class='notice'>...and after a moment of disorentation, \
|
||||
you're besides yourself!</span>")
|
||||
|
||||
|
||||
/datum/action/innate/swap_body
|
||||
name = "Swap Body"
|
||||
check_flags = NONE
|
||||
button_icon_state = "slimeswap"
|
||||
icon_icon = 'icons/mob/actions/actions_slime.dmi'
|
||||
background_icon_state = "bg_alien"
|
||||
|
||||
/datum/action/innate/swap_body/Activate()
|
||||
if(!isslimeperson(owner))
|
||||
to_chat(owner, "<span class='warning'>You are not a slimeperson.</span>")
|
||||
Remove(owner)
|
||||
else
|
||||
ui_interact(owner)
|
||||
|
||||
/datum/action/innate/swap_body/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
|
||||
|
||||
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.open()
|
||||
|
||||
/datum/action/innate/swap_body/ui_data(mob/user)
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if(!isslimeperson(H))
|
||||
return
|
||||
|
||||
var/datum/species/jelly/slime/SS = H.dna.species
|
||||
|
||||
var/list/data = list()
|
||||
data["bodies"] = list()
|
||||
for(var/b in SS.bodies)
|
||||
var/mob/living/carbon/human/body = b
|
||||
if(!body || QDELETED(body) || !isslimeperson(body))
|
||||
SS.bodies -= b
|
||||
continue
|
||||
|
||||
var/list/L = list()
|
||||
// HTML colors need a # prefix
|
||||
L["htmlcolor"] = "#[body.dna.features["mcolor"]]"
|
||||
L["area"] = get_area_name(body, TRUE)
|
||||
var/stat = "error"
|
||||
switch(body.stat)
|
||||
if(CONSCIOUS)
|
||||
stat = "Conscious"
|
||||
if(UNCONSCIOUS)
|
||||
stat = "Unconscious"
|
||||
if(DEAD)
|
||||
stat = "Dead"
|
||||
var/occupied
|
||||
if(body == H)
|
||||
occupied = "owner"
|
||||
else if(body.mind && body.mind.active)
|
||||
occupied = "stranger"
|
||||
else
|
||||
occupied = "available"
|
||||
|
||||
L["status"] = stat
|
||||
L["exoticblood"] = body.blood_volume
|
||||
L["name"] = body.name
|
||||
L["ref"] = "[REF(body)]"
|
||||
L["occupied"] = occupied
|
||||
var/button
|
||||
if(occupied == "owner")
|
||||
button = "selected"
|
||||
else if(occupied == "stranger")
|
||||
button = "danger"
|
||||
else if(can_swap(body))
|
||||
button = null
|
||||
else
|
||||
button = "disabled"
|
||||
|
||||
L["swap_button_state"] = button
|
||||
L["swappable"] = (occupied == "available") && can_swap(body)
|
||||
|
||||
data["bodies"] += list(L)
|
||||
|
||||
return data
|
||||
|
||||
/datum/action/innate/swap_body/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if(!isslimeperson(owner))
|
||||
return
|
||||
if(!H.mind || !H.mind.active)
|
||||
return
|
||||
switch(action)
|
||||
if("swap")
|
||||
var/mob/living/carbon/human/selected = locate(params["ref"])
|
||||
if(!can_swap(selected))
|
||||
return
|
||||
SStgui.close_uis(src)
|
||||
swap_to_dupe(H.mind, selected)
|
||||
|
||||
/datum/action/innate/swap_body/proc/can_swap(mob/living/carbon/human/dupe)
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if(!isslimeperson(H))
|
||||
return FALSE
|
||||
var/datum/species/jelly/slime/SS = H.dna.species
|
||||
|
||||
if(QDELETED(dupe)) //Is there a body?
|
||||
SS.bodies -= dupe
|
||||
return FALSE
|
||||
|
||||
if(!isslimeperson(dupe)) //Is it a slimeperson?
|
||||
SS.bodies -= dupe
|
||||
return FALSE
|
||||
|
||||
if(dupe.stat == DEAD) //Is it alive?
|
||||
return FALSE
|
||||
|
||||
if(dupe.stat != CONSCIOUS) //Is it awake?
|
||||
return FALSE
|
||||
|
||||
if(dupe.mind && dupe.mind.active) //Is it unoccupied?
|
||||
return FALSE
|
||||
|
||||
if(!(dupe in SS.bodies)) //Do we actually own it?
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/action/innate/swap_body/proc/swap_to_dupe(datum/mind/M, mob/living/carbon/human/dupe)
|
||||
if(!can_swap(dupe)) //sanity check
|
||||
return
|
||||
if(M.current.stat == CONSCIOUS)
|
||||
M.current.visible_message("<span class='notice'>[M.current] \
|
||||
stops moving and starts staring vacantly into space.</span>",
|
||||
"<span class='notice'>You stop moving this body...</span>")
|
||||
else
|
||||
to_chat(M.current, "<span class='notice'>You abandon this body...</span>")
|
||||
M.current.transfer_trait_datums(dupe)
|
||||
M.transfer_to(dupe)
|
||||
dupe.visible_message("<span class='notice'>[dupe] blinks and looks \
|
||||
around.</span>",
|
||||
"<span class='notice'>...and move this one instead.</span>")
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////Round Start Slimes///////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/species/jelly/roundstartslime
|
||||
name = "Xenobiological Slime Hybrid"
|
||||
id = "slimeperson"
|
||||
limbs_id = "slime"
|
||||
default_color = "00FFFF"
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR)
|
||||
inherent_traits = list(TRAIT_TOXINLOVER)
|
||||
mutant_bodyparts = list("mam_tail", "mam_ears", "mam_body_markings", "mam_snouts", "taur")
|
||||
default_features = list("mcolor" = "FFF", "mcolor2" = "FFF","mcolor3" = "FFF", "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.
|
||||
coldmod = 3
|
||||
heatmod = 1
|
||||
burnmod = 1
|
||||
|
||||
/datum/species/jelly/roundstartslime/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
|
||||
/datum/species/jelly/roundstartslime/spec_stun(mob/living/carbon/human/H,amount)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
. = ..()
|
||||
|
||||
/datum/species/jelly/roundstartslime/can_wag_tail(mob/living/carbon/human/H)
|
||||
return ("mam_tail" in mutant_bodyparts) || ("mam_waggingtail" in mutant_bodyparts)
|
||||
|
||||
/datum/species/jelly/roundstartslime/is_wagging_tail(mob/living/carbon/human/H)
|
||||
return ("mam_waggingtail" in mutant_bodyparts)
|
||||
|
||||
/datum/species/jelly/roundstartslime/start_wagging_tail(mob/living/carbon/human/H)
|
||||
if("mam_tail" in mutant_bodyparts)
|
||||
mutant_bodyparts -= "mam_tail"
|
||||
mutant_bodyparts |= "mam_waggingtail"
|
||||
H.update_body()
|
||||
|
||||
/datum/species/jelly/roundstartslime/stop_wagging_tail(mob/living/carbon/human/H)
|
||||
if("mam_waggingtail" in mutant_bodyparts)
|
||||
mutant_bodyparts -= "mam_waggingtail"
|
||||
mutant_bodyparts |= "mam_tail"
|
||||
H.update_body()
|
||||
|
||||
|
||||
/datum/action/innate/slime_change
|
||||
name = "Alter Form"
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
button_icon_state = "alter_form" //placeholder
|
||||
icon_icon = 'modular_citadel/icons/mob/actions/actions_slime.dmi'
|
||||
background_icon_state = "bg_alien"
|
||||
|
||||
/datum/action/innate/slime_change/Activate()
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if(!isjellyperson(H))
|
||||
return
|
||||
else
|
||||
H.visible_message("<span class='notice'>[owner] gains a look of \
|
||||
concentration while standing perfectly still.\
|
||||
Their body seems to shift and starts getting more goo-like.</span>",
|
||||
"<span class='notice'>You focus intently on altering your body while \
|
||||
standing perfectly still...</span>")
|
||||
change_form()
|
||||
|
||||
/datum/action/innate/slime_change/proc/change_form()
|
||||
var/mob/living/carbon/human/H = owner
|
||||
var/select_alteration = input(owner, "Select what part of your form to alter", "Form Alteration", "cancel") in list("Hair Style", "Genitals", "Tail", "Snout", "Markings", "Ears", "Taur body", "Penis", "Vagina", "Penis Length", "Breast Size", "Breast Shape", "Cancel")
|
||||
if(select_alteration == "Hair Style")
|
||||
if(H.gender == MALE)
|
||||
var/new_style = input(owner, "Select a facial hair style", "Hair Alterations") as null|anything in GLOB.facial_hair_styles_list
|
||||
if(new_style)
|
||||
H.facial_hair_style = new_style
|
||||
else
|
||||
H.facial_hair_style = "Shaved"
|
||||
//handle normal hair
|
||||
var/new_style = input(owner, "Select a hair style", "Hair Alterations") as null|anything in GLOB.hair_styles_list
|
||||
if(new_style)
|
||||
H.hair_style = new_style
|
||||
H.update_hair()
|
||||
else if (select_alteration == "Genitals")
|
||||
var/operation = input("Select organ operation.", "Organ Manipulation", "cancel") in list("add sexual organ", "remove sexual organ", "cancel")
|
||||
switch(operation)
|
||||
if("add sexual organ")
|
||||
var/new_organ = input("Select sexual organ:", "Organ Manipulation") as null|anything in GLOB.genitals_list
|
||||
if(!new_organ)
|
||||
return
|
||||
H.give_genital(GLOB.genitals_list[new_organ])
|
||||
|
||||
if("remove sexual organ")
|
||||
var/list/organs = list()
|
||||
for(var/obj/item/organ/genital/X in H.internal_organs)
|
||||
var/obj/item/organ/I = X
|
||||
organs["[I.name] ([I.type])"] = I
|
||||
var/obj/item/O = input("Select sexual organ:", "Organ Manipulation", null) as null|anything in organs
|
||||
var/obj/item/organ/genital/G = organs[O]
|
||||
if(!G)
|
||||
return
|
||||
G.forceMove(get_turf(H))
|
||||
qdel(G)
|
||||
H.update_genitals()
|
||||
|
||||
else if (select_alteration == "Ears")
|
||||
var/list/snowflake_ears_list = list("Normal" = null)
|
||||
for(var/path in GLOB.mam_ears_list)
|
||||
var/datum/sprite_accessory/mam_ears/instance = GLOB.mam_ears_list[path]
|
||||
if(istype(instance, /datum/sprite_accessory))
|
||||
var/datum/sprite_accessory/S = instance
|
||||
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
|
||||
snowflake_ears_list[S.name] = path
|
||||
var/new_ears
|
||||
new_ears = input(owner, "Choose your character's ears:", "Ear Alteration") as null|anything in snowflake_ears_list
|
||||
if(new_ears)
|
||||
H.dna.features["mam_ears"] = new_ears
|
||||
H.update_body()
|
||||
|
||||
else if (select_alteration == "Snout")
|
||||
var/list/snowflake_snouts_list = list("Normal" = null)
|
||||
for(var/path in GLOB.mam_snouts_list)
|
||||
var/datum/sprite_accessory/mam_snouts/instance = GLOB.mam_snouts_list[path]
|
||||
if(istype(instance, /datum/sprite_accessory))
|
||||
var/datum/sprite_accessory/S = instance
|
||||
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
|
||||
snowflake_snouts_list[S.name] = path
|
||||
var/new_snout
|
||||
new_snout = input(owner, "Choose your character's face:", "Face Alteration") as null|anything in snowflake_snouts_list
|
||||
if(new_snout)
|
||||
H.dna.features["mam_snouts"] = new_snout
|
||||
H.update_body()
|
||||
|
||||
else if (select_alteration == "Markings")
|
||||
var/list/snowflake_markings_list = list()
|
||||
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))
|
||||
var/datum/sprite_accessory/S = instance
|
||||
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
|
||||
snowflake_markings_list[S.name] = path
|
||||
var/new_mam_body_markings
|
||||
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)
|
||||
H.update_body()
|
||||
|
||||
else if (select_alteration == "Tail")
|
||||
var/list/snowflake_tails_list = list("Normal" = null)
|
||||
for(var/path in GLOB.mam_tails_list)
|
||||
var/datum/sprite_accessory/mam_tails/instance = GLOB.mam_tails_list[path]
|
||||
if(istype(instance, /datum/sprite_accessory))
|
||||
var/datum/sprite_accessory/S = instance
|
||||
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
|
||||
snowflake_tails_list[S.name] = path
|
||||
var/new_tail
|
||||
new_tail = input(owner, "Choose your character's Tail(s):", "Tail Alteration") as null|anything in snowflake_tails_list
|
||||
if(new_tail)
|
||||
H.dna.features["mam_tail"] = new_tail
|
||||
if(new_tail != "None")
|
||||
H.dna.features["taur"] = "None"
|
||||
H.update_body()
|
||||
|
||||
else if (select_alteration == "Taur body")
|
||||
var/list/snowflake_taur_list = list("Normal" = null)
|
||||
for(var/path in GLOB.taur_list)
|
||||
var/datum/sprite_accessory/taur/instance = GLOB.taur_list[path]
|
||||
if(istype(instance, /datum/sprite_accessory))
|
||||
var/datum/sprite_accessory/S = instance
|
||||
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
|
||||
snowflake_taur_list[S.name] = path
|
||||
var/new_taur
|
||||
new_taur = input(owner, "Choose your character's tauric body:", "Tauric Alteration") as null|anything in snowflake_taur_list
|
||||
if(new_taur)
|
||||
H.dna.features["taur"] = new_taur
|
||||
if(new_taur != "None")
|
||||
H.dna.features["mam_tail"] = "None"
|
||||
H.update_body()
|
||||
|
||||
else if (select_alteration == "Penis")
|
||||
for(var/obj/item/organ/genital/penis/X in H.internal_organs)
|
||||
qdel(X)
|
||||
var/new_shape
|
||||
new_shape = input(owner, "Choose your character's dong", "Genital Alteration") as null|anything in GLOB.cock_shapes_list
|
||||
if(new_shape)
|
||||
H.dna.features["cock_shape"] = new_shape
|
||||
H.update_genitals()
|
||||
H.give_genital(/obj/item/organ/genital/testicles)
|
||||
H.give_genital(/obj/item/organ/genital/penis)
|
||||
H.apply_overlay()
|
||||
|
||||
|
||||
else if (select_alteration == "Vagina")
|
||||
for(var/obj/item/organ/genital/vagina/X in H.internal_organs)
|
||||
qdel(X)
|
||||
var/new_shape
|
||||
new_shape = input(owner, "Choose your character's pussy", "Genital Alteration") as null|anything in GLOB.vagina_shapes_list
|
||||
if(new_shape)
|
||||
H.dna.features["vag_shape"] = new_shape
|
||||
H.update_genitals()
|
||||
H.give_genital(/obj/item/organ/genital/womb)
|
||||
H.give_genital(/obj/item/organ/genital/vagina)
|
||||
H.apply_overlay()
|
||||
|
||||
else if (select_alteration == "Penis Length")
|
||||
for(var/obj/item/organ/genital/penis/X in H.internal_organs)
|
||||
qdel(X)
|
||||
var/new_length
|
||||
new_length = input(owner, "Penis length in inches:\n([COCK_SIZE_MIN]-[COCK_SIZE_MAX])", "Genital Alteration") as num|null
|
||||
if(new_length)
|
||||
H.dna.features["cock_length"] = max(min( round(text2num(new_length)), COCK_SIZE_MAX),COCK_SIZE_MIN)
|
||||
H.update_genitals()
|
||||
H.apply_overlay()
|
||||
H.give_genital(/obj/item/organ/genital/testicles)
|
||||
H.give_genital(/obj/item/organ/genital/penis)
|
||||
|
||||
else if (select_alteration == "Breast Size")
|
||||
for(var/obj/item/organ/genital/breasts/X in H.internal_organs)
|
||||
qdel(X)
|
||||
var/new_size
|
||||
new_size = input(owner, "Breast Size", "Genital Alteration") as null|anything in GLOB.breasts_size_list
|
||||
if(new_size)
|
||||
H.dna.features["breasts_size"] = new_size
|
||||
H.update_genitals()
|
||||
H.apply_overlay()
|
||||
H.give_genital(/obj/item/organ/genital/breasts)
|
||||
|
||||
else if (select_alteration == "Breast Shape")
|
||||
for(var/obj/item/organ/genital/breasts/X in H.internal_organs)
|
||||
qdel(X)
|
||||
var/new_shape
|
||||
new_shape = input(owner, "Breast Shape", "Genital Alteration") as null|anything in GLOB.breasts_shapes_list
|
||||
if(new_shape)
|
||||
H.dna.features["breasts_shape"] = new_shape
|
||||
H.update_genitals()
|
||||
H.apply_overlay()
|
||||
H.give_genital(/obj/item/organ/genital/breasts)
|
||||
|
||||
else
|
||||
return
|
||||
|
||||
|
||||
///////////////////////////////////LUMINESCENTS//////////////////////////////////////////
|
||||
|
||||
//Luminescents are able to consume and use slime extracts, without them decaying.
|
||||
|
||||
/datum/species/jelly/luminescent
|
||||
name = "Luminescent Slime Entity"
|
||||
id = "lum"
|
||||
say_mod = "says"
|
||||
var/glow_intensity = LUMINESCENT_DEFAULT_GLOW
|
||||
var/obj/effect/dummy/luminescent_glow/glow
|
||||
var/obj/item/slime_extract/current_extract
|
||||
var/datum/action/innate/integrate_extract/integrate_extract
|
||||
var/datum/action/innate/use_extract/extract_minor
|
||||
var/datum/action/innate/use_extract/major/extract_major
|
||||
var/extract_cooldown = 0
|
||||
|
||||
/datum/species/jelly/luminescent/on_species_loss(mob/living/carbon/C)
|
||||
..()
|
||||
if(current_extract)
|
||||
current_extract.forceMove(C.drop_location())
|
||||
current_extract = null
|
||||
qdel(glow)
|
||||
if(integrate_extract)
|
||||
integrate_extract.Remove(C)
|
||||
if(extract_minor)
|
||||
extract_minor.Remove(C)
|
||||
if(extract_major)
|
||||
extract_major.Remove(C)
|
||||
|
||||
/datum/species/jelly/luminescent/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
..()
|
||||
glow = new(C)
|
||||
update_glow(C)
|
||||
integrate_extract = new(src)
|
||||
integrate_extract.Grant(C)
|
||||
extract_minor = new(src)
|
||||
extract_minor.Grant(C)
|
||||
extract_major = new(src)
|
||||
extract_major.Grant(C)
|
||||
|
||||
/datum/species/jelly/luminescent/proc/update_slime_actions()
|
||||
integrate_extract.update_name()
|
||||
integrate_extract.UpdateButtonIcon()
|
||||
extract_minor.UpdateButtonIcon()
|
||||
extract_major.UpdateButtonIcon()
|
||||
|
||||
/datum/species/jelly/luminescent/proc/update_glow(mob/living/carbon/C, intensity)
|
||||
if(intensity)
|
||||
glow_intensity = intensity
|
||||
glow.set_light(glow_intensity, glow_intensity, C.dna.features["mcolor"])
|
||||
|
||||
/obj/effect/dummy/luminescent_glow
|
||||
name = "luminescent glow"
|
||||
desc = "Tell a coder if you're seeing this."
|
||||
icon_state = "nothing"
|
||||
light_color = "#FFFFFF"
|
||||
light_range = LUMINESCENT_DEFAULT_GLOW
|
||||
|
||||
/obj/effect/dummy/luminescent_glow/Initialize()
|
||||
. = ..()
|
||||
if(!isliving(loc))
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/datum/action/innate/integrate_extract
|
||||
name = "Integrate Extract"
|
||||
desc = "Eat a slime extract to use its properties."
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
button_icon_state = "slimeconsume"
|
||||
icon_icon = 'icons/mob/actions/actions_slime.dmi'
|
||||
background_icon_state = "bg_alien"
|
||||
var/datum/species/jelly/luminescent/species
|
||||
|
||||
/datum/action/innate/integrate_extract/New(_species)
|
||||
..()
|
||||
species = _species
|
||||
|
||||
/datum/action/innate/integrate_extract/proc/update_name()
|
||||
if(!species || !species.current_extract)
|
||||
name = "Integrate Extract"
|
||||
desc = "Eat a slime extract to use its properties."
|
||||
else
|
||||
name = "Eject Extract"
|
||||
desc = "Eject your current slime extract."
|
||||
|
||||
/datum/action/innate/integrate_extract/UpdateButtonIcon(status_only, force)
|
||||
if(!species || !species.current_extract)
|
||||
button_icon_state = "slimeconsume"
|
||||
else
|
||||
button_icon_state = "slimeeject"
|
||||
..()
|
||||
|
||||
/datum/action/innate/integrate_extract/ApplyIcon(obj/screen/movable/action_button/current_button, force)
|
||||
..(current_button, TRUE)
|
||||
if(species && species.current_extract)
|
||||
current_button.add_overlay(mutable_appearance(species.current_extract.icon, species.current_extract.icon_state))
|
||||
|
||||
/datum/action/innate/integrate_extract/Activate()
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if(!is_species(H, /datum/species/jelly/luminescent) || !species)
|
||||
return
|
||||
CHECK_DNA_AND_SPECIES(H)
|
||||
|
||||
if(species.current_extract)
|
||||
var/obj/item/slime_extract/S = species.current_extract
|
||||
if(!H.put_in_active_hand(S))
|
||||
S.forceMove(H.drop_location())
|
||||
species.current_extract = null
|
||||
to_chat(H, "<span class='notice'>You eject [S].</span>")
|
||||
species.update_slime_actions()
|
||||
else
|
||||
var/obj/item/I = H.get_active_held_item()
|
||||
if(istype(I, /obj/item/slime_extract))
|
||||
var/obj/item/slime_extract/S = I
|
||||
if(!S.Uses)
|
||||
to_chat(H, "<span class='warning'>[I] is spent! You cannot integrate it.</span>")
|
||||
return
|
||||
if(!H.temporarilyRemoveItemFromInventory(S))
|
||||
return
|
||||
S.forceMove(H)
|
||||
species.current_extract = S
|
||||
to_chat(H, "<span class='notice'>You consume [I], and you feel it pulse within you...</span>")
|
||||
species.update_slime_actions()
|
||||
else
|
||||
to_chat(H, "<span class='warning'>You need to hold an unused slime extract in your active hand!</span>")
|
||||
|
||||
/datum/action/innate/use_extract
|
||||
name = "Extract Minor Activation"
|
||||
desc = "Pulse the slime extract with energized jelly to activate it."
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
button_icon_state = "slimeuse1"
|
||||
icon_icon = 'icons/mob/actions/actions_slime.dmi'
|
||||
background_icon_state = "bg_alien"
|
||||
var/activation_type = SLIME_ACTIVATE_MINOR
|
||||
var/datum/species/jelly/luminescent/species
|
||||
|
||||
/datum/action/innate/use_extract/New(_species)
|
||||
..()
|
||||
species = _species
|
||||
|
||||
/datum/action/innate/use_extract/IsAvailable()
|
||||
if(..())
|
||||
if(species && species.current_extract && (world.time > species.extract_cooldown))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/action/innate/use_extract/ApplyIcon(obj/screen/movable/action_button/current_button, force)
|
||||
..(current_button, TRUE)
|
||||
if(species && species.current_extract)
|
||||
current_button.add_overlay(mutable_appearance(species.current_extract.icon, species.current_extract.icon_state))
|
||||
|
||||
/datum/action/innate/use_extract/Activate()
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if(!is_species(H, /datum/species/jelly/luminescent) || !species)
|
||||
return
|
||||
CHECK_DNA_AND_SPECIES(H)
|
||||
|
||||
if(species.current_extract)
|
||||
species.extract_cooldown = world.time + 100
|
||||
var/cooldown = species.current_extract.activate(H, species, activation_type)
|
||||
species.extract_cooldown = world.time + cooldown
|
||||
|
||||
/datum/action/innate/use_extract/major
|
||||
name = "Extract Major Activation"
|
||||
desc = "Pulse the slime extract with plasma jelly to activate it."
|
||||
button_icon_state = "slimeuse2"
|
||||
activation_type = SLIME_ACTIVATE_MAJOR
|
||||
|
||||
///////////////////////////////////STARGAZERS//////////////////////////////////////////
|
||||
|
||||
//Stargazers are the telepathic branch of jellypeople, able to project psychic messages and to link minds with willing participants.
|
||||
|
||||
/datum/species/jelly/stargazer
|
||||
name = "Stargazer Slime Entity"
|
||||
id = "stargazer"
|
||||
var/datum/action/innate/project_thought/project_thought
|
||||
var/datum/action/innate/link_minds/link_minds
|
||||
var/list/mob/living/linked_mobs = list()
|
||||
var/list/datum/action/innate/linked_speech/linked_actions = list()
|
||||
var/mob/living/carbon/human/slimelink_owner
|
||||
var/current_link_id = 0
|
||||
|
||||
/datum/species/jelly/stargazer/on_species_loss(mob/living/carbon/C)
|
||||
..()
|
||||
for(var/M in linked_mobs)
|
||||
unlink_mob(M)
|
||||
if(project_thought)
|
||||
project_thought.Remove(C)
|
||||
if(link_minds)
|
||||
link_minds.Remove(C)
|
||||
|
||||
/datum/species/jelly/stargazer/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
..()
|
||||
for(var/M in linked_mobs)
|
||||
unlink_mob(M)
|
||||
|
||||
/datum/species/jelly/stargazer/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
..()
|
||||
project_thought = new(src)
|
||||
project_thought.Grant(C)
|
||||
link_minds = new(src)
|
||||
link_minds.Grant(C)
|
||||
slimelink_owner = C
|
||||
link_mob(C)
|
||||
|
||||
/datum/species/jelly/stargazer/proc/link_mob(mob/living/M)
|
||||
if(QDELETED(M) || M.stat == DEAD)
|
||||
return FALSE
|
||||
if(HAS_TRAIT(M, TRAIT_MINDSHIELD)) //mindshield implant, no dice
|
||||
return FALSE
|
||||
if(M.anti_magic_check(FALSE, FALSE, TRUE, 0))
|
||||
return FALSE
|
||||
if(M in linked_mobs)
|
||||
return FALSE
|
||||
linked_mobs.Add(M)
|
||||
to_chat(M, "<span class='notice'>You are now connected to [slimelink_owner.real_name]'s Slime Link.</span>")
|
||||
var/datum/action/innate/linked_speech/action = new(src)
|
||||
linked_actions.Add(action)
|
||||
action.Grant(M)
|
||||
return TRUE
|
||||
|
||||
/datum/species/jelly/stargazer/proc/unlink_mob(mob/living/M)
|
||||
var/link_id = linked_mobs.Find(M)
|
||||
if(!(link_id))
|
||||
return
|
||||
var/datum/action/innate/linked_speech/action = linked_actions[link_id]
|
||||
action.Remove(M)
|
||||
to_chat(M, "<span class='notice'>You are no longer connected to [slimelink_owner.real_name]'s Slime Link.</span>")
|
||||
linked_mobs[link_id] = null
|
||||
linked_actions[link_id] = null
|
||||
|
||||
/datum/action/innate/linked_speech
|
||||
name = "Slimelink"
|
||||
desc = "Send a psychic message to everyone connected to your slime link."
|
||||
button_icon_state = "link_speech"
|
||||
icon_icon = 'icons/mob/actions/actions_slime.dmi'
|
||||
background_icon_state = "bg_alien"
|
||||
var/datum/species/jelly/stargazer/species
|
||||
|
||||
/datum/action/innate/linked_speech/New(_species)
|
||||
..()
|
||||
species = _species
|
||||
|
||||
/datum/action/innate/linked_speech/Activate()
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if(!species || !(H in species.linked_mobs))
|
||||
to_chat(H, "<span class='warning'>The link seems to have been severed...</span>")
|
||||
Remove(H)
|
||||
return
|
||||
|
||||
var/message = sanitize(input("Message:", "Slime Telepathy") as text|null)
|
||||
|
||||
if(!species || !(H in species.linked_mobs))
|
||||
to_chat(H, "<span class='warning'>The link seems to have been severed...</span>")
|
||||
Remove(H)
|
||||
return
|
||||
|
||||
if(QDELETED(H) || H.stat == DEAD)
|
||||
species.unlink_mob(H)
|
||||
return
|
||||
|
||||
if(message)
|
||||
var/msg = "<i><font color=#008CA2>\[[species.slimelink_owner.real_name]'s Slime Link\] <b>[H]:</b> [message]</font></i>"
|
||||
log_directed_talk(H, species.slimelink_owner, msg, LOG_SAY, "slime link")
|
||||
for(var/X in species.linked_mobs)
|
||||
var/mob/living/M = X
|
||||
if(QDELETED(M) || M.stat == DEAD)
|
||||
species.unlink_mob(M)
|
||||
continue
|
||||
to_chat(M, msg)
|
||||
|
||||
for(var/X in GLOB.dead_mob_list)
|
||||
var/mob/M = X
|
||||
var/link = FOLLOW_LINK(M, H)
|
||||
to_chat(M, "[link] [msg]")
|
||||
|
||||
/datum/action/innate/project_thought
|
||||
name = "Send Thought"
|
||||
desc = "Send a private psychic message to someone you can see."
|
||||
button_icon_state = "send_mind"
|
||||
icon_icon = 'icons/mob/actions/actions_slime.dmi'
|
||||
background_icon_state = "bg_alien"
|
||||
|
||||
/datum/action/innate/project_thought/Activate()
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if(H.stat == DEAD)
|
||||
return
|
||||
if(!is_species(H, /datum/species/jelly/stargazer))
|
||||
return
|
||||
CHECK_DNA_AND_SPECIES(H)
|
||||
|
||||
var/list/options = list()
|
||||
for(var/mob/living/Ms in oview(H))
|
||||
options += Ms
|
||||
var/mob/living/M = input("Select who to send your message to:","Send thought to?",null) as null|mob in options
|
||||
if(!M)
|
||||
return
|
||||
if(M.anti_magic_check(FALSE, FALSE, TRUE, 0))
|
||||
to_chat(H, "<span class='notice'>As you try to communicate with [M], you're suddenly stopped by a vision of a massive tinfoil wall that streches beyond visible range. It seems you've been foiled.</span>")
|
||||
return
|
||||
var/msg = sanitize(input("Message:", "Telepathy") as text|null)
|
||||
if(msg)
|
||||
if(M.anti_magic_check(FALSE, FALSE, TRUE, 0))
|
||||
to_chat(H, "<span class='notice'>As you try to communicate with [M], you're suddenly stopped by a vision of a massive tinfoil wall that streches beyond visible range. It seems you've been foiled.</span>")
|
||||
return
|
||||
log_directed_talk(H, M, msg, LOG_SAY, "slime telepathy")
|
||||
to_chat(M, "<span class='notice'>You hear an alien voice in your head... </span><font color=#008CA2>[msg]</font>")
|
||||
to_chat(H, "<span class='notice'>You telepathically said: \"[msg]\" to [M]</span>")
|
||||
for(var/dead in GLOB.dead_mob_list)
|
||||
if(!isobserver(dead))
|
||||
continue
|
||||
var/follow_link_user = FOLLOW_LINK(dead, H)
|
||||
var/follow_link_target = FOLLOW_LINK(dead, M)
|
||||
to_chat(dead, "[follow_link_user] <span class='name'>[H]</span> <span class='alertalien'>Slime Telepathy --> </span> [follow_link_target] <span class='name'>[M]</span> <span class='noticealien'>[msg]</span>")
|
||||
|
||||
/datum/action/innate/link_minds
|
||||
name = "Link Minds"
|
||||
desc = "Link someone's mind to your Slime Link, allowing them to communicate telepathically with other linked minds."
|
||||
button_icon_state = "mindlink"
|
||||
icon_icon = 'icons/mob/actions/actions_slime.dmi'
|
||||
background_icon_state = "bg_alien"
|
||||
var/datum/species/jelly/stargazer/species
|
||||
|
||||
/datum/action/innate/link_minds/New(_species)
|
||||
..()
|
||||
species = _species
|
||||
|
||||
/datum/action/innate/link_minds/Activate()
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if(!is_species(H, /datum/species/jelly/stargazer))
|
||||
return
|
||||
CHECK_DNA_AND_SPECIES(H)
|
||||
|
||||
if(!H.pulling || !isliving(H.pulling) || H.grab_state < GRAB_AGGRESSIVE)
|
||||
to_chat(H, "<span class='warning'>You need to aggressively grab someone to link minds!</span>")
|
||||
return
|
||||
|
||||
var/mob/living/target = H.pulling
|
||||
|
||||
to_chat(H, "<span class='notice'>You begin linking [target]'s mind to yours...</span>")
|
||||
to_chat(target, "<span class='warning'>You feel a foreign presence within your mind...</span>")
|
||||
if(do_after(H, 60, target = target))
|
||||
if(H.pulling != target || H.grab_state < GRAB_AGGRESSIVE)
|
||||
return
|
||||
if(species.link_mob(target))
|
||||
to_chat(H, "<span class='notice'>You connect [target]'s mind to your slime link!</span>")
|
||||
else
|
||||
to_chat(H, "<span class='warning'>You can't seem to link [target]'s mind...</span>")
|
||||
to_chat(target, "<span class='warning'>The foreign presence leaves your mind.</span>")
|
||||
@@ -1,106 +0,0 @@
|
||||
/datum/species/lizard
|
||||
// Reptilian humanoids with scaled skin and tails.
|
||||
name = "Anthromorphic Lizard"
|
||||
id = "lizard"
|
||||
say_mod = "hisses"
|
||||
default_color = "00FF00"
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS,HORNCOLOR,WINGCOLOR)
|
||||
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_REPTILE)
|
||||
mutant_bodyparts = list("tail_lizard", "snout", "spines", "horns", "frills", "body_markings", "legs", "taur", "deco_wings")
|
||||
mutanttongue = /obj/item/organ/tongue/lizard
|
||||
mutanttail = /obj/item/organ/tail/lizard
|
||||
coldmod = 1.5
|
||||
heatmod = 0.67
|
||||
default_features = list("mcolor" = "0F0", "mcolor2" = "0F0", "mcolor3" = "0F0", "tail_lizard" = "Smooth", "snout" = "Round",
|
||||
"horns" = "None", "frills" = "None", "spines" = "None", "body_markings" = "None",
|
||||
"legs" = "Digitigrade", "taur" = "None", "deco_wings" = "None")
|
||||
attack_verb = "slash"
|
||||
attack_sound = 'sound/weapons/slash.ogg'
|
||||
miss_sound = 'sound/weapons/slashmiss.ogg'
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/lizard
|
||||
gib_types = list(/obj/effect/gibspawner/lizard, /obj/effect/gibspawner/lizard/bodypartless)
|
||||
skinned_type = /obj/item/stack/sheet/animalhide/lizard
|
||||
exotic_bloodtype = "L"
|
||||
disliked_food = GRAIN | DAIRY
|
||||
liked_food = GROSS | MEAT
|
||||
|
||||
/datum/species/lizard/after_equip_job(datum/job/J, mob/living/carbon/human/H)
|
||||
H.grant_language(/datum/language/draconic)
|
||||
|
||||
/datum/species/lizard/random_name(gender,unique,lastname)
|
||||
if(unique)
|
||||
return random_unique_lizard_name(gender)
|
||||
|
||||
var/randname = lizard_name(gender)
|
||||
|
||||
if(lastname)
|
||||
randname += " [lastname]"
|
||||
|
||||
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 ("tail_lizard" in mutant_bodyparts) || ("waggingtail_lizard" in mutant_bodyparts)
|
||||
|
||||
/datum/species/lizard/is_wagging_tail(mob/living/carbon/human/H)
|
||||
return ("waggingtail_lizard" in mutant_bodyparts)
|
||||
|
||||
/datum/species/lizard/start_wagging_tail(mob/living/carbon/human/H)
|
||||
if("tail_lizard" in mutant_bodyparts)
|
||||
mutant_bodyparts -= "tail_lizard"
|
||||
mutant_bodyparts -= "spines"
|
||||
mutant_bodyparts |= "waggingtail_lizard"
|
||||
mutant_bodyparts |= "waggingspines"
|
||||
H.update_body()
|
||||
|
||||
/datum/species/lizard/stop_wagging_tail(mob/living/carbon/human/H)
|
||||
if("waggingtail_lizard" in mutant_bodyparts)
|
||||
mutant_bodyparts -= "waggingtail_lizard"
|
||||
mutant_bodyparts -= "waggingspines"
|
||||
mutant_bodyparts |= "tail_lizard"
|
||||
mutant_bodyparts |= "spines"
|
||||
H.update_body()
|
||||
|
||||
/datum/species/lizard/on_species_gain(mob/living/carbon/human/C, datum/species/old_species)
|
||||
if(("legs" in C.dna.species.mutant_bodyparts) && (C.dna.features["legs"] == "Digitigrade" || C.dna.features["legs"] == "Avian"))
|
||||
species_traits += DIGITIGRADE
|
||||
if(DIGITIGRADE in species_traits)
|
||||
C.Digitigrade_Leg_Swap(FALSE)
|
||||
return ..()
|
||||
|
||||
/datum/species/lizard/on_species_loss(mob/living/carbon/human/C, datum/species/new_species)
|
||||
if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Plantigrade")
|
||||
species_traits -= DIGITIGRADE
|
||||
if(DIGITIGRADE in species_traits)
|
||||
C.Digitigrade_Leg_Swap(TRUE)
|
||||
|
||||
/*
|
||||
Lizard subspecies: ASHWALKERS
|
||||
*/
|
||||
/datum/species/lizard/ashwalker
|
||||
name = "Ash Walker"
|
||||
id = "ashlizard"
|
||||
limbs_id = "lizard"
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE)
|
||||
inherent_traits = list(TRAIT_NOGUNS)
|
||||
mutantlungs = /obj/item/organ/lungs/ashwalker
|
||||
burnmod = 0.9
|
||||
brutemod = 0.9
|
||||
|
||||
/datum/species/lizard/ashwalker/on_species_gain(mob/living/carbon/human/C, datum/species/old_species)
|
||||
if((C.dna.features["spines"] != "None" ) && (C.dna.features["tail_lizard"] == "None")) //tbh, it's kinda ugly for them not to have a tail yet have floating spines
|
||||
C.dna.features["tail_lizard"] = "Smooth"
|
||||
C.update_body()
|
||||
return ..()
|
||||
@@ -1,220 +0,0 @@
|
||||
#define HEART_RESPAWN_THRESHHOLD 40
|
||||
#define HEART_SPECIAL_SHADOWIFY 2
|
||||
|
||||
/datum/species/shadow
|
||||
// Humans cursed to stay in the darkness, lest their life forces drain. They regain health in shadow and die in light.
|
||||
name = "???"
|
||||
id = "shadow"
|
||||
sexes = 0
|
||||
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)
|
||||
|
||||
dangerous_existence = 1
|
||||
mutanteyes = /obj/item/organ/eyes/night_vision
|
||||
|
||||
|
||||
/datum/species/shadow/spec_life(mob/living/carbon/human/H)
|
||||
var/turf/T = H.loc
|
||||
if(istype(T))
|
||||
var/light_amount = T.get_lumcount()
|
||||
|
||||
if(light_amount > SHADOW_SPECIES_LIGHT_THRESHOLD) //if there's enough light, start dying
|
||||
H.take_overall_damage(1,1)
|
||||
else if (light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD) //heal in the dark
|
||||
H.heal_overall_damage(1,1)
|
||||
|
||||
/datum/species/shadow/check_roundstart_eligible()
|
||||
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/datum/species/shadow/nightmare
|
||||
name = "Nightmare"
|
||||
id = "nightmare"
|
||||
limbs_id = "shadow"
|
||||
burnmod = 1.5
|
||||
blacklisted = TRUE
|
||||
no_equip = list(SLOT_WEAR_MASK, SLOT_WEAR_SUIT, SLOT_GLOVES, SLOT_SHOES, SLOT_W_UNIFORM, SLOT_S_STORE)
|
||||
species_traits = list(NOBLOOD,NO_UNDERWEAR,NO_DNA_COPY,NOTRANSSTING,NOEYES,NOGENITALS,NOAROUSAL)
|
||||
inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_NOBREATH,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER)
|
||||
mutanteyes = /obj/item/organ/eyes/night_vision/nightmare
|
||||
mutant_organs = list(/obj/item/organ/heart/nightmare)
|
||||
mutant_brain = /obj/item/organ/brain/nightmare
|
||||
|
||||
var/info_text = "You are a <span class='danger'>Nightmare</span>. The ability <span class='warning'>shadow walk</span> allows unlimited, unrestricted movement in the dark while activated. \
|
||||
Your <span class='warning'>light eater</span> will destroy any light producing objects you attack, as well as destroy any lights a living creature may be holding. You will automatically dodge gunfire and melee attacks when on a dark tile. If killed, you will eventually revive if left in darkness."
|
||||
|
||||
/datum/species/shadow/nightmare/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
. = ..()
|
||||
to_chat(C, "[info_text]")
|
||||
|
||||
C.real_name = "[pick(GLOB.nightmare_names)]"
|
||||
C.name = C.real_name
|
||||
if(C.mind)
|
||||
C.mind.name = C.real_name
|
||||
C.dna.real_name = C.real_name
|
||||
|
||||
/datum/species/shadow/nightmare/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H)
|
||||
var/turf/T = H.loc
|
||||
if(istype(T))
|
||||
var/light_amount = T.get_lumcount()
|
||||
if(light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD)
|
||||
H.visible_message("<span class='danger'>[H] dances in the shadows, evading [P]!</span>")
|
||||
playsound(T, "bullet_miss", 75, 1)
|
||||
return -1
|
||||
return 0
|
||||
|
||||
/datum/species/shadow/nightmare/check_roundstart_eligible()
|
||||
return FALSE
|
||||
|
||||
//Organs
|
||||
|
||||
/obj/item/organ/brain/nightmare
|
||||
name = "tumorous mass"
|
||||
desc = "A fleshy growth that was dug out of the skull of a Nightmare."
|
||||
icon_state = "brain-x-d"
|
||||
var/obj/effect/proc_holder/spell/targeted/shadowwalk/shadowwalk
|
||||
|
||||
/obj/item/organ/brain/nightmare/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
|
||||
..()
|
||||
if(M.dna.species.id != "nightmare")
|
||||
M.set_species(/datum/species/shadow/nightmare)
|
||||
visible_message("<span class='warning'>[M] thrashes as [src] takes root in [M.p_their()] body!</span>")
|
||||
var/obj/effect/proc_holder/spell/targeted/shadowwalk/SW = new
|
||||
M.AddSpell(SW)
|
||||
shadowwalk = SW
|
||||
|
||||
|
||||
/obj/item/organ/brain/nightmare/Remove(mob/living/carbon/M, special = 0)
|
||||
if(shadowwalk)
|
||||
M.RemoveSpell(shadowwalk)
|
||||
..()
|
||||
|
||||
|
||||
/obj/item/organ/heart/nightmare
|
||||
name = "heart of darkness"
|
||||
desc = "An alien organ that twists and writhes when exposed to light."
|
||||
icon = 'icons/obj/surgery.dmi'
|
||||
icon_state = "demon_heart-on"
|
||||
color = "#1C1C1C"
|
||||
var/respawn_progress = 0
|
||||
var/obj/item/light_eater/blade
|
||||
decay_factor = 0
|
||||
|
||||
|
||||
/obj/item/organ/heart/nightmare/attack(mob/M, mob/living/carbon/user, obj/target)
|
||||
if(M != user)
|
||||
return ..()
|
||||
user.visible_message("<span class='warning'>[user] raises [src] to [user.p_their()] mouth and tears into it with [user.p_their()] teeth!</span>", \
|
||||
"<span class='danger'>[src] feels unnaturally cold in your hands. You raise [src] your mouth and devour it!</span>")
|
||||
playsound(user, 'sound/magic/demon_consume.ogg', 50, 1)
|
||||
|
||||
|
||||
user.visible_message("<span class='warning'>Blood erupts from [user]'s arm as it reforms into a weapon!</span>", \
|
||||
"<span class='userdanger'>Icy blood pumps through your veins as your arm reforms itself!</span>")
|
||||
user.temporarilyRemoveItemFromInventory(src, TRUE)
|
||||
Insert(user)
|
||||
|
||||
/obj/item/organ/heart/nightmare/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
|
||||
..()
|
||||
if(special != HEART_SPECIAL_SHADOWIFY)
|
||||
blade = new/obj/item/light_eater
|
||||
M.put_in_hands(blade)
|
||||
|
||||
/obj/item/organ/heart/nightmare/Remove(mob/living/carbon/M, special = 0)
|
||||
respawn_progress = 0
|
||||
if(blade && special != HEART_SPECIAL_SHADOWIFY)
|
||||
QDEL_NULL(blade)
|
||||
M.visible_message("<span class='warning'>\The [blade] disintegrates!</span>")
|
||||
..()
|
||||
|
||||
/obj/item/organ/heart/nightmare/Stop()
|
||||
return 0
|
||||
|
||||
/obj/item/organ/heart/nightmare/update_icon()
|
||||
return //always beating visually
|
||||
|
||||
/obj/item/organ/heart/nightmare/on_death()
|
||||
if(!owner)
|
||||
return
|
||||
var/turf/T = get_turf(owner)
|
||||
if(istype(T))
|
||||
var/light_amount = T.get_lumcount()
|
||||
if(light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD)
|
||||
respawn_progress++
|
||||
playsound(owner,'sound/effects/singlebeat.ogg',40,1)
|
||||
if(respawn_progress >= HEART_RESPAWN_THRESHHOLD)
|
||||
owner.revive(full_heal = TRUE)
|
||||
if(!(owner.dna.species.id == "shadow" || owner.dna.species.id == "nightmare"))
|
||||
var/mob/living/carbon/old_owner = owner
|
||||
Remove(owner, HEART_SPECIAL_SHADOWIFY)
|
||||
old_owner.set_species(/datum/species/shadow)
|
||||
Insert(old_owner, HEART_SPECIAL_SHADOWIFY)
|
||||
to_chat(owner, "<span class='userdanger'>You feel the shadows invade your skin, leaping into the center of your chest! You're alive!</span>")
|
||||
SEND_SOUND(owner, sound('sound/effects/ghost.ogg'))
|
||||
owner.visible_message("<span class='warning'>[owner] staggers to [owner.p_their()] feet!</span>")
|
||||
playsound(owner, 'sound/hallucinations/far_noise.ogg', 50, 1)
|
||||
respawn_progress = 0
|
||||
|
||||
//Weapon
|
||||
|
||||
/obj/item/light_eater
|
||||
name = "light eater" //as opposed to heavy eater
|
||||
icon_state = "arm_blade"
|
||||
item_state = "arm_blade"
|
||||
force = 25
|
||||
armour_penetration = 35
|
||||
lefthand_file = 'icons/mob/inhands/antag/changeling_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/changeling_righthand.dmi'
|
||||
item_flags = ABSTRACT | DROPDEL
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
sharpness = IS_SHARP
|
||||
total_mass = TOTAL_MASS_HAND_REPLACEMENT
|
||||
|
||||
/obj/item/light_eater/Initialize()
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_NODROP, HAND_REPLACEMENT_TRAIT)
|
||||
AddComponent(/datum/component/butchering, 80, 70)
|
||||
|
||||
/obj/item/light_eater/afterattack(atom/movable/AM, mob/user, proximity)
|
||||
. = ..()
|
||||
if(!proximity)
|
||||
return
|
||||
if(isopenturf(AM)) //So you can actually melee with it
|
||||
return
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
if(iscyborg(AM))
|
||||
var/mob/living/silicon/robot/borg = AM
|
||||
if(!borg.lamp_cooldown)
|
||||
borg.update_headlamp(TRUE, INFINITY)
|
||||
to_chat(borg, "<span class='danger'>Your headlamp is fried! You'll need a human to help replace it.</span>")
|
||||
else
|
||||
for(var/obj/item/O in AM)
|
||||
if(O.light_range && O.light_power)
|
||||
disintegrate(O)
|
||||
if(L.pulling && L.pulling.light_range && isitem(L.pulling))
|
||||
disintegrate(L.pulling)
|
||||
else if(isitem(AM))
|
||||
var/obj/item/I = AM
|
||||
if(I.light_range && I.light_power)
|
||||
disintegrate(I)
|
||||
|
||||
/obj/item/light_eater/proc/disintegrate(obj/item/O)
|
||||
if(istype(O, /obj/item/pda))
|
||||
var/obj/item/pda/PDA = O
|
||||
PDA.set_light(0)
|
||||
PDA.fon = FALSE
|
||||
PDA.f_lum = 0
|
||||
PDA.update_icon()
|
||||
visible_message("<span class='danger'>The light in [PDA] shorts out!</span>")
|
||||
else
|
||||
visible_message("<span class='danger'>[O] is disintegrated by [src]!</span>")
|
||||
O.burn()
|
||||
playsound(src, 'sound/items/welder.ogg', 50, 1)
|
||||
|
||||
#undef HEART_SPECIAL_SHADOWIFY
|
||||
#undef HEART_RESPAWN_THRESHHOLD
|
||||
@@ -1,30 +0,0 @@
|
||||
/datum/species/skeleton
|
||||
// 2spooky
|
||||
name = "Spooky Scary 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_biotypes = list(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
|
||||
|
||||
/datum/species/skeleton/check_roundstart_eligible()
|
||||
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/datum/species/skeleton/space
|
||||
name = "Spooky Spacey Skeleton"
|
||||
id = "spaceskeleton"
|
||||
limbs_id = "skeleton"
|
||||
blacklisted = 1
|
||||
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
|
||||
@@ -1,127 +0,0 @@
|
||||
/datum/species/synth
|
||||
name = "Synthetic" //inherited from the real species, for health scanners and things
|
||||
id = "synth"
|
||||
say_mod = "beep boops" //inherited from a user's real species
|
||||
sexes = 0
|
||||
species_traits = list(NOTRANSSTING,NOGENITALS,NOAROUSAL) //all of these + whatever we inherit from the real species
|
||||
inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOLIMBDISABLE,TRAIT_NOHUNGER,TRAIT_NOBREATH)
|
||||
inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID)
|
||||
dangerous_existence = 1
|
||||
blacklisted = 1
|
||||
meat = null
|
||||
gib_types = /obj/effect/gibspawner/robot
|
||||
damage_overlay_type = "synth"
|
||||
limbs_id = "synth"
|
||||
var/list/initial_species_traits = list(NOTRANSSTING) //for getting these values back for assume_disguise()
|
||||
var/list/initial_inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOLIMBDISABLE,TRAIT_NOHUNGER,TRAIT_NOBREATH)
|
||||
var/disguise_fail_health = 75 //When their health gets to this level their synthflesh partially falls off
|
||||
var/datum/species/fake_species = null //a species to do most of our work for us, unless we're damaged
|
||||
|
||||
/datum/species/synth/military
|
||||
name = "Military Synth"
|
||||
id = "military_synth"
|
||||
armor = 25
|
||||
punchdamagelow = 10
|
||||
punchdamagehigh = 19
|
||||
punchstunthreshold = 14 //about 50% chance to stun
|
||||
disguise_fail_health = 50
|
||||
|
||||
/datum/species/synth/on_species_gain(mob/living/carbon/human/H, datum/species/old_species)
|
||||
..()
|
||||
assume_disguise(old_species, H)
|
||||
RegisterSignal(H, COMSIG_MOB_SAY, .proc/handle_speech)
|
||||
|
||||
/datum/species/synth/on_species_loss(mob/living/carbon/human/H)
|
||||
. = ..()
|
||||
UnregisterSignal(H, COMSIG_MOB_SAY)
|
||||
|
||||
/datum/species/synth/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
|
||||
if(chem.id == "synthflesh")
|
||||
chem.reaction_mob(H, TOUCH, 2 ,0) //heal a little
|
||||
H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/species/synth/proc/assume_disguise(datum/species/S, mob/living/carbon/human/H)
|
||||
if(S && !istype(S, type))
|
||||
name = S.name
|
||||
say_mod = S.say_mod
|
||||
sexes = S.sexes
|
||||
species_traits = initial_species_traits.Copy()
|
||||
inherent_traits = initial_inherent_traits.Copy()
|
||||
species_traits |= S.species_traits
|
||||
inherent_traits |= S.inherent_traits
|
||||
attack_verb = S.attack_verb
|
||||
attack_sound = S.attack_sound
|
||||
miss_sound = S.miss_sound
|
||||
meat = S.meat
|
||||
mutant_bodyparts = S.mutant_bodyparts.Copy()
|
||||
mutant_organs = S.mutant_organs.Copy()
|
||||
default_features = S.default_features.Copy()
|
||||
nojumpsuit = S.nojumpsuit
|
||||
no_equip = S.no_equip.Copy()
|
||||
limbs_id = S.limbs_id
|
||||
use_skintones = S.use_skintones
|
||||
fixed_mut_color = S.fixed_mut_color
|
||||
hair_color = S.hair_color
|
||||
fake_species = new S.type
|
||||
else
|
||||
name = initial(name)
|
||||
say_mod = initial(say_mod)
|
||||
species_traits = initial_species_traits.Copy()
|
||||
inherent_traits = initial_inherent_traits.Copy()
|
||||
attack_verb = initial(attack_verb)
|
||||
attack_sound = initial(attack_sound)
|
||||
miss_sound = initial(miss_sound)
|
||||
mutant_bodyparts = list()
|
||||
default_features = list()
|
||||
nojumpsuit = initial(nojumpsuit)
|
||||
no_equip = list()
|
||||
qdel(fake_species)
|
||||
fake_species = null
|
||||
meat = initial(meat)
|
||||
limbs_id = "synth"
|
||||
use_skintones = 0
|
||||
sexes = 0
|
||||
fixed_mut_color = ""
|
||||
hair_color = ""
|
||||
|
||||
for(var/X in H.bodyparts) //propagates the damage_overlay changes
|
||||
var/obj/item/bodypart/BP = X
|
||||
BP.update_limb()
|
||||
H.update_body_parts() //to update limb icon cache with the new damage overlays
|
||||
|
||||
//Proc redirects:
|
||||
//Passing procs onto the fake_species, to ensure we look as much like them as possible
|
||||
|
||||
/datum/species/synth/handle_hair(mob/living/carbon/human/H, forced_colour)
|
||||
if(fake_species)
|
||||
fake_species.handle_hair(H, forced_colour)
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/species/synth/handle_body(mob/living/carbon/human/H)
|
||||
if(fake_species)
|
||||
fake_species.handle_body(H)
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/species/synth/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour)
|
||||
if(fake_species)
|
||||
fake_species.handle_body(H,forced_colour)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/datum/species/synth/proc/handle_speech(datum/source, list/speech_args)
|
||||
if (isliving(source)) // yeah it's gonna be living but just to be clean
|
||||
var/mob/living/L = source
|
||||
if(fake_species && L.health > disguise_fail_health)
|
||||
switch (fake_species.type)
|
||||
if (/datum/species/golem/bananium)
|
||||
speech_args[SPEECH_SPANS] |= SPAN_CLOWN
|
||||
if (/datum/species/golem/clockwork)
|
||||
speech_args[SPEECH_SPANS] |= SPAN_ROBOT
|
||||
@@ -1,150 +0,0 @@
|
||||
/datum/species/vampire
|
||||
name = "Vampire"
|
||||
id = "vampire"
|
||||
default_color = "FFFFFF"
|
||||
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,DRINKSBLOOD)
|
||||
inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH)
|
||||
inherent_biotypes = list(MOB_UNDEAD, MOB_HUMANOID)
|
||||
default_features = list("mcolor" = "FFF", "tail_human" = "None", "ears" = "None", "wings" = "None")
|
||||
exotic_bloodtype = "U"
|
||||
use_skintones = TRUE
|
||||
mutant_heart = /obj/item/organ/heart/vampire
|
||||
mutanttongue = /obj/item/organ/tongue/vampire
|
||||
blacklisted = TRUE
|
||||
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."
|
||||
|
||||
/datum/species/vampire/check_roundstart_eligible()
|
||||
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/species/vampire/on_species_gain(mob/living/carbon/human/C, datum/species/old_species)
|
||||
. = ..()
|
||||
to_chat(C, "[info_text]")
|
||||
C.skin_tone = "albino"
|
||||
C.update_body(0)
|
||||
var/obj/effect/proc_holder/spell/targeted/shapeshift/bat/B = new
|
||||
C.AddSpell(B)
|
||||
|
||||
/datum/species/vampire/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
if(C.mind)
|
||||
for(var/S in C.mind.spell_list)
|
||||
var/obj/effect/proc_holder/spell/S2 = S
|
||||
if(S2.type == /obj/effect/proc_holder/spell/targeted/shapeshift/bat)
|
||||
C.mind.spell_list.Remove(S2)
|
||||
qdel(S2)
|
||||
|
||||
/datum/species/vampire/spec_life(mob/living/carbon/human/C)
|
||||
. = ..()
|
||||
if(istype(C.loc, /obj/structure/closet/crate/coffin))
|
||||
C.heal_overall_damage(4,4)
|
||||
C.adjustToxLoss(-4)
|
||||
C.adjustOxyLoss(-4)
|
||||
C.adjustCloneLoss(-4)
|
||||
return
|
||||
C.blood_volume -= 0.75 //Will take roughly 19.5 minutes to die from standard blood volume, roughly 83 minutes to die from max blood volume.
|
||||
if(C.blood_volume <= (BLOOD_VOLUME_SURVIVE*C.blood_ratio))
|
||||
to_chat(C, "<span class='danger'>You ran out of blood!</span>")
|
||||
C.dust()
|
||||
var/area/A = get_area(C)
|
||||
if(istype(A, /area/chapel))
|
||||
to_chat(C, "<span class='danger'>You don't belong here!</span>")
|
||||
C.adjustFireLoss(5)
|
||||
C.adjust_fire_stacks(6)
|
||||
C.IgniteMob()
|
||||
|
||||
/obj/item/organ/tongue/vampire
|
||||
name = "vampire tongue"
|
||||
actions_types = list(/datum/action/item_action/organ_action/vampire)
|
||||
color = "#1C1C1C"
|
||||
var/drain_cooldown = 0
|
||||
|
||||
#define VAMP_DRAIN_AMOUNT 50
|
||||
|
||||
/datum/action/item_action/organ_action/vampire
|
||||
name = "Drain Victim"
|
||||
desc = "Leech blood from any carbon victim you are passively grabbing."
|
||||
|
||||
/datum/action/item_action/organ_action/vampire/Trigger()
|
||||
. = ..()
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/H = owner
|
||||
var/obj/item/organ/tongue/vampire/V = target
|
||||
if(V.drain_cooldown >= world.time)
|
||||
to_chat(H, "<span class='notice'>You just drained blood, wait a few seconds.</span>")
|
||||
return
|
||||
if(H.pulling && iscarbon(H.pulling))
|
||||
var/mob/living/carbon/victim = H.pulling
|
||||
if(H.blood_volume >= BLOOD_VOLUME_MAXIMUM)
|
||||
to_chat(H, "<span class='notice'>You're already full!</span>")
|
||||
return
|
||||
if(victim.stat == DEAD)
|
||||
to_chat(H, "<span class='notice'>You need a living victim!</span>")
|
||||
return
|
||||
if(!victim.blood_volume || (victim.dna && ((NOBLOOD in victim.dna.species.species_traits) || victim.dna.species.exotic_blood)))
|
||||
to_chat(H, "<span class='notice'>[victim] doesn't have blood!</span>")
|
||||
return
|
||||
V.drain_cooldown = world.time + 30
|
||||
if(victim.anti_magic_check(FALSE, TRUE, FALSE, 0))
|
||||
to_chat(victim, "<span class='warning'>[H] tries to bite you, but stops before touching you!</span>")
|
||||
to_chat(H, "<span class='warning'>[victim] is blessed! You stop just in time to avoid catching fire.</span>")
|
||||
return
|
||||
if(!do_after(H, 30, target = victim))
|
||||
return
|
||||
var/blood_volume_difference = BLOOD_VOLUME_MAXIMUM - H.blood_volume //How much capacity we have left to absorb blood
|
||||
var/drained_blood = min(victim.blood_volume, VAMP_DRAIN_AMOUNT, blood_volume_difference)
|
||||
to_chat(victim, "<span class='danger'>[H] is draining your blood!</span>")
|
||||
to_chat(H, "<span class='notice'>You drain some blood!</span>")
|
||||
playsound(H, 'sound/items/drink.ogg', 30, 1, -2)
|
||||
victim.blood_volume = CLAMP(victim.blood_volume - drained_blood, 0, BLOOD_VOLUME_MAXIMUM)
|
||||
H.blood_volume = CLAMP(H.blood_volume + drained_blood, 0, BLOOD_VOLUME_MAXIMUM)
|
||||
if(!victim.blood_volume)
|
||||
to_chat(H, "<span class='warning'>You finish off [victim]'s blood supply!</span>")
|
||||
|
||||
#undef VAMP_DRAIN_AMOUNT
|
||||
|
||||
/obj/item/organ/heart/vampire
|
||||
name = "vampire heart"
|
||||
actions_types = list(/datum/action/item_action/organ_action/vampire_heart)
|
||||
color = "#1C1C1C"
|
||||
|
||||
/datum/action/item_action/organ_action/vampire_heart
|
||||
name = "Check Blood Level"
|
||||
desc = "Check how much blood you have remaining."
|
||||
|
||||
/datum/action/item_action/organ_action/vampire_heart/Trigger()
|
||||
. = ..()
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/H = owner
|
||||
to_chat(H, "<span class='notice'>Current blood level: [H.blood_volume]/[BLOOD_VOLUME_MAXIMUM].</span>")
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/shapeshift/bat
|
||||
name = "Bat Form"
|
||||
desc = "Take on the shape a space bat."
|
||||
invocation = "Squeak!"
|
||||
charge_max = 50
|
||||
cooldown_min = 50
|
||||
shapeshift_type = /mob/living/simple_animal/hostile/retaliate/bat
|
||||
var/ventcrawl_nude_only = TRUE
|
||||
var/transfer_name = TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/shapeshift/bat/Shapeshift(mob/living/caster) //cit change
|
||||
var/obj/shapeshift_holder/H = locate() in caster
|
||||
if(H)
|
||||
to_chat(caster, "<span class='warning'>You're already shapeshifted!</span>")
|
||||
return
|
||||
|
||||
var/mob/living/shape = new shapeshift_type(caster.loc)
|
||||
H = new(shape,src,caster)
|
||||
if(istype(H, /mob/living/simple_animal))
|
||||
var/mob/living/simple_animal/SA = H
|
||||
if((caster.blood_volume >= (BLOOD_VOLUME_BAD*caster.blood_ratio)) || (ventcrawl_nude_only && length(caster.get_equipped_items(include_pockets = TRUE))))
|
||||
SA.ventcrawler = FALSE
|
||||
if(transfer_name)
|
||||
H.name = caster.name
|
||||
|
||||
clothes_req = 0
|
||||
human_req = 0
|
||||
@@ -1,98 +0,0 @@
|
||||
#define REGENERATION_DELAY 60 // After taking damage, how long it takes for automatic regeneration to begin
|
||||
|
||||
/datum/species/zombie
|
||||
// 1spooky
|
||||
name = "High-Functioning Zombie"
|
||||
id = "zombie"
|
||||
say_mod = "moans"
|
||||
sexes = 0
|
||||
blacklisted = 1
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/zombie
|
||||
species_traits = list(NOBLOOD,NOZOMBIE,NOTRANSSTING)
|
||||
inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NOBREATH,TRAIT_NODEATH,TRAIT_FAKEDEATH)
|
||||
inherent_biotypes = list(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
|
||||
|
||||
/datum/species/zombie/notspaceproof
|
||||
id = "notspaceproofzombie"
|
||||
limbs_id = "zombie"
|
||||
blacklisted = 0
|
||||
inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_RADIMMUNE,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NOBREATH,TRAIT_NODEATH,TRAIT_FAKEDEATH)
|
||||
|
||||
/datum/species/zombie/notspaceproof/check_roundstart_eligible()
|
||||
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/datum/species/zombie/infectious
|
||||
name = "Infectious Zombie"
|
||||
id = "memezombies"
|
||||
limbs_id = "zombie"
|
||||
mutanthands = /obj/item/zombie_hand
|
||||
armor = 20 // 120 damage to KO a zombie, which kills it
|
||||
speedmod = 1.6
|
||||
mutanteyes = /obj/item/organ/eyes/night_vision/zombie
|
||||
var/heal_rate = 1
|
||||
var/regen_cooldown = 0
|
||||
|
||||
/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)
|
||||
. = ..()
|
||||
if(.)
|
||||
regen_cooldown = world.time + REGENERATION_DELAY
|
||||
|
||||
/datum/species/zombie/infectious/spec_life(mob/living/carbon/C)
|
||||
. = ..()
|
||||
C.a_intent = INTENT_HARM // THE SUFFERING MUST FLOW
|
||||
|
||||
//Zombies never actually die, they just fall down until they regenerate enough to rise back up.
|
||||
//They must be restrained, beheaded or gibbed to stop being a threat.
|
||||
if(regen_cooldown < world.time)
|
||||
var/heal_amt = heal_rate
|
||||
if(C.InCritical())
|
||||
heal_amt *= 2
|
||||
C.heal_overall_damage(heal_amt,heal_amt)
|
||||
C.adjustToxLoss(-heal_amt)
|
||||
if(!C.InCritical() && prob(4))
|
||||
playsound(C, pick(spooks), 50, TRUE, 10)
|
||||
|
||||
//Congrats you somehow died so hard you stopped being a zombie
|
||||
/datum/species/zombie/infectious/spec_death(gibbed, mob/living/carbon/C)
|
||||
. = ..()
|
||||
var/obj/item/organ/zombie_infection/infection
|
||||
infection = C.getorganslot(ORGAN_SLOT_ZOMBIE)
|
||||
if(infection)
|
||||
qdel(infection)
|
||||
|
||||
/datum/species/zombie/infectious/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
. = ..()
|
||||
|
||||
// Deal with the source of this zombie corruption
|
||||
// Infection organ needs to be handled separately from mutant_organs
|
||||
// because it persists through species transitions
|
||||
var/obj/item/organ/zombie_infection/infection
|
||||
infection = C.getorganslot(ORGAN_SLOT_ZOMBIE)
|
||||
if(!infection)
|
||||
infection = new()
|
||||
infection.Insert(C)
|
||||
|
||||
|
||||
// Your skin falls off
|
||||
/datum/species/krokodil_addict
|
||||
name = "Human"
|
||||
id = "goofzombies"
|
||||
limbs_id = "zombie" //They look like zombies
|
||||
sexes = 0
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/zombie
|
||||
mutanttongue = /obj/item/organ/tongue/zombie
|
||||
|
||||
#undef REGENERATION_DELAY
|
||||
@@ -1,755 +0,0 @@
|
||||
///////////////////////
|
||||
//UPDATE_ICONS SYSTEM//
|
||||
///////////////////////
|
||||
/* Keep these comments up-to-date if you -insist- on hurting my code-baby ;_;
|
||||
This system allows you to update individual mob-overlays, without regenerating them all each time.
|
||||
When we generate overlays we generate the standing version and then rotate the mob as necessary..
|
||||
|
||||
As of the time of writing there are 20 layers within this list. Please try to keep this from increasing. //22 and counting, good job guys
|
||||
var/overlays_standing[20] //For the standing stance
|
||||
|
||||
Most of the time we only wish to update one overlay:
|
||||
e.g. - we dropped the fireaxe out of our left hand and need to remove its icon from our mob
|
||||
e.g.2 - our hair colour has changed, so we need to update our hair icons on our mob
|
||||
In these cases, instead of updating every overlay using the old behaviour (regenerate_icons), we instead call
|
||||
the appropriate update_X proc.
|
||||
e.g. - update_l_hand()
|
||||
e.g.2 - update_hair()
|
||||
|
||||
Note: Recent changes by aranclanos+carn:
|
||||
update_icons() no longer needs to be called.
|
||||
the system is easier to use. update_icons() should not be called unless you absolutely -know- you need it.
|
||||
IN ALL OTHER CASES it's better to just call the specific update_X procs.
|
||||
|
||||
Note: The defines for layer numbers is now kept exclusvely in __DEFINES/misc.dm instead of being defined there,
|
||||
then redefined and undefiend everywhere else. If you need to change the layering of sprites (or add a new layer)
|
||||
that's where you should start.
|
||||
|
||||
All of this means that this code is more maintainable, faster and still fairly easy to use.
|
||||
|
||||
There are several things that need to be remembered:
|
||||
> Whenever we do something that should cause an overlay to update (which doesn't use standard procs
|
||||
( i.e. you do something like l_hand = /obj/item/something new(src), rather than using the helper procs)
|
||||
You will need to call the relevant update_inv_* proc
|
||||
|
||||
All of these are named after the variable they update from. They are defined at the mob/ level like
|
||||
update_clothing was, so you won't cause undefined proc runtimes with usr.update_inv_wear_id() if the usr is a
|
||||
slime etc. Instead, it'll just return without doing any work. So no harm in calling it for slimes and such.
|
||||
|
||||
|
||||
> There are also these special cases:
|
||||
update_damage_overlays() //handles damage overlays for brute/burn damage
|
||||
update_body() //Handles updating your mob's body layer and mutant bodyparts
|
||||
as well as sprite-accessories that didn't really fit elsewhere (underwear, undershirts, socks, lips, eyes)
|
||||
//NOTE: update_mutantrace() is now merged into this!
|
||||
update_hair() //Handles updating your hair overlay (used to be update_face, but mouth and
|
||||
eyes were merged into update_body())
|
||||
|
||||
|
||||
*/
|
||||
|
||||
//HAIR OVERLAY
|
||||
/mob/living/carbon/human/update_hair()
|
||||
dna.species.handle_hair(src)
|
||||
|
||||
//used when putting/removing clothes that hide certain mutant body parts to just update those and not update the whole body.
|
||||
/mob/living/carbon/human/proc/update_mutant_bodyparts()
|
||||
dna.species.handle_mutant_bodyparts(src)
|
||||
|
||||
|
||||
/mob/living/carbon/human/update_body()
|
||||
remove_overlay(BODY_LAYER)
|
||||
dna.species.handle_body(src)
|
||||
..()
|
||||
|
||||
/mob/living/carbon/human/update_fire()
|
||||
..((fire_stacks > 3) ? "Standing" : "Generic_mob_burning")
|
||||
|
||||
|
||||
/* --------------------------------------- */
|
||||
//For legacy support.
|
||||
/mob/living/carbon/human/regenerate_icons()
|
||||
|
||||
if(!..())
|
||||
icon_render_key = null //invalidate bodyparts cache
|
||||
update_body()
|
||||
update_hair()
|
||||
update_inv_w_uniform()
|
||||
update_inv_wear_id()
|
||||
update_inv_gloves()
|
||||
update_inv_glasses()
|
||||
update_inv_ears()
|
||||
update_inv_shoes()
|
||||
update_inv_s_store()
|
||||
update_inv_wear_mask()
|
||||
update_inv_head()
|
||||
update_inv_belt()
|
||||
update_inv_back()
|
||||
update_inv_wear_suit()
|
||||
update_inv_pockets()
|
||||
update_inv_neck()
|
||||
update_transform()
|
||||
//mutations
|
||||
update_mutations_overlay()
|
||||
//damage overlays
|
||||
update_damage_overlays()
|
||||
|
||||
/* --------------------------------------- */
|
||||
//vvvvvv UPDATE_INV PROCS vvvvvv
|
||||
|
||||
/mob/living/carbon/human/update_inv_w_uniform()
|
||||
remove_overlay(UNIFORM_LAYER)
|
||||
|
||||
if(client && hud_used)
|
||||
var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_W_UNIFORM]
|
||||
inv.update_icon()
|
||||
|
||||
if(istype(w_uniform, /obj/item/clothing/under))
|
||||
var/obj/item/clothing/under/U = w_uniform
|
||||
U.screen_loc = ui_iclothing
|
||||
if(client && hud_used && hud_used.hud_shown)
|
||||
if(hud_used.inventory_shown)
|
||||
client.screen += w_uniform
|
||||
update_observer_view(w_uniform,1)
|
||||
|
||||
if(wear_suit && (wear_suit.flags_inv & HIDEJUMPSUIT))
|
||||
return
|
||||
|
||||
|
||||
var/t_color = U.item_color
|
||||
if(!t_color)
|
||||
t_color = U.icon_state
|
||||
if(U.suit_style == NORMAL_SUIT_STYLE)
|
||||
if(U.adjusted == ALT_STYLE)
|
||||
t_color = "[t_color]_d"
|
||||
|
||||
var/alt_worn = U.alternate_worn_icon
|
||||
|
||||
if(!U.force_alternate_icon && U.mutantrace_variation && U.suit_style == DIGITIGRADE_SUIT_STYLE)
|
||||
alt_worn = 'modular_citadel/icons/mob/uniform_digi.dmi'
|
||||
|
||||
var/mutable_appearance/uniform_overlay
|
||||
|
||||
if(dna && dna.species.sexes)
|
||||
var/G = (gender == FEMALE) ? "f" : "m"
|
||||
if(G == "f" && U.fitted != NO_FEMALE_UNIFORM)
|
||||
uniform_overlay = U.build_worn_icon(state = "[t_color]", default_layer = UNIFORM_LAYER, default_icon_file = (alt_worn ? alt_worn : 'icons/mob/uniform.dmi'), isinhands = FALSE, femaleuniform = U.fitted)
|
||||
|
||||
if(!uniform_overlay)
|
||||
uniform_overlay = U.build_worn_icon(state = "[t_color]", default_layer = UNIFORM_LAYER, default_icon_file = (alt_worn ? alt_worn : 'icons/mob/uniform.dmi'), isinhands = FALSE)
|
||||
|
||||
|
||||
if(OFFSET_UNIFORM in dna.species.offset_features)
|
||||
uniform_overlay.pixel_x += dna.species.offset_features[OFFSET_UNIFORM][1]
|
||||
uniform_overlay.pixel_y += dna.species.offset_features[OFFSET_UNIFORM][2]
|
||||
overlays_standing[UNIFORM_LAYER] = uniform_overlay
|
||||
|
||||
apply_overlay(UNIFORM_LAYER)
|
||||
update_mutant_bodyparts()
|
||||
|
||||
|
||||
/mob/living/carbon/human/update_inv_wear_id()
|
||||
remove_overlay(ID_LAYER)
|
||||
|
||||
if(client && hud_used)
|
||||
var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_WEAR_ID]
|
||||
inv.update_icon()
|
||||
|
||||
var/mutable_appearance/id_overlay = overlays_standing[ID_LAYER]
|
||||
|
||||
if(wear_id)
|
||||
wear_id.screen_loc = ui_id
|
||||
if(client && hud_used && hud_used.hud_shown)
|
||||
client.screen += wear_id
|
||||
update_observer_view(wear_id)
|
||||
|
||||
//TODO: add an icon file for ID slot stuff, so it's less snowflakey
|
||||
id_overlay = wear_id.build_worn_icon(state = wear_id.item_state, default_layer = ID_LAYER, default_icon_file = ((wear_id.alternate_worn_icon) ? wear_id.alternate_worn_icon : 'icons/mob/mob.dmi'))
|
||||
if(OFFSET_ID in dna.species.offset_features)
|
||||
id_overlay.pixel_x += dna.species.offset_features[OFFSET_ID][1]
|
||||
id_overlay.pixel_y += dna.species.offset_features[OFFSET_ID][2]
|
||||
overlays_standing[ID_LAYER] = id_overlay
|
||||
apply_overlay(ID_LAYER)
|
||||
|
||||
|
||||
/mob/living/carbon/human/update_inv_gloves()
|
||||
remove_overlay(GLOVES_LAYER)
|
||||
|
||||
if(client && hud_used && hud_used.inv_slots[SLOT_GLOVES])
|
||||
var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_GLOVES]
|
||||
inv.update_icon()
|
||||
|
||||
if(!gloves && bloody_hands)
|
||||
var/mutable_appearance/bloody_overlay = mutable_appearance('icons/effects/blood.dmi', "bloodyhands", -GLOVES_LAYER, color = blood_DNA_to_color())
|
||||
if(get_num_arms() < 2)
|
||||
if(has_left_hand())
|
||||
bloody_overlay.icon_state = "bloodyhands_left"
|
||||
else if(has_right_hand())
|
||||
bloody_overlay.icon_state = "bloodyhands_right"
|
||||
|
||||
overlays_standing[GLOVES_LAYER] = bloody_overlay
|
||||
|
||||
var/mutable_appearance/gloves_overlay = overlays_standing[GLOVES_LAYER]
|
||||
if(gloves)
|
||||
gloves.screen_loc = ui_gloves
|
||||
if(client && hud_used && hud_used.hud_shown)
|
||||
if(hud_used.inventory_shown)
|
||||
client.screen += gloves
|
||||
update_observer_view(gloves,1)
|
||||
var/t_state = gloves.item_state
|
||||
if(!t_state)
|
||||
t_state = gloves.icon_state
|
||||
overlays_standing[GLOVES_LAYER] = gloves.build_worn_icon(state = t_state, default_layer = GLOVES_LAYER, default_icon_file = ((gloves.alternate_worn_icon) ? gloves.alternate_worn_icon : 'icons/mob/hands.dmi'))
|
||||
gloves_overlay = overlays_standing[GLOVES_LAYER]
|
||||
if(OFFSET_GLOVES in dna.species.offset_features)
|
||||
gloves_overlay.pixel_x += dna.species.offset_features[OFFSET_GLOVES][1]
|
||||
gloves_overlay.pixel_y += dna.species.offset_features[OFFSET_GLOVES][2]
|
||||
overlays_standing[GLOVES_LAYER] = gloves_overlay
|
||||
apply_overlay(GLOVES_LAYER)
|
||||
|
||||
|
||||
/mob/living/carbon/human/update_inv_glasses()
|
||||
remove_overlay(GLASSES_LAYER)
|
||||
|
||||
if(!get_bodypart(BODY_ZONE_HEAD)) //decapitated
|
||||
return
|
||||
|
||||
if(client && hud_used)
|
||||
var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_GLASSES]
|
||||
inv.update_icon()
|
||||
|
||||
if(glasses)
|
||||
glasses.screen_loc = ui_glasses //...draw the item in the inventory screen
|
||||
if(client && hud_used && hud_used.hud_shown)
|
||||
if(hud_used.inventory_shown) //if the inventory is open ...
|
||||
client.screen += glasses //Either way, add the item to the HUD
|
||||
update_observer_view(glasses,1)
|
||||
if(!(head && (head.flags_inv & HIDEEYES)) && !(wear_mask && (wear_mask.flags_inv & HIDEEYES)))
|
||||
overlays_standing[GLASSES_LAYER] = glasses.build_worn_icon(state = glasses.icon_state, default_layer = GLASSES_LAYER, default_icon_file = ((glasses.alternate_worn_icon) ? glasses.alternate_worn_icon : 'icons/mob/eyes.dmi'))
|
||||
var/mutable_appearance/glasses_overlay = overlays_standing[GLASSES_LAYER]
|
||||
if(glasses_overlay)
|
||||
if(OFFSET_GLASSES in dna.species.offset_features)
|
||||
glasses_overlay.pixel_x += dna.species.offset_features[OFFSET_GLASSES][1]
|
||||
glasses_overlay.pixel_y += dna.species.offset_features[OFFSET_GLASSES][2]
|
||||
overlays_standing[GLASSES_LAYER] = glasses_overlay
|
||||
apply_overlay(GLASSES_LAYER)
|
||||
|
||||
|
||||
/mob/living/carbon/human/update_inv_ears()
|
||||
remove_overlay(EARS_LAYER)
|
||||
|
||||
if(!get_bodypart(BODY_ZONE_HEAD)) //decapitated
|
||||
return
|
||||
|
||||
if(client && hud_used)
|
||||
var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_EARS]
|
||||
inv.update_icon()
|
||||
|
||||
if(ears)
|
||||
ears.screen_loc = ui_ears //move the item to the appropriate screen loc
|
||||
if(client && hud_used && hud_used.hud_shown)
|
||||
if(hud_used.inventory_shown) //if the inventory is open
|
||||
client.screen += ears //add it to the client's screen
|
||||
update_observer_view(ears,1)
|
||||
|
||||
overlays_standing[EARS_LAYER] = ears.build_worn_icon(state = ears.icon_state, default_layer = EARS_LAYER, default_icon_file = ((ears.alternate_worn_icon) ? ears.alternate_worn_icon : 'icons/mob/ears.dmi'))
|
||||
var/mutable_appearance/ears_overlay = overlays_standing[EARS_LAYER]
|
||||
if(OFFSET_EARS in dna.species.offset_features)
|
||||
ears_overlay.pixel_x += dna.species.offset_features[OFFSET_EARS][1]
|
||||
ears_overlay.pixel_y += dna.species.offset_features[OFFSET_EARS][2]
|
||||
overlays_standing[EARS_LAYER] = ears_overlay
|
||||
apply_overlay(EARS_LAYER)
|
||||
|
||||
|
||||
/mob/living/carbon/human/update_inv_shoes()
|
||||
remove_overlay(SHOES_LAYER)
|
||||
|
||||
if(get_num_legs() <2)
|
||||
return
|
||||
|
||||
if(client && hud_used)
|
||||
var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_SHOES]
|
||||
inv.update_icon()
|
||||
/*
|
||||
if(!shoes && bloody_feet)
|
||||
var/mutable_appearance/bloody_overlay = mutable_appearance('icons/effects/blood.dmi', "bloodyfeet", -SHOES_LAYER, color = blood_DNA_to_color())
|
||||
if(dna.features["taur"] != "None")
|
||||
if(dna.features["taur"] in GLOB.noodle_taurs)
|
||||
bloody_overlay = mutable_appearance('modular_citadel/icons/mob/64x32_effects.dmi', "snekbloodyfeet", -SHOES_LAYER, color = blood_DNA_to_color())
|
||||
if(get_num_legs() < 2)
|
||||
if(has_left_leg())
|
||||
bloody_overlay.icon_state = "snekbloodyfeet_left"
|
||||
else if(has_right_leg())
|
||||
bloody_overlay.icon_state = "snekbloodyfeet_right"
|
||||
else if(dna.features["taur"] in GLOB.paw_taurs)
|
||||
bloody_overlay = mutable_appearance('modular_citadel/icons/mob/64x32_effects.dmi', "pawbloodyfeet", -SHOES_LAYER, color = blood_DNA_to_color())
|
||||
if(get_num_legs() < 2)
|
||||
if(has_left_leg())
|
||||
bloody_overlay.icon_state = "pawbloodyfeet_left"
|
||||
else if(has_right_leg())
|
||||
bloody_overlay.icon_state = "pawbloodyfeet_right"
|
||||
else
|
||||
if(get_num_legs() < 2)
|
||||
if(has_left_leg())
|
||||
bloody_overlay.icon_state = "bloodyfeet_left"
|
||||
else if(has_right_leg())
|
||||
bloody_overlay.icon_state = "bloodyfeet_right"
|
||||
|
||||
overlays_standing[GLOVES_LAYER] = bloody_overlay*/
|
||||
|
||||
if(shoes)
|
||||
var/obj/item/clothing/shoes/S = shoes
|
||||
shoes.screen_loc = ui_shoes //move the item to the appropriate screen loc
|
||||
if(client && hud_used && hud_used.hud_shown)
|
||||
if(hud_used.inventory_shown) //if the inventory is open
|
||||
client.screen += shoes //add it to client's screen
|
||||
update_observer_view(shoes,1)
|
||||
if(S.mutantrace_variation)
|
||||
if(S.adjusted == ALT_STYLE)
|
||||
S.alternate_worn_icon = 'modular_citadel/icons/mob/digishoes.dmi'
|
||||
else
|
||||
S.alternate_worn_icon = null
|
||||
var/t_state = shoes.item_state
|
||||
if (!t_state)
|
||||
t_state = shoes.icon_state
|
||||
overlays_standing[SHOES_LAYER] = shoes.build_worn_icon(state = t_state, default_layer = SHOES_LAYER, default_icon_file = ((shoes.alternate_worn_icon) ? shoes.alternate_worn_icon : 'icons/mob/feet.dmi'))
|
||||
var/mutable_appearance/shoes_overlay = overlays_standing[SHOES_LAYER]
|
||||
if(OFFSET_SHOES in dna.species.offset_features)
|
||||
shoes_overlay.pixel_x += dna.species.offset_features[OFFSET_SHOES][1]
|
||||
shoes_overlay.pixel_y += dna.species.offset_features[OFFSET_SHOES][2]
|
||||
overlays_standing[SHOES_LAYER] = shoes_overlay
|
||||
apply_overlay(SHOES_LAYER)
|
||||
|
||||
/mob/living/carbon/human/update_inv_s_store()
|
||||
remove_overlay(SUIT_STORE_LAYER)
|
||||
|
||||
if(client && hud_used)
|
||||
var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_S_STORE]
|
||||
inv.update_icon()
|
||||
|
||||
if(s_store)
|
||||
s_store.screen_loc = ui_sstore1
|
||||
if(client && hud_used && hud_used.hud_shown)
|
||||
client.screen += s_store
|
||||
update_observer_view(s_store)
|
||||
var/t_state = s_store.item_state
|
||||
if(!t_state)
|
||||
t_state = s_store.icon_state
|
||||
overlays_standing[SUIT_STORE_LAYER] = mutable_appearance(((s_store.alternate_worn_icon) ? s_store.alternate_worn_icon : 'icons/mob/belt_mirror.dmi'), t_state, -SUIT_STORE_LAYER)
|
||||
var/mutable_appearance/s_store_overlay = overlays_standing[SUIT_STORE_LAYER]
|
||||
if(OFFSET_S_STORE in dna.species.offset_features)
|
||||
s_store_overlay.pixel_x += dna.species.offset_features[OFFSET_S_STORE][1]
|
||||
s_store_overlay.pixel_y += dna.species.offset_features[OFFSET_S_STORE][2]
|
||||
overlays_standing[SUIT_STORE_LAYER] = s_store_overlay
|
||||
apply_overlay(SUIT_STORE_LAYER)
|
||||
|
||||
|
||||
/mob/living/carbon/human/update_inv_head()
|
||||
..()
|
||||
update_mutant_bodyparts()
|
||||
if(head)
|
||||
remove_overlay(HEAD_LAYER)
|
||||
var/obj/item/clothing/head/H = head
|
||||
if(H.mutantrace_variation)
|
||||
if(H.muzzle_var == ALT_STYLE)
|
||||
H.alternate_worn_icon = 'modular_citadel/icons/mob/muzzled_helmet.dmi'
|
||||
else
|
||||
H.alternate_worn_icon = null
|
||||
|
||||
overlays_standing[HEAD_LAYER] = H.build_worn_icon(state = H.icon_state, default_layer = HEAD_LAYER, default_icon_file = ((head.alternate_worn_icon) ? H.alternate_worn_icon : 'icons/mob/head.dmi'))
|
||||
var/mutable_appearance/head_overlay = overlays_standing[HEAD_LAYER]
|
||||
|
||||
if(OFFSET_HEAD in dna.species.offset_features)
|
||||
head_overlay.pixel_x += dna.species.offset_features[OFFSET_HEAD][1]
|
||||
head_overlay.pixel_y += dna.species.offset_features[OFFSET_HEAD][2]
|
||||
overlays_standing[HEAD_LAYER] = head_overlay
|
||||
apply_overlay(HEAD_LAYER)
|
||||
|
||||
/mob/living/carbon/human/update_inv_belt()
|
||||
remove_overlay(BELT_LAYER)
|
||||
|
||||
if(client && hud_used)
|
||||
var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_BELT]
|
||||
inv.update_icon()
|
||||
|
||||
if(belt)
|
||||
belt.screen_loc = ui_belt
|
||||
if(client && hud_used && hud_used.hud_shown)
|
||||
client.screen += belt
|
||||
update_observer_view(belt)
|
||||
|
||||
var/t_state = belt.item_state
|
||||
if(!t_state)
|
||||
t_state = belt.icon_state
|
||||
|
||||
overlays_standing[BELT_LAYER] = belt.build_worn_icon(state = t_state, default_layer = BELT_LAYER, default_icon_file = ((belt.alternate_worn_icon) ? belt.alternate_worn_icon : 'icons/mob/belt.dmi'))
|
||||
var/mutable_appearance/belt_overlay = overlays_standing[BELT_LAYER]
|
||||
if(OFFSET_BELT in dna.species.offset_features)
|
||||
belt_overlay.pixel_x += dna.species.offset_features[OFFSET_BELT][1]
|
||||
belt_overlay.pixel_y += dna.species.offset_features[OFFSET_BELT][2]
|
||||
overlays_standing[BELT_LAYER] = belt_overlay
|
||||
apply_overlay(BELT_LAYER)
|
||||
|
||||
|
||||
/mob/living/carbon/human/update_inv_wear_suit()
|
||||
remove_overlay(SUIT_LAYER)
|
||||
|
||||
if(client && hud_used)
|
||||
var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_WEAR_SUIT]
|
||||
inv.update_icon()
|
||||
|
||||
if(wear_suit)
|
||||
var/obj/item/clothing/suit/S = wear_suit
|
||||
var/item_level_support = FALSE // LISTEN! If you must degrade the code with further snowflake checks, at least keep it compatible with worn non-clothing items!
|
||||
if(!istype(S))
|
||||
item_level_support = TRUE
|
||||
wear_suit.screen_loc = ui_oclothing
|
||||
if(client && hud_used && hud_used.hud_shown)
|
||||
if(hud_used.inventory_shown)
|
||||
client.screen += wear_suit
|
||||
update_observer_view(wear_suit,1)
|
||||
|
||||
if(!item_level_support && !S.force_alternate_icon)
|
||||
if(S.mutantrace_variation) //Just make sure we've got this checked too
|
||||
if(S.taurmode == NOT_TAURIC && S.adjusted == ALT_STYLE) //are we not a taur, but we have Digitigrade legs? Run this check first, then.
|
||||
S.alternate_worn_icon = 'modular_citadel/icons/mob/suit_digi.dmi'
|
||||
else
|
||||
S.alternate_worn_icon = null
|
||||
|
||||
if(S.tauric == TRUE) //Are we a suit with tauric mode possible?
|
||||
if(S.taurmode == SNEK_TAURIC)
|
||||
S.alternate_worn_icon = 'modular_citadel/icons/mob/taur_naga.dmi'
|
||||
if(S.taurmode == PAW_TAURIC)
|
||||
S.alternate_worn_icon = 'modular_citadel/icons/mob/taur_canine.dmi'
|
||||
if(S.taurmode == NOT_TAURIC && S.adjusted == ALT_STYLE)
|
||||
S.alternate_worn_icon = 'modular_citadel/icons/mob/suit_digi.dmi'
|
||||
else if(S.taurmode == NOT_TAURIC && S.adjusted == NORMAL_STYLE)
|
||||
S.alternate_worn_icon = null
|
||||
|
||||
overlays_standing[SUIT_LAYER] = S.build_worn_icon(state = wear_suit.icon_state, default_layer = SUIT_LAYER, default_icon_file = ((wear_suit.alternate_worn_icon) ? S.alternate_worn_icon : 'icons/mob/suit.dmi'))
|
||||
var/mutable_appearance/suit_overlay = overlays_standing[SUIT_LAYER]
|
||||
if(OFFSET_SUIT in dna.species.offset_features)
|
||||
suit_overlay.pixel_x += dna.species.offset_features[OFFSET_SUIT][1]
|
||||
suit_overlay.pixel_y += dna.species.offset_features[OFFSET_SUIT][2]
|
||||
if(!item_level_support && S.center)
|
||||
suit_overlay = center_image(suit_overlay, S.dimension_x, S.dimension_y)
|
||||
overlays_standing[SUIT_LAYER] = suit_overlay
|
||||
update_hair()
|
||||
update_mutant_bodyparts()
|
||||
|
||||
apply_overlay(SUIT_LAYER)
|
||||
|
||||
|
||||
/mob/living/carbon/human/update_inv_pockets()
|
||||
if(client && hud_used)
|
||||
var/obj/screen/inventory/inv
|
||||
|
||||
inv = hud_used.inv_slots[SLOT_L_STORE]
|
||||
inv.update_icon()
|
||||
|
||||
inv = hud_used.inv_slots[SLOT_R_STORE]
|
||||
inv.update_icon()
|
||||
|
||||
if(l_store)
|
||||
l_store.screen_loc = ui_storage1
|
||||
if(hud_used.hud_shown)
|
||||
client.screen += l_store
|
||||
update_observer_view(l_store)
|
||||
|
||||
if(r_store)
|
||||
r_store.screen_loc = ui_storage2
|
||||
if(hud_used.hud_shown)
|
||||
client.screen += r_store
|
||||
update_observer_view(r_store)
|
||||
|
||||
|
||||
/mob/living/carbon/human/update_inv_wear_mask()
|
||||
..()
|
||||
if(wear_mask)
|
||||
var/obj/item/clothing/mask/M = wear_mask
|
||||
remove_overlay(FACEMASK_LAYER)
|
||||
if(M.mutantrace_variation)
|
||||
if(M.muzzle_var == ALT_STYLE)
|
||||
M.alternate_worn_icon = 'modular_citadel/icons/mob/muzzled_mask.dmi'
|
||||
else
|
||||
M.alternate_worn_icon = null
|
||||
|
||||
overlays_standing[FACEMASK_LAYER] = M.build_worn_icon(state = wear_mask.icon_state, default_layer = FACEMASK_LAYER, default_icon_file = ((wear_mask.alternate_worn_icon) ? M.alternate_worn_icon : 'icons/mob/mask.dmi'))
|
||||
var/mutable_appearance/mask_overlay = overlays_standing[FACEMASK_LAYER]
|
||||
|
||||
if(OFFSET_FACEMASK in dna.species.offset_features)
|
||||
mask_overlay.pixel_x += dna.species.offset_features[OFFSET_FACEMASK][1]
|
||||
mask_overlay.pixel_y += dna.species.offset_features[OFFSET_FACEMASK][2]
|
||||
overlays_standing[FACEMASK_LAYER] = mask_overlay
|
||||
apply_overlay(FACEMASK_LAYER)
|
||||
update_mutant_bodyparts() //e.g. upgate needed because mask now hides lizard snout
|
||||
|
||||
/mob/living/carbon/human/update_inv_back()
|
||||
..()
|
||||
var/mutable_appearance/back_overlay = overlays_standing[BACK_LAYER]
|
||||
if(back_overlay)
|
||||
remove_overlay(BACK_LAYER)
|
||||
if(OFFSET_BACK in dna.species.offset_features)
|
||||
back_overlay.pixel_x += dna.species.offset_features[OFFSET_BACK][1]
|
||||
back_overlay.pixel_y += dna.species.offset_features[OFFSET_BACK][2]
|
||||
overlays_standing[BACK_LAYER] = back_overlay
|
||||
apply_overlay(BACK_LAYER)
|
||||
|
||||
/proc/wear_female_version(t_color, icon, layer, type)
|
||||
var/index = t_color
|
||||
var/icon/female_clothing_icon = GLOB.female_clothing_icons[index]
|
||||
if(!female_clothing_icon) //Create standing/laying icons if they don't exist
|
||||
generate_female_clothing(index,t_color,icon,type)
|
||||
return mutable_appearance(GLOB.female_clothing_icons[t_color], layer = -layer)
|
||||
|
||||
/mob/living/carbon/human/proc/get_overlays_copy(list/unwantedLayers)
|
||||
var/list/out = new
|
||||
for(var/i in 1 to TOTAL_LAYERS)
|
||||
if(overlays_standing[i])
|
||||
if(i in unwantedLayers)
|
||||
continue
|
||||
out += overlays_standing[i]
|
||||
return out
|
||||
|
||||
//human HUD updates for items in our inventory
|
||||
|
||||
//update whether our head item appears on our hud.
|
||||
/mob/living/carbon/human/update_hud_head(obj/item/I)
|
||||
I.screen_loc = ui_head
|
||||
if(client && hud_used && hud_used.hud_shown)
|
||||
if(hud_used.inventory_shown)
|
||||
client.screen += I
|
||||
update_observer_view(I,1)
|
||||
|
||||
//update whether our mask item appears on our hud.
|
||||
/mob/living/carbon/human/update_hud_wear_mask(obj/item/I)
|
||||
I.screen_loc = ui_mask
|
||||
if(client && hud_used && hud_used.hud_shown)
|
||||
if(hud_used.inventory_shown)
|
||||
client.screen += I
|
||||
update_observer_view(I,1)
|
||||
|
||||
//update whether our neck item appears on our hud.
|
||||
/mob/living/carbon/human/update_hud_neck(obj/item/I)
|
||||
I.screen_loc = ui_neck
|
||||
if(client && hud_used && hud_used.hud_shown)
|
||||
if(hud_used.inventory_shown)
|
||||
client.screen += I
|
||||
update_observer_view(I,1)
|
||||
|
||||
//update whether our back item appears on our hud.
|
||||
/mob/living/carbon/human/update_hud_back(obj/item/I)
|
||||
I.screen_loc = ui_back
|
||||
if(client && hud_used && hud_used.hud_shown)
|
||||
client.screen += I
|
||||
update_observer_view(I)
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Does everything in relation to building the /mutable_appearance used in the mob's overlays list
|
||||
covers:
|
||||
inhands and any other form of worn item
|
||||
centering large appearances
|
||||
layering appearances on custom layers
|
||||
building appearances from custom icon files
|
||||
|
||||
By Remie Richards (yes I'm taking credit because this just removed 90% of the copypaste in update_icons())
|
||||
|
||||
state: A string to use as the state, this is FAR too complex to solve in this proc thanks to shitty old code
|
||||
so it's specified as an argument instead.
|
||||
|
||||
default_layer: The layer to draw this on if no other layer is specified
|
||||
|
||||
default_icon_file: The icon file to draw states from if no other icon file is specified
|
||||
|
||||
isinhands: If true then alternate_worn_icon is skipped so that default_icon_file is used,
|
||||
in this situation default_icon_file is expected to match either the lefthand_ or righthand_ file var
|
||||
|
||||
femalueuniform: A value matching a uniform item's fitted var, if this is anything but NO_FEMALE_UNIFORM, we
|
||||
generate/load female uniform sprites matching all previously decided variables
|
||||
|
||||
|
||||
*/
|
||||
/obj/item/proc/build_worn_icon(var/state = "", var/default_layer = 0, var/default_icon_file = null, var/isinhands = FALSE, var/femaleuniform = NO_FEMALE_UNIFORM)
|
||||
|
||||
//Find a valid icon file from variables+arguments
|
||||
var/file2use
|
||||
if(!isinhands && alternate_worn_icon)
|
||||
file2use = alternate_worn_icon
|
||||
if(!file2use)
|
||||
file2use = default_icon_file
|
||||
|
||||
//Find a valid layer from variables+arguments
|
||||
var/layer2use
|
||||
if(alternate_worn_layer)
|
||||
layer2use = alternate_worn_layer
|
||||
if(!layer2use)
|
||||
layer2use = default_layer
|
||||
|
||||
var/mutable_appearance/standing
|
||||
if(femaleuniform)
|
||||
standing = wear_female_version(state,file2use,layer2use,femaleuniform)
|
||||
if(!standing)
|
||||
standing = mutable_appearance(file2use, state, -layer2use)
|
||||
|
||||
//Get the overlays for this item when it's being worn
|
||||
//eg: ammo counters, primed grenade flashes, etc.
|
||||
var/list/worn_overlays = worn_overlays(isinhands, file2use)
|
||||
if(worn_overlays && worn_overlays.len)
|
||||
standing.overlays.Add(worn_overlays)
|
||||
|
||||
standing = center_image(standing, isinhands ? inhand_x_dimension : worn_x_dimension, isinhands ? inhand_y_dimension : worn_y_dimension)
|
||||
|
||||
//Handle held offsets
|
||||
var/mob/M = loc
|
||||
if(istype(M))
|
||||
var/list/L = get_held_offsets()
|
||||
if(L)
|
||||
standing.pixel_x += L["x"] //+= because of center()ing
|
||||
standing.pixel_y += L["y"]
|
||||
|
||||
standing.alpha = alpha
|
||||
standing.color = color
|
||||
|
||||
return standing
|
||||
|
||||
|
||||
/obj/item/proc/get_held_offsets()
|
||||
var/list/L
|
||||
if(ismob(loc))
|
||||
var/mob/M = loc
|
||||
L = M.get_item_offsets_for_index(M.get_held_index_of_item(src))
|
||||
return L
|
||||
|
||||
|
||||
//Can't think of a better way to do this, sadly
|
||||
/mob/proc/get_item_offsets_for_index(i)
|
||||
switch(i)
|
||||
if(3) //odd = left hands
|
||||
return list("x" = 0, "y" = 16)
|
||||
if(4) //even = right hands
|
||||
return list("x" = 0, "y" = 16)
|
||||
else //No offsets or Unwritten number of hands
|
||||
return list("x" = 0, "y" = 0)
|
||||
|
||||
|
||||
|
||||
//produces a key based on the human's limbs
|
||||
/mob/living/carbon/human/generate_icon_render_key()
|
||||
. = "[dna.species.limbs_id]"
|
||||
|
||||
if(dna.check_mutation(HULK))
|
||||
. += "-coloured-hulk"
|
||||
else if(dna.species.use_skintones)
|
||||
. += "-coloured-[skin_tone]"
|
||||
else if(dna.species.fixed_mut_color)
|
||||
. += "-coloured-[dna.species.fixed_mut_color]"
|
||||
else if(dna.features["mcolor"])
|
||||
. += "-coloured-[dna.features["mcolor"]]-[dna.features["mcolor2"]]-[dna.features["mcolor3"]]"
|
||||
else
|
||||
. += "-not_coloured"
|
||||
|
||||
. += "-[gender]"
|
||||
|
||||
|
||||
var/is_taur = FALSE
|
||||
var/mob/living/carbon/human/H = src
|
||||
if(("taur" in H.dna.species.mutant_bodyparts) && (H.dna.features["taur"] != "None"))
|
||||
is_taur = TRUE
|
||||
|
||||
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
|
||||
if(istype(BP, /obj/item/bodypart/r_leg) || istype(BP, /obj/item/bodypart/l_leg))
|
||||
if(is_taur)
|
||||
continue
|
||||
|
||||
|
||||
. += "-[BP.body_zone]"
|
||||
if(BP.status == BODYPART_ORGANIC)
|
||||
. += "-organic"
|
||||
else
|
||||
. += "-robotic"
|
||||
if(BP.use_digitigrade)
|
||||
. += "-digitigrade[BP.use_digitigrade]"
|
||||
if(BP.dmg_overlay_type)
|
||||
. += "-[BP.dmg_overlay_type]"
|
||||
if(BP.body_markings)
|
||||
. += "-[BP.body_markings]"
|
||||
else
|
||||
. += "-no_marking"
|
||||
|
||||
if(HAS_TRAIT(src, TRAIT_HUSK))
|
||||
. += "-husk"
|
||||
|
||||
/mob/living/carbon/human/load_limb_from_cache()
|
||||
..()
|
||||
update_hair()
|
||||
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/update_observer_view(obj/item/I, inventory)
|
||||
if(observers && observers.len)
|
||||
for(var/M in observers)
|
||||
var/mob/dead/observe = M
|
||||
if(observe.client && observe.client.eye == src)
|
||||
if(observe.hud_used)
|
||||
if(inventory && !observe.hud_used.inventory_shown)
|
||||
continue
|
||||
observe.client.screen += I
|
||||
else
|
||||
observers -= observe
|
||||
if(!observers.len)
|
||||
observers = null
|
||||
break
|
||||
|
||||
// Only renders the head of the human
|
||||
/mob/living/carbon/human/proc/update_body_parts_head_only()
|
||||
if (!dna)
|
||||
return
|
||||
|
||||
if (!dna.species)
|
||||
return
|
||||
|
||||
var/obj/item/bodypart/HD = get_bodypart("head")
|
||||
|
||||
if (!istype(HD))
|
||||
return
|
||||
|
||||
HD.update_limb()
|
||||
|
||||
add_overlay(HD.get_limb_icon())
|
||||
update_damage_overlays()
|
||||
|
||||
if(HD && !(HAS_TRAIT(src, TRAIT_HUSK)))
|
||||
// lipstick
|
||||
if(lip_style && (LIPS in dna.species.species_traits))
|
||||
var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/human_face.dmi', "lips_[lip_style]", -BODY_LAYER)
|
||||
lip_overlay.color = lip_color
|
||||
if(OFFSET_LIPS in dna.species.offset_features)
|
||||
lip_overlay.pixel_x += dna.species.offset_features[OFFSET_LIPS][1]
|
||||
lip_overlay.pixel_y += dna.species.offset_features[OFFSET_LIPS][2]
|
||||
add_overlay(lip_overlay)
|
||||
|
||||
// eyes
|
||||
if(!(NOEYES in dna.species.species_traits))
|
||||
var/has_eyes = getorganslot(ORGAN_SLOT_EYES)
|
||||
var/mutable_appearance/eye_overlay
|
||||
if(!has_eyes)
|
||||
eye_overlay = mutable_appearance('icons/mob/human_face.dmi', "eyes_missing", -BODY_LAYER)
|
||||
else
|
||||
eye_overlay = mutable_appearance('icons/mob/human_face.dmi', "eyes", -BODY_LAYER)
|
||||
if((EYECOLOR in dna.species.species_traits) && has_eyes)
|
||||
eye_overlay.color = "#" + eye_color
|
||||
if(OFFSET_EYES in dna.species.offset_features)
|
||||
eye_overlay.pixel_x += dna.species.offset_features[OFFSET_EYES][1]
|
||||
eye_overlay.pixel_y += dna.species.offset_features[OFFSET_EYES][2]
|
||||
add_overlay(eye_overlay)
|
||||
|
||||
dna.species.handle_hair(src)
|
||||
|
||||
update_inv_head()
|
||||
update_inv_wear_mask()
|
||||
@@ -1,756 +0,0 @@
|
||||
/mob/living/carbon/Life()
|
||||
set invisibility = 0
|
||||
|
||||
if(notransform)
|
||||
return
|
||||
|
||||
if(damageoverlaytemp)
|
||||
damageoverlaytemp = 0
|
||||
update_damage_hud()
|
||||
|
||||
//Reagent processing needs to come before breathing, to prevent edge cases.
|
||||
handle_organs()
|
||||
|
||||
. = ..()
|
||||
|
||||
if (QDELETED(src))
|
||||
return
|
||||
|
||||
if(.) //not dead
|
||||
handle_blood()
|
||||
|
||||
if(stat != DEAD)
|
||||
var/bprv = handle_bodyparts()
|
||||
if(bprv & BODYPART_LIFE_UPDATE_HEALTH)
|
||||
updatehealth()
|
||||
update_stamina()
|
||||
|
||||
if(stat != DEAD)
|
||||
handle_brain_damage()
|
||||
|
||||
/* BUG_PROBABLE_CAUSE
|
||||
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
|
||||
|
||||
//Procs called while dead
|
||||
/mob/living/carbon/proc/handle_death()
|
||||
for(var/datum/reagent/R in reagents.reagent_list)
|
||||
if(R.chemical_flags & REAGENT_DEAD_PROCESS)
|
||||
R.on_mob_dead(src)
|
||||
|
||||
///////////////
|
||||
// BREATHING //
|
||||
///////////////
|
||||
|
||||
//Start of a breath chain, calls breathe()
|
||||
/mob/living/carbon/handle_breathing(times_fired)
|
||||
var/next_breath = 4
|
||||
var/obj/item/organ/lungs/L = getorganslot(ORGAN_SLOT_LUNGS)
|
||||
var/obj/item/organ/heart/H = getorganslot(ORGAN_SLOT_HEART)
|
||||
if(L)
|
||||
if(L.damage > L.high_threshold)
|
||||
next_breath--
|
||||
if(H)
|
||||
if(H.damage > H.high_threshold)
|
||||
next_breath--
|
||||
|
||||
if((times_fired % next_breath) == 0 || failed_last_breath)
|
||||
breathe() //Breathe per 4 ticks if healthy, down to 2 if our lungs or heart are damaged, unless suffocating
|
||||
if(failed_last_breath)
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "suffocation", /datum/mood_event/suffocation)
|
||||
else
|
||||
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "suffocation")
|
||||
else
|
||||
if(istype(loc, /obj/))
|
||||
var/obj/location_as_object = loc
|
||||
location_as_object.handle_internal_lifeform(src,0)
|
||||
|
||||
//Second link in a breath chain, calls check_breath()
|
||||
/mob/living/carbon/proc/breathe()
|
||||
var/obj/item/organ/lungs = getorganslot(ORGAN_SLOT_LUNGS)
|
||||
if(reagents.has_reagent("lexorin"))
|
||||
return
|
||||
if(istype(loc, /obj/machinery/atmospherics/components/unary/cryo_cell))
|
||||
return
|
||||
if(istype(loc, /obj/item/dogborg/sleeper))
|
||||
return
|
||||
if(ismob(loc))
|
||||
return
|
||||
if(isbelly(loc))
|
||||
return
|
||||
|
||||
var/datum/gas_mixture/environment
|
||||
if(loc)
|
||||
environment = loc.return_air()
|
||||
|
||||
var/datum/gas_mixture/breath
|
||||
|
||||
if(!getorganslot(ORGAN_SLOT_BREATHING_TUBE))
|
||||
if(health <= HEALTH_THRESHOLD_FULLCRIT || (pulledby && pulledby.grab_state >= GRAB_KILL) || (lungs && lungs.organ_flags & ORGAN_FAILING))
|
||||
losebreath++ //You can't breath at all when in critical or when being choked, so you're going to miss a breath
|
||||
|
||||
else if(health <= crit_threshold)
|
||||
losebreath += 0.25 //You're having trouble breathing in soft crit, so you'll miss a breath one in four times
|
||||
|
||||
//Suffocate
|
||||
if(losebreath >= 1) //You've missed a breath, take oxy damage
|
||||
losebreath--
|
||||
if(prob(10))
|
||||
emote("gasp")
|
||||
if(istype(loc, /obj/))
|
||||
var/obj/loc_as_obj = loc
|
||||
loc_as_obj.handle_internal_lifeform(src,0)
|
||||
else
|
||||
//Breathe from internal
|
||||
breath = get_breath_from_internal(BREATH_VOLUME)
|
||||
|
||||
if(isnull(breath)) //in case of 0 pressure internals
|
||||
|
||||
if(isobj(loc)) //Breathe from loc as object
|
||||
var/obj/loc_as_obj = loc
|
||||
breath = loc_as_obj.handle_internal_lifeform(src, BREATH_VOLUME)
|
||||
|
||||
else if(isturf(loc)) //Breathe from loc as turf
|
||||
var/breath_moles = 0
|
||||
if(environment)
|
||||
breath_moles = environment.total_moles()*BREATH_PERCENTAGE
|
||||
|
||||
breath = loc.remove_air(breath_moles)
|
||||
else //Breathe from loc as obj again
|
||||
if(istype(loc, /obj/))
|
||||
var/obj/loc_as_obj = loc
|
||||
loc_as_obj.handle_internal_lifeform(src,0)
|
||||
|
||||
check_breath(breath)
|
||||
|
||||
if(breath)
|
||||
loc.assume_air(breath)
|
||||
air_update_turf()
|
||||
|
||||
/mob/living/carbon/proc/has_smoke_protection()
|
||||
if(HAS_TRAIT(src, TRAIT_NOBREATH))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
//Third link in a breath chain, calls handle_breath_temperature()
|
||||
/mob/living/carbon/proc/check_breath(datum/gas_mixture/breath)
|
||||
if((status_flags & GODMODE))
|
||||
return
|
||||
|
||||
var/obj/item/organ/lungs = getorganslot(ORGAN_SLOT_LUNGS)
|
||||
if(!lungs)
|
||||
adjustOxyLoss(2)
|
||||
|
||||
//CRIT
|
||||
if(!breath || (breath.total_moles() == 0) || !lungs)
|
||||
if(reagents.has_reagent("epinephrine") && lungs)
|
||||
return
|
||||
adjustOxyLoss(1)
|
||||
|
||||
failed_last_breath = 1
|
||||
throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy)
|
||||
return 0
|
||||
|
||||
var/safe_oxy_min = 16
|
||||
var/safe_oxy_max = 50
|
||||
var/safe_co2_max = 10
|
||||
var/safe_tox_max = 0.05
|
||||
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/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
|
||||
|
||||
|
||||
//OXYGEN
|
||||
if(O2_partialpressure > safe_oxy_max) // Too much Oxygen - blatant CO2 effect copy/pasta
|
||||
if(!o2overloadtime)
|
||||
o2overloadtime = world.time
|
||||
else if(world.time - o2overloadtime > 120)
|
||||
Dizzy(10) // better than a minute of you're fucked KO, but certainly a wake up call. Honk.
|
||||
adjustOxyLoss(3)
|
||||
if(world.time - o2overloadtime > 300)
|
||||
adjustOxyLoss(8)
|
||||
if(prob(20))
|
||||
emote("cough")
|
||||
throw_alert("too_much_oxy", /obj/screen/alert/too_much_oxy)
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "suffocation", /datum/mood_event/suffocation)
|
||||
|
||||
if(O2_partialpressure < safe_oxy_min) //Not enough oxygen
|
||||
if(prob(20))
|
||||
emote("gasp")
|
||||
if(O2_partialpressure > 0)
|
||||
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
|
||||
else
|
||||
adjustOxyLoss(3)
|
||||
failed_last_breath = 1
|
||||
throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy)
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "suffocation", /datum/mood_event/suffocation)
|
||||
|
||||
else //Enough oxygen
|
||||
failed_last_breath = 0
|
||||
o2overloadtime = 0 //reset our counter for this too
|
||||
if(health >= crit_threshold)
|
||||
adjustOxyLoss(-5)
|
||||
oxygen_used = breath_gases[/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
|
||||
|
||||
//CARBON DIOXIDE
|
||||
if(CO2_partialpressure > safe_co2_max)
|
||||
if(!co2overloadtime)
|
||||
co2overloadtime = world.time
|
||||
else if(world.time - co2overloadtime > 120)
|
||||
Unconscious(60)
|
||||
adjustOxyLoss(3)
|
||||
if(world.time - co2overloadtime > 300)
|
||||
adjustOxyLoss(8)
|
||||
if(prob(20))
|
||||
emote("cough")
|
||||
|
||||
else
|
||||
co2overloadtime = 0
|
||||
|
||||
//TOXINS/PLASMA
|
||||
if(Toxins_partialpressure > safe_tox_max)
|
||||
var/ratio = (breath_gases[/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(SA_partialpressure > SA_para_min)
|
||||
Unconscious(60)
|
||||
if(SA_partialpressure > SA_sleep_min)
|
||||
Sleeping(max(AmountSleeping() + 40, 200))
|
||||
else if(SA_partialpressure > 0.01)
|
||||
if(prob(20))
|
||||
emote(pick("giggle","laugh"))
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "chemical_euphoria", /datum/mood_event/chemical_euphoria)
|
||||
else
|
||||
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(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
|
||||
radiation += tritium_partialpressure/10
|
||||
|
||||
//NITRYL
|
||||
if(breath_gases[/datum/gas/nitryl])
|
||||
var/nitryl_partialpressure = (breath_gases[/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(miasma_partialpressure > MINIMUM_MOLES_DELTA_TO_MOVE)
|
||||
|
||||
if(prob(0.05 * miasma_partialpressure))
|
||||
var/datum/disease/advance/miasma_disease = new /datum/disease/advance/random(2,3)
|
||||
miasma_disease.name = "Unknown"
|
||||
ForceContractDisease(miasma_disease, TRUE, TRUE)
|
||||
|
||||
//Miasma side effects
|
||||
switch(miasma_partialpressure)
|
||||
if(1 to 5)
|
||||
// At lower pp, give out a little warning
|
||||
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "smell")
|
||||
if(prob(5))
|
||||
to_chat(src, "<span class='notice'>There is an unpleasant smell in the air.</span>")
|
||||
if(5 to 20)
|
||||
//At somewhat higher pp, warning becomes more obvious
|
||||
if(prob(15))
|
||||
to_chat(src, "<span class='warning'>You smell something horribly decayed inside this room.</span>")
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "smell", /datum/mood_event/disgust/bad_smell)
|
||||
if(15 to 30)
|
||||
//Small chance to vomit. By now, people have internals on anyway
|
||||
if(prob(5))
|
||||
to_chat(src, "<span class='warning'>The stench of rotting carcasses is unbearable!</span>")
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "smell", /datum/mood_event/disgust/nauseating_stench)
|
||||
vomit()
|
||||
if(30 to INFINITY)
|
||||
//Higher chance to vomit. Let the horror start
|
||||
if(prob(25))
|
||||
to_chat(src, "<span class='warning'>The stench of rotting carcasses is unbearable!</span>")
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "smell", /datum/mood_event/disgust/nauseating_stench)
|
||||
vomit()
|
||||
else
|
||||
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "smell")
|
||||
|
||||
|
||||
//Clear all moods if no miasma at all
|
||||
else
|
||||
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "smell")
|
||||
|
||||
|
||||
|
||||
|
||||
GAS_GARBAGE_COLLECT(breath.gases)
|
||||
|
||||
//BREATH TEMPERATURE
|
||||
handle_breath_temperature(breath)
|
||||
|
||||
return 1
|
||||
|
||||
//Fourth and final link in a breath chain
|
||||
/mob/living/carbon/proc/handle_breath_temperature(datum/gas_mixture/breath)
|
||||
return
|
||||
|
||||
/mob/living/carbon/proc/get_breath_from_internal(volume_needed)
|
||||
var/obj/item/clothing/check
|
||||
var/internals = FALSE
|
||||
|
||||
for(check in GET_INTERNAL_SLOTS(src))
|
||||
if(CHECK_BITFIELD(check.clothing_flags, ALLOWINTERNALS))
|
||||
internals = TRUE
|
||||
if(internal)
|
||||
if(internal.loc != src)
|
||||
internal = null
|
||||
update_internals_hud_icon(0)
|
||||
else if (!internals && !getorganslot(ORGAN_SLOT_BREATHING_TUBE))
|
||||
internal = null
|
||||
update_internals_hud_icon(0)
|
||||
else
|
||||
update_internals_hud_icon(1)
|
||||
. = internal.remove_air_volume(volume_needed)
|
||||
if(!.)
|
||||
return FALSE //to differentiate between no internals and active, but empty internals
|
||||
|
||||
// Make corpses rot, emitting miasma
|
||||
/mob/living/carbon/proc/rot()
|
||||
// Properly stored corpses shouldn't create miasma
|
||||
if(istype(loc, /obj/structure/closet/crate/coffin)|| istype(loc, /obj/structure/closet/body_bag) || istype(loc, /obj/structure/bodycontainer))
|
||||
return
|
||||
|
||||
// No decay if formaldehyde in corpse or when the corpse is charred
|
||||
if(reagents.has_reagent("formaldehyde", 15) || HAS_TRAIT(src, TRAIT_HUSK))
|
||||
return
|
||||
|
||||
// Also no decay if corpse chilled or not organic/undead
|
||||
if(bodytemperature <= T0C-10 || (!(MOB_ORGANIC in mob_biotypes) && !(MOB_UNDEAD in mob_biotypes)))
|
||||
return
|
||||
|
||||
// Wait a bit before decaying
|
||||
if(world.time - timeofdeath < 1200)
|
||||
return
|
||||
|
||||
var/deceasedturf = get_turf(src)
|
||||
|
||||
// Closed turfs don't have any air in them, so no gas building up
|
||||
if(!istype(deceasedturf,/turf/open))
|
||||
return
|
||||
|
||||
var/turf/open/miasma_turf = deceasedturf
|
||||
|
||||
var/list/cached_gases = miasma_turf.air.gases
|
||||
|
||||
cached_gases[/datum/gas/miasma] += 0.1
|
||||
|
||||
/mob/living/carbon/proc/handle_blood()
|
||||
return
|
||||
|
||||
/mob/living/carbon/proc/handle_bodyparts()
|
||||
for(var/I in bodyparts)
|
||||
var/obj/item/bodypart/BP = I
|
||||
if(BP.needs_processing)
|
||||
. |= BP.on_life()
|
||||
|
||||
/mob/living/carbon/proc/handle_organs()
|
||||
if(stat != DEAD)
|
||||
for(var/V in internal_organs)
|
||||
var/obj/item/organ/O = V
|
||||
if(O)
|
||||
O.on_life()
|
||||
else
|
||||
for(var/V in internal_organs)
|
||||
var/obj/item/organ/O = V
|
||||
if(O)
|
||||
O.on_death() //Needed so organs decay while inside the body.
|
||||
|
||||
/mob/living/carbon/handle_diseases()
|
||||
for(var/thing in diseases)
|
||||
var/datum/disease/D = thing
|
||||
if(prob(D.infectivity))
|
||||
D.spread()
|
||||
|
||||
if(stat != DEAD || D.process_dead)
|
||||
D.stage_act()
|
||||
|
||||
//todo generalize this and move hud out
|
||||
/mob/living/carbon/proc/handle_changeling()
|
||||
if(mind && hud_used && hud_used.lingchemdisplay)
|
||||
var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(changeling)
|
||||
changeling.regenerate()
|
||||
hud_used.lingchemdisplay.invisibility = 0
|
||||
hud_used.lingchemdisplay.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#dd66dd'>[round(changeling.chem_charges)]</font></div>"
|
||||
else
|
||||
hud_used.lingchemdisplay.invisibility = INVISIBILITY_ABSTRACT
|
||||
|
||||
|
||||
/mob/living/carbon/handle_mutations_and_radiation()
|
||||
if(dna && dna.temporary_mutations.len)
|
||||
var/datum/mutation/human/HM
|
||||
for(var/mut in dna.temporary_mutations)
|
||||
if(dna.temporary_mutations[mut] < world.time)
|
||||
if(mut == UI_CHANGED)
|
||||
if(dna.previous["UI"])
|
||||
dna.uni_identity = merge_text(dna.uni_identity,dna.previous["UI"])
|
||||
updateappearance(mutations_overlay_update=1)
|
||||
dna.previous.Remove("UI")
|
||||
dna.temporary_mutations.Remove(mut)
|
||||
continue
|
||||
if(mut == UE_CHANGED)
|
||||
if(dna.previous["name"])
|
||||
real_name = dna.previous["name"]
|
||||
name = real_name
|
||||
dna.previous.Remove("name")
|
||||
if(dna.previous["UE"])
|
||||
dna.unique_enzymes = dna.previous["UE"]
|
||||
dna.previous.Remove("UE")
|
||||
if(dna.previous["blood_type"])
|
||||
dna.blood_type = dna.previous["blood_type"]
|
||||
dna.previous.Remove("blood_type")
|
||||
dna.temporary_mutations.Remove(mut)
|
||||
continue
|
||||
HM = GLOB.mutations_list[mut]
|
||||
HM.force_lose(src)
|
||||
dna.temporary_mutations.Remove(mut)
|
||||
|
||||
radiation -= min(radiation, RAD_LOSS_PER_TICK)
|
||||
if(radiation > RAD_MOB_SAFE)
|
||||
adjustToxLoss(log(radiation-RAD_MOB_SAFE)*RAD_TOX_COEFFICIENT)
|
||||
|
||||
/mob/living/carbon/handle_stomach()
|
||||
set waitfor = 0
|
||||
for(var/mob/living/M in stomach_contents)
|
||||
if(M.loc != src)
|
||||
stomach_contents.Remove(M)
|
||||
continue
|
||||
if(iscarbon(M) && stat != DEAD)
|
||||
if(M.stat == DEAD)
|
||||
M.death(1)
|
||||
stomach_contents.Remove(M)
|
||||
qdel(M)
|
||||
continue
|
||||
if(SSmobs.times_fired%3==1)
|
||||
if(!(M.status_flags & GODMODE))
|
||||
M.adjustBruteLoss(5)
|
||||
nutrition += 10
|
||||
|
||||
|
||||
/*
|
||||
Alcohol Poisoning Chart
|
||||
Note that all higher effects of alcohol poisoning will inherit effects for smaller amounts (i.e. light poisoning inherts from slight poisoning)
|
||||
In addition, severe effects won't always trigger unless the drink is poisonously strong
|
||||
All effects don't start immediately, but rather get worse over time; the rate is affected by the imbiber's alcohol tolerance
|
||||
|
||||
0: Non-alcoholic
|
||||
1-10: Barely classifiable as alcohol - occassional slurring
|
||||
11-20: Slight alcohol content - slurring
|
||||
21-30: Below average - imbiber begins to look slightly drunk
|
||||
31-40: Just below average - no unique effects
|
||||
41-50: Average - mild disorientation, imbiber begins to look drunk
|
||||
51-60: Just above average - disorientation, vomiting, imbiber begins to look heavily drunk
|
||||
61-70: Above average - small chance of blurry vision, imbiber begins to look smashed
|
||||
71-80: High alcohol content - blurry vision, imbiber completely shitfaced
|
||||
81-90: Extremely high alcohol content - light brain damage, passing out
|
||||
91-100: Dangerously toxic - swift death
|
||||
*/
|
||||
#define BALLMER_POINTS 5
|
||||
GLOBAL_LIST_INIT(ballmer_good_msg, list("Hey guys, what if we rolled out a bluespace wiring system so mice can't destroy the powergrid anymore?",
|
||||
"Hear me out here. What if, and this is just a theory, we made R&D controllable from our PDAs?",
|
||||
"I'm thinking we should roll out a git repository for our research under the AGPLv3 license so that we can share it among the other stations freely.",
|
||||
"I dunno about you guys, but IDs and PDAs being separate is clunky as fuck. Maybe we should merge them into a chip in our arms? That way they can't be stolen easily.",
|
||||
"Why the fuck aren't we just making every pair of shoes into galoshes? We have the technology."))
|
||||
GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put a webserver that's automatically turned on with default admin passwords into every PDA?",
|
||||
"So like, you know how we separate our codebase from the master copy that runs on our consumer boxes? What if we merged the two and undid the separation between codebase and server?",
|
||||
"Dude, radical idea: H.O.N.K mechs but with no bananium required.",
|
||||
"Best idea ever: Disposal pipes instead of hallways."))
|
||||
|
||||
//this updates all special effects: stun, sleeping, knockdown, druggy, stuttering, etc..
|
||||
/mob/living/carbon/handle_status_effects()
|
||||
..()
|
||||
if(getStaminaLoss() && !combatmode)//CIT CHANGE - prevents stamina regen while combat mode is active
|
||||
adjustStaminaLoss(resting ? (recoveringstam ? -7.5 : -6) : -3)//CIT CHANGE - decreases adjuststaminaloss to stop stamina damage from being such a joke
|
||||
|
||||
if(!recoveringstam && incomingstammult != 1)
|
||||
incomingstammult = max(0.01, incomingstammult)
|
||||
incomingstammult = min(1, incomingstammult*2)
|
||||
|
||||
//CIT CHANGES START HERE. STAMINA BUFFER STUFF
|
||||
if(bufferedstam && world.time > stambufferregentime)
|
||||
var/drainrate = max((bufferedstam*(bufferedstam/(5)))*0.1,1)
|
||||
bufferedstam = max(bufferedstam - drainrate, 0)
|
||||
adjustStaminaLoss(drainrate*0.5)
|
||||
//END OF CIT CHANGES
|
||||
|
||||
var/restingpwr = 1 + 4 * resting
|
||||
|
||||
//Dizziness
|
||||
if(dizziness)
|
||||
var/client/C = client
|
||||
var/pixel_x_diff = 0
|
||||
var/pixel_y_diff = 0
|
||||
var/temp
|
||||
var/saved_dizz = dizziness
|
||||
if(C)
|
||||
var/oldsrc = src
|
||||
var/amplitude = dizziness*(sin(dizziness * world.time) + 1) // This shit is annoying at high strength
|
||||
src = null
|
||||
spawn(0)
|
||||
if(C)
|
||||
temp = amplitude * sin(saved_dizz * world.time)
|
||||
pixel_x_diff += temp
|
||||
C.pixel_x += temp
|
||||
temp = amplitude * cos(saved_dizz * world.time)
|
||||
pixel_y_diff += temp
|
||||
C.pixel_y += temp
|
||||
sleep(3)
|
||||
if(C)
|
||||
temp = amplitude * sin(saved_dizz * world.time)
|
||||
pixel_x_diff += temp
|
||||
C.pixel_x += temp
|
||||
temp = amplitude * cos(saved_dizz * world.time)
|
||||
pixel_y_diff += temp
|
||||
C.pixel_y += temp
|
||||
sleep(3)
|
||||
if(C)
|
||||
C.pixel_x -= pixel_x_diff
|
||||
C.pixel_y -= pixel_y_diff
|
||||
src = oldsrc
|
||||
dizziness = max(dizziness - restingpwr, 0)
|
||||
|
||||
if(drowsyness)
|
||||
drowsyness = max(drowsyness - restingpwr, 0)
|
||||
blur_eyes(2)
|
||||
if(prob(5))
|
||||
AdjustSleeping(20)
|
||||
Unconscious(100)
|
||||
|
||||
//Jitteriness
|
||||
if(jitteriness)
|
||||
do_jitter_animation(jitteriness)
|
||||
jitteriness = max(jitteriness - restingpwr, 0)
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "jittery", /datum/mood_event/jittery)
|
||||
else
|
||||
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "jittery")
|
||||
|
||||
if(stuttering)
|
||||
stuttering = max(stuttering-1, 0)
|
||||
|
||||
if(slurring || drunkenness)
|
||||
slurring = max(slurring-1,0,drunkenness)
|
||||
|
||||
if(cultslurring)
|
||||
cultslurring = max(cultslurring-1, 0)
|
||||
|
||||
if(silent)
|
||||
silent = max(silent-1, 0)
|
||||
|
||||
if(druggy)
|
||||
adjust_drugginess(-1)
|
||||
|
||||
if(hallucination)
|
||||
handle_hallucinations()
|
||||
|
||||
if(drunkenness)
|
||||
drunkenness = max(drunkenness - (drunkenness * 0.04), 0)
|
||||
if(drunkenness >= 6)
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "drunk", /datum/mood_event/drunk)
|
||||
jitteriness = max(jitteriness - 3, 0)
|
||||
if(HAS_TRAIT(src, TRAIT_DRUNK_HEALING))
|
||||
adjustBruteLoss(-0.12, FALSE)
|
||||
adjustFireLoss(-0.06, FALSE)
|
||||
|
||||
if(mind && (mind.assigned_role == "Scientist" || mind.assigned_role == "Research Director"))
|
||||
if(SSresearch.science_tech)
|
||||
if(drunkenness >= 12.9 && drunkenness <= 13.8)
|
||||
drunkenness = round(drunkenness, 0.01)
|
||||
var/ballmer_percent = 0
|
||||
if(drunkenness == 13.35) // why run math if I dont have to
|
||||
ballmer_percent = 1
|
||||
else
|
||||
ballmer_percent = (-abs(drunkenness - 13.35) / 0.9) + 1
|
||||
if(prob(5))
|
||||
say(pick(GLOB.ballmer_good_msg), forced = "ballmer")
|
||||
SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = BALLMER_POINTS * ballmer_percent))
|
||||
if(drunkenness > 26) // by this point you're into windows ME territory
|
||||
if(prob(5))
|
||||
SSresearch.science_tech.remove_point_list(list(TECHWEB_POINT_TYPE_GENERIC = BALLMER_POINTS))
|
||||
say(pick(GLOB.ballmer_windows_me_msg), forced = "ballmer")
|
||||
|
||||
if(drunkenness >= 41)
|
||||
if(prob(25))
|
||||
confused += 2
|
||||
Dizzy(10)
|
||||
if(HAS_TRAIT(src, TRAIT_DRUNK_HEALING)) // effects stack with lower tiers
|
||||
adjustBruteLoss(-0.3, FALSE)
|
||||
adjustFireLoss(-0.15, FALSE)
|
||||
|
||||
if(drunkenness >= 51)
|
||||
if(prob(5))
|
||||
confused += 10
|
||||
vomit()
|
||||
Dizzy(25)
|
||||
|
||||
if(drunkenness >= 61)
|
||||
if(prob(50))
|
||||
blur_eyes(5)
|
||||
if(HAS_TRAIT(src, TRAIT_DRUNK_HEALING))
|
||||
adjustBruteLoss(-0.4, FALSE)
|
||||
adjustFireLoss(-0.2, FALSE)
|
||||
|
||||
if(drunkenness >= 71)
|
||||
blur_eyes(5)
|
||||
|
||||
if(drunkenness >= 81)
|
||||
adjustToxLoss(0.2)
|
||||
if(prob(5) && !stat)
|
||||
to_chat(src, "<span class='warning'>Maybe you should lie down for a bit...</span>")
|
||||
|
||||
if(drunkenness >= 91)
|
||||
adjustOrganLoss(ORGAN_SLOT_BRAIN, 0.4, 60)
|
||||
if(prob(20) && !stat)
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_DOCKED && is_station_level(z)) //QoL mainly
|
||||
to_chat(src, "<span class='warning'>You're so tired... but you can't miss that shuttle...</span>")
|
||||
else
|
||||
to_chat(src, "<span class='warning'>Just a quick nap...</span>")
|
||||
Sleeping(900)
|
||||
|
||||
if(drunkenness >= 101)
|
||||
adjustToxLoss(4) //Let's be honest you shouldn't be alive by now
|
||||
else
|
||||
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "drunk")
|
||||
|
||||
//used in human and monkey handle_environment()
|
||||
/mob/living/carbon/proc/natural_bodytemperature_stabilization()
|
||||
var/body_temperature_difference = BODYTEMP_NORMAL - bodytemperature
|
||||
switch(bodytemperature)
|
||||
if(-INFINITY to BODYTEMP_COLD_DAMAGE_LIMIT) //Cold damage limit is 50 below the default, the temperature where you start to feel effects.
|
||||
return max((body_temperature_difference * metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR), BODYTEMP_AUTORECOVERY_MINIMUM)
|
||||
if(BODYTEMP_COLD_DAMAGE_LIMIT to BODYTEMP_NORMAL)
|
||||
return max(body_temperature_difference * metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR, min(body_temperature_difference, BODYTEMP_AUTORECOVERY_MINIMUM/4))
|
||||
if(BODYTEMP_NORMAL to BODYTEMP_HEAT_DAMAGE_LIMIT) // Heat damage limit is 50 above the default, the temperature where you start to feel effects.
|
||||
return min(body_temperature_difference * metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR, max(body_temperature_difference, -BODYTEMP_AUTORECOVERY_MINIMUM/4))
|
||||
if(BODYTEMP_HEAT_DAMAGE_LIMIT to INFINITY)
|
||||
return min((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), -BODYTEMP_AUTORECOVERY_MINIMUM) //We're dealing with negative numbers
|
||||
/////////
|
||||
//LIVER//
|
||||
/////////
|
||||
|
||||
/mob/living/carbon/proc/handle_liver()
|
||||
var/obj/item/organ/liver/liver = getorganslot(ORGAN_SLOT_LIVER)
|
||||
if((!dna && !liver) || (NOLIVER in dna.species.species_traits))
|
||||
return
|
||||
if(liver)
|
||||
if(liver.damage < liver.maxHealth)
|
||||
liver.organ_flags |= ORGAN_FAILING
|
||||
liver_failure()
|
||||
else
|
||||
liver_failure()
|
||||
|
||||
/mob/living/carbon/proc/undergoing_liver_failure()
|
||||
var/obj/item/organ/liver/liver = getorganslot(ORGAN_SLOT_LIVER)
|
||||
if(liver && liver.failing)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/proc/return_liver_damage()
|
||||
var/obj/item/organ/liver/liver = getorganslot(ORGAN_SLOT_LIVER)
|
||||
if(liver)
|
||||
return liver.damage
|
||||
|
||||
/mob/living/carbon/proc/applyLiverDamage(var/d)
|
||||
var/obj/item/organ/liver/L = getorganslot(ORGAN_SLOT_LIVER)
|
||||
if(L)
|
||||
L.damage += d
|
||||
|
||||
/mob/living/carbon/proc/liver_failure()
|
||||
reagents.end_metabolization(src, keep_liverless = TRUE) //Stops trait-based effects on reagents, to prevent permanent buffs
|
||||
reagents.metabolize(src, can_overdose=FALSE, liverless = TRUE)
|
||||
if(HAS_TRAIT(src, TRAIT_STABLELIVER))
|
||||
return
|
||||
adjustToxLoss(4, TRUE, TRUE)
|
||||
if(prob(30))
|
||||
to_chat(src, "<span class='warning'>You feel a stabbing pain in your abdomen!</span>")
|
||||
|
||||
|
||||
////////////////
|
||||
//BRAIN DAMAGE//
|
||||
////////////////
|
||||
|
||||
/mob/living/carbon/proc/handle_brain_damage()
|
||||
for(var/T in get_traumas())
|
||||
var/datum/brain_trauma/BT = T
|
||||
BT.on_life()
|
||||
|
||||
/////////////////////////////////////
|
||||
//MONKEYS WITH TOO MUCH CHOLOESTROL//
|
||||
/////////////////////////////////////
|
||||
|
||||
/mob/living/carbon/proc/can_heartattack()
|
||||
if(!needs_heart())
|
||||
return FALSE
|
||||
var/obj/item/organ/heart/heart = getorganslot(ORGAN_SLOT_HEART)
|
||||
if(!heart || (heart.organ_flags & ORGAN_SYNTHETIC))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/proc/needs_heart()
|
||||
if(HAS_TRAIT(src, TRAIT_STABLEHEART))
|
||||
return FALSE
|
||||
if(dna && dna.species && (NOBLOOD in dna.species.species_traits)) //not all carbons have species!
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/proc/undergoing_cardiac_arrest()
|
||||
var/obj/item/organ/heart/heart = getorganslot(ORGAN_SLOT_HEART)
|
||||
if(istype(heart) && heart.beating)
|
||||
return FALSE
|
||||
else if(!needs_heart())
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/proc/set_heartattack(status)
|
||||
if(!can_heartattack())
|
||||
return FALSE
|
||||
|
||||
var/obj/item/organ/heart/heart = getorganslot(ORGAN_SLOT_HEART)
|
||||
if(!istype(heart))
|
||||
return
|
||||
|
||||
heart.beating = !status
|
||||
@@ -1,309 +0,0 @@
|
||||
//IMPORTANT: Multiple animate() calls do not stack well, so try to do them all at once if you can.
|
||||
/mob/living/carbon/update_transform()
|
||||
var/matrix/ntransform = matrix(transform) //aka transform.Copy()
|
||||
var/final_pixel_y = pixel_y
|
||||
var/final_dir = dir
|
||||
var/changed = 0
|
||||
if(lying != lying_prev && rotate_on_lying)
|
||||
changed++
|
||||
ntransform.TurnTo(lying_prev,lying)
|
||||
if(lying == 0) //Lying to standing
|
||||
final_pixel_y = get_standard_pixel_y_offset()
|
||||
else //if(lying != 0)
|
||||
if(lying_prev == 0) //Standing to lying
|
||||
pixel_y = get_standard_pixel_y_offset()
|
||||
final_pixel_y = get_standard_pixel_y_offset(lying)
|
||||
if(dir & (EAST|WEST)) //Facing east or west
|
||||
final_dir = pick(NORTH, SOUTH) //So you fall on your side rather than your face or ass
|
||||
|
||||
if(resize != RESIZE_DEFAULT_SIZE)
|
||||
changed++
|
||||
ntransform.Scale(resize)
|
||||
resize = RESIZE_DEFAULT_SIZE
|
||||
|
||||
if(changed)
|
||||
animate(src, transform = ntransform, time = 2, pixel_y = final_pixel_y, dir = final_dir, easing = EASE_IN|EASE_OUT)
|
||||
setMovetype(movement_type & ~FLOATING) // If we were without gravity, the bouncing animation got stopped, so we make sure we restart it in next life().
|
||||
|
||||
|
||||
/mob/living/carbon
|
||||
var/list/overlays_standing[TOTAL_LAYERS]
|
||||
|
||||
/mob/living/carbon/proc/apply_overlay(cache_index)
|
||||
if((. = overlays_standing[cache_index]))
|
||||
add_overlay(.)
|
||||
|
||||
/mob/living/carbon/proc/remove_overlay(cache_index)
|
||||
var/I = overlays_standing[cache_index]
|
||||
if(I)
|
||||
cut_overlay(I)
|
||||
overlays_standing[cache_index] = null
|
||||
|
||||
/mob/living/carbon/regenerate_icons()
|
||||
if(notransform)
|
||||
return 1
|
||||
update_inv_hands()
|
||||
update_inv_handcuffed()
|
||||
update_inv_legcuffed()
|
||||
update_fire()
|
||||
|
||||
|
||||
/mob/living/carbon/update_inv_hands()
|
||||
remove_overlay(HANDS_LAYER)
|
||||
if (handcuffed)
|
||||
drop_all_held_items()
|
||||
return
|
||||
|
||||
var/list/hands = list()
|
||||
for(var/obj/item/I in held_items)
|
||||
if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD)
|
||||
I.screen_loc = ui_hand_position(get_held_index_of_item(I))
|
||||
client.screen += I
|
||||
if(observers && observers.len)
|
||||
for(var/M in observers)
|
||||
var/mob/dead/observe = M
|
||||
if(observe.client && observe.client.eye == src)
|
||||
observe.client.screen += I
|
||||
else
|
||||
observers -= observe
|
||||
if(!observers.len)
|
||||
observers = null
|
||||
break
|
||||
|
||||
var/t_state = I.item_state
|
||||
if(!t_state)
|
||||
t_state = I.icon_state
|
||||
|
||||
var/icon_file = I.lefthand_file
|
||||
if(get_held_index_of_item(I) % 2 == 0)
|
||||
icon_file = I.righthand_file
|
||||
|
||||
hands += I.build_worn_icon(state = t_state, default_layer = HANDS_LAYER, default_icon_file = icon_file, isinhands = TRUE)
|
||||
|
||||
overlays_standing[HANDS_LAYER] = hands
|
||||
apply_overlay(HANDS_LAYER)
|
||||
|
||||
|
||||
/mob/living/carbon/update_fire(var/fire_icon = "Generic_mob_burning")
|
||||
remove_overlay(FIRE_LAYER)
|
||||
if(on_fire)
|
||||
var/mutable_appearance/new_fire_overlay = mutable_appearance('icons/mob/OnFire.dmi', fire_icon, -FIRE_LAYER)
|
||||
new_fire_overlay.appearance_flags = RESET_COLOR
|
||||
overlays_standing[FIRE_LAYER] = new_fire_overlay
|
||||
|
||||
apply_overlay(FIRE_LAYER)
|
||||
|
||||
|
||||
|
||||
/mob/living/carbon/update_damage_overlays()
|
||||
remove_overlay(DAMAGE_LAYER)
|
||||
var/dam_colors = "#E62525"
|
||||
if(ishuman(src))
|
||||
var/mob/living/carbon/human/H = src
|
||||
dam_colors = bloodtype_to_color(H.dna.blood_type)
|
||||
|
||||
var/mutable_appearance/damage_overlay = mutable_appearance('icons/mob/dam_mob.dmi', "blank", -DAMAGE_LAYER, color = dam_colors)
|
||||
overlays_standing[DAMAGE_LAYER] = damage_overlay
|
||||
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
if(BP.dmg_overlay_type)
|
||||
if(BP.brutestate)
|
||||
damage_overlay.add_overlay("[BP.dmg_overlay_type]_[BP.body_zone]_[BP.brutestate]0") //we're adding icon_states of the base image as overlays
|
||||
if(BP.burnstate)
|
||||
damage_overlay.add_overlay("[BP.dmg_overlay_type]_[BP.body_zone]_0[BP.burnstate]")
|
||||
|
||||
apply_overlay(DAMAGE_LAYER)
|
||||
|
||||
|
||||
/mob/living/carbon/update_inv_wear_mask()
|
||||
remove_overlay(FACEMASK_LAYER)
|
||||
|
||||
if(!get_bodypart(BODY_ZONE_HEAD)) //Decapitated
|
||||
return
|
||||
|
||||
if(client && hud_used && hud_used.inv_slots[SLOT_WEAR_MASK])
|
||||
var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_WEAR_MASK]
|
||||
inv.update_icon()
|
||||
|
||||
if(wear_mask)
|
||||
if(!(head && (head.flags_inv & HIDEMASK)))
|
||||
overlays_standing[FACEMASK_LAYER] = wear_mask.build_worn_icon(state = wear_mask.icon_state, default_layer = FACEMASK_LAYER, default_icon_file = 'icons/mob/mask.dmi')
|
||||
update_hud_wear_mask(wear_mask)
|
||||
|
||||
apply_overlay(FACEMASK_LAYER)
|
||||
|
||||
/mob/living/carbon/update_inv_neck()
|
||||
remove_overlay(NECK_LAYER)
|
||||
|
||||
if(client && hud_used && hud_used.inv_slots[SLOT_NECK])
|
||||
var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_NECK]
|
||||
inv.update_icon()
|
||||
|
||||
if(wear_neck)
|
||||
if(!(head && (head.flags_inv & HIDENECK)))
|
||||
overlays_standing[NECK_LAYER] = wear_neck.build_worn_icon(state = wear_neck.icon_state, default_layer = NECK_LAYER, default_icon_file = 'icons/mob/neck.dmi')
|
||||
update_hud_neck(wear_neck)
|
||||
|
||||
apply_overlay(NECK_LAYER)
|
||||
|
||||
/mob/living/carbon/update_inv_back()
|
||||
remove_overlay(BACK_LAYER)
|
||||
|
||||
if(client && hud_used && hud_used.inv_slots[SLOT_BACK])
|
||||
var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_BACK]
|
||||
inv.update_icon()
|
||||
|
||||
if(back)
|
||||
overlays_standing[BACK_LAYER] = back.build_worn_icon(state = back.icon_state, default_layer = BACK_LAYER, default_icon_file = 'icons/mob/back.dmi')
|
||||
update_hud_back(back)
|
||||
|
||||
apply_overlay(BACK_LAYER)
|
||||
|
||||
/mob/living/carbon/update_inv_head()
|
||||
remove_overlay(HEAD_LAYER)
|
||||
|
||||
if(!get_bodypart(BODY_ZONE_HEAD)) //Decapitated
|
||||
return
|
||||
|
||||
if(client && hud_used && hud_used.inv_slots[SLOT_BACK])
|
||||
var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_HEAD]
|
||||
inv.update_icon()
|
||||
|
||||
if(head)
|
||||
overlays_standing[HEAD_LAYER] = head.build_worn_icon(state = head.icon_state, default_layer = HEAD_LAYER, default_icon_file = 'icons/mob/head.dmi')
|
||||
update_hud_head(head)
|
||||
|
||||
apply_overlay(HEAD_LAYER)
|
||||
|
||||
|
||||
/mob/living/carbon/update_inv_handcuffed()
|
||||
remove_overlay(HANDCUFF_LAYER)
|
||||
if(handcuffed)
|
||||
var/mutable_appearance/cuffs = mutable_appearance('icons/mob/restraints.dmi', handcuffed.item_state, -HANDCUFF_LAYER)
|
||||
cuffs.color = handcuffed.color
|
||||
|
||||
overlays_standing[HANDCUFF_LAYER] = cuffs
|
||||
apply_overlay(HANDCUFF_LAYER)
|
||||
|
||||
/mob/living/carbon/update_inv_legcuffed()
|
||||
remove_overlay(LEGCUFF_LAYER)
|
||||
clear_alert("legcuffed")
|
||||
if(legcuffed)
|
||||
var/mutable_appearance/legcuffs = mutable_appearance('icons/mob/restraints.dmi', legcuffed.item_state, -LEGCUFF_LAYER)
|
||||
legcuffs.color = legcuffed.color
|
||||
|
||||
overlays_standing[LEGCUFF_LAYER] = legcuffs
|
||||
apply_overlay(LEGCUFF_LAYER)
|
||||
throw_alert("legcuffed", /obj/screen/alert/restrained/legcuffed, new_master = legcuffed)
|
||||
|
||||
//mob HUD updates for items in our inventory
|
||||
|
||||
//update whether handcuffs appears on our hud.
|
||||
/mob/living/carbon/proc/update_hud_handcuffed()
|
||||
if(hud_used)
|
||||
for(var/hand in hud_used.hand_slots)
|
||||
var/obj/screen/inventory/hand/H = hud_used.hand_slots[hand]
|
||||
if(H)
|
||||
H.update_icon()
|
||||
|
||||
//update whether our head item appears on our hud.
|
||||
/mob/living/carbon/proc/update_hud_head(obj/item/I)
|
||||
return
|
||||
|
||||
//update whether our mask item appears on our hud.
|
||||
/mob/living/carbon/proc/update_hud_wear_mask(obj/item/I)
|
||||
return
|
||||
|
||||
//update whether our neck item appears on our hud.
|
||||
/mob/living/carbon/proc/update_hud_neck(obj/item/I)
|
||||
return
|
||||
|
||||
//update whether our back item appears on our hud.
|
||||
/mob/living/carbon/proc/update_hud_back(obj/item/I)
|
||||
return
|
||||
|
||||
|
||||
|
||||
//Overlays for the worn overlay so you can overlay while you overlay
|
||||
//eg: ammo counters, primed grenade flashing, etc.
|
||||
//"icon_file" is used automatically for inhands etc. to make sure it gets the right inhand file
|
||||
/obj/item/proc/worn_overlays(isinhands = FALSE, icon_file)
|
||||
. = list()
|
||||
|
||||
|
||||
/mob/living/carbon/update_body()
|
||||
update_body_parts()
|
||||
|
||||
/mob/living/carbon/proc/update_body_parts()
|
||||
//CHECK FOR UPDATE
|
||||
var/oldkey = icon_render_key
|
||||
icon_render_key = generate_icon_render_key()
|
||||
if(oldkey == icon_render_key)
|
||||
return
|
||||
|
||||
remove_overlay(BODYPARTS_LAYER)
|
||||
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
BP.update_limb()
|
||||
|
||||
//LOAD ICONS
|
||||
if(limb_icon_cache[icon_render_key])
|
||||
load_limb_from_cache()
|
||||
return
|
||||
|
||||
//GENERATE NEW LIMBS
|
||||
var/list/new_limbs = list()
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
new_limbs += BP.get_limb_icon()
|
||||
if(new_limbs.len)
|
||||
overlays_standing[BODYPARTS_LAYER] = new_limbs
|
||||
limb_icon_cache[icon_render_key] = new_limbs
|
||||
|
||||
apply_overlay(BODYPARTS_LAYER)
|
||||
update_damage_overlays()
|
||||
|
||||
|
||||
|
||||
/////////////////////
|
||||
// Limb Icon Cache //
|
||||
/////////////////////
|
||||
/*
|
||||
Called from update_body_parts() these procs handle the limb icon cache.
|
||||
the limb icon cache adds an icon_render_key to a human mob, it represents:
|
||||
- skin_tone (if applicable)
|
||||
- gender
|
||||
- limbs (stores as the limb name and whether it is removed/fine, organic/robotic)
|
||||
These procs only store limbs as to increase the number of matching icon_render_keys
|
||||
This cache exists because drawing 6/7 icons for humans constantly is quite a waste
|
||||
See RemieRichards on irc.rizon.net #coderbus
|
||||
*/
|
||||
|
||||
//produces a key based on the mob's limbs
|
||||
|
||||
/mob/living/carbon/proc/generate_icon_render_key()
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
. += "-[BP.body_zone]"
|
||||
if(BP.use_digitigrade)
|
||||
. += "-digitigrade[BP.use_digitigrade]"
|
||||
if(BP.animal_origin)
|
||||
. += "-[BP.animal_origin]"
|
||||
if(BP.status == BODYPART_ORGANIC)
|
||||
. += "-organic"
|
||||
else
|
||||
. += "-robotic"
|
||||
|
||||
if(HAS_TRAIT(src, TRAIT_HUSK))
|
||||
. += "-husk"
|
||||
|
||||
|
||||
//change the mob's icon to the one matching its key
|
||||
/mob/living/carbon/proc/load_limb_from_cache()
|
||||
if(limb_icon_cache[icon_render_key])
|
||||
remove_overlay(BODYPARTS_LAYER)
|
||||
overlays_standing[BODYPARTS_LAYER] = limb_icon_cache[icon_render_key]
|
||||
apply_overlay(BODYPARTS_LAYER)
|
||||
update_damage_overlays()
|
||||
Reference in New Issue
Block a user