Merge remote-tracking branch 'upstream/master' into slime-legs

This commit is contained in:
Timothy Teakettle
2020-12-28 17:22:53 +00:00
1080 changed files with 54402 additions and 21299 deletions
+1 -1
View File
@@ -17,4 +17,4 @@
if(loc)
if(istype(loc, /obj/item/organ/brain))
qdel(loc)//Gets rid of the brain item
..()
..()
+1 -1
View File
@@ -21,4 +21,4 @@
key = "whistle"
key_third_person = "whistles"
message = "whistles."
emote_type = EMOTE_AUDIBLE
emote_type = EMOTE_AUDIBLE
@@ -22,4 +22,4 @@
return
/mob/living/brain/set_blurriness()
return
return
@@ -1,8 +1,8 @@
/mob/living/carbon/alien/getToxLoss()
/mob/living/carbon/alien/getToxLoss(toxins_type = TOX_OMNI)
return 0
/mob/living/carbon/alien/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE) //alien immune to tox damage
/mob/living/carbon/alien/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE, toxins_type = TOX_DEFAULT) //alien immune to tox damage
return FALSE
//aliens are immune to stamina damage.
@@ -41,4 +41,4 @@
return 1
else
to_chat(user, "<span class='notice'>We already have a living royal!</span>")
return 0
return 0
@@ -20,4 +20,4 @@
if(istype(node)) // just in case someone would ever add a diffirent node to hivenode slot
node.queen_death()
return ..()
return ..()
@@ -1,3 +1,3 @@
//can't unequip since it can't equip anything
/mob/living/carbon/alien/larva/doUnEquip(obj/item/W)
return
return
@@ -30,4 +30,4 @@
hud_used.alien_queen_finder.add_overlay(finder_eye)
/mob/living/carbon/alien/humanoid/royal/queen/findQueen()
return //Queen already knows where she is. Hopefully.
return //Queen already knows where she is. Hopefully.
@@ -8,4 +8,4 @@
return
/mob/living/carbon/alien/update_body_parts()//we don't use the bodyparts layer for aliens.
return
return
+4 -2
View File
@@ -604,14 +604,14 @@
ENABLE_BITFIELD(combat_flags, COMBAT_FLAG_HARD_STAMCRIT)
filters += CIT_FILTER_STAMINACRIT
update_mobility()
if((combat_flags & COMBAT_FLAG_HARD_STAMCRIT) && total_health <= STAMINA_CRIT)
if((combat_flags & COMBAT_FLAG_HARD_STAMCRIT) && total_health <= STAMINA_CRIT_REMOVAL_THRESHOLD)
to_chat(src, "<span class='notice'>You don't feel nearly as exhausted anymore.</span>")
DISABLE_BITFIELD(combat_flags, COMBAT_FLAG_HARD_STAMCRIT)
filters -= CIT_FILTER_STAMINACRIT
update_mobility()
UpdateStaminaBuffer()
update_health_hud()
/mob/living/carbon/update_sight()
if(!client)
return
@@ -839,6 +839,8 @@
/mob/living/carbon/update_stat()
if(status_flags & GODMODE)
return
if(stat != CONSCIOUS)
clear_typing_indicator()
if(stat != DEAD)
if(health <= HEALTH_THRESHOLD_DEAD && !HAS_TRAIT(src, TRAIT_NODEATH))
death()
@@ -212,6 +212,11 @@
. = ..()
if(. & EMP_PROTECT_CONTENTS)
return
if(HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM))
//EMPs fuck robots over. Up to ~11.5 corruption per EMP if hit by the full power. They also get up to 15 burn damage per EMP (up to 2.5 per limb), plus short hardstun
//Though, note that the burn damage is linear, while corruption is logarythmical, which means at lower severities you still get corruption, but far less burn / stun
//Note than as compensation, they only take half the limb burn damage someone fully augmented would take, which would be up to 30 burn.
adjustToxLoss(round(log(severity)*2.5, 0.1), toxins_type = TOX_SYSCORRUPT)
for(var/X in internal_organs)
var/obj/item/organ/O = X
O.emp_act(severity)
@@ -350,10 +355,10 @@
return embeds
/mob/living/carbon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0)
/mob/living/carbon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash, override_protection = 0)
. = ..()
var/damage = intensity - get_eye_protection()
var/damage = override_protection ? intensity : intensity - get_eye_protection()
if(.) // we've been flashed
var/obj/item/organ/eyes/eyes = getorganslot(ORGAN_SLOT_EYES)
if (!eyes)
@@ -453,14 +458,14 @@
/mob/living/carbon/getBruteLoss_nonProsthetic()
var/amount = 0
for(var/obj/item/bodypart/BP in bodyparts)
if (BP.status < 2)
if (BP.is_organic_limb())
amount += BP.brute_dam
return amount
/mob/living/carbon/getFireLoss_nonProsthetic()
var/amount = 0
for(var/obj/item/bodypart/BP in bodyparts)
if (BP.status < 2)
if (BP.is_organic_limb())
amount += BP.burn_dam
return amount
@@ -65,6 +65,8 @@
var/drunkenness = 0 //Overall drunkenness - check handle_alcohol() in life.dm for effects
var/tackling = FALSE //Whether or not we are tackling, this will prevent the knock into effects for carbons
var/corruption_timer = 0 //Only relevant for robotpeople. A timer that ticks in handle_corruption() so stuff doesn't happen every tick.
/// All of the wounds a carbon has afflicted throughout their limbs
var/list/all_wounds
/// All of the scars a carbon has afflicted throughout their limbs
@@ -85,8 +85,10 @@
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
//God save me from spaghettifying this - Syscorrupt damage is not affected by toxlovers.
/mob/living/carbon/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE, toxins_type = TOX_DEFAULT)
if(!forced && HAS_TRAIT(src, TRAIT_TOXINLOVER) && toxins_type != TOX_SYSCORRUPT) //damage becomes healing and healing becomes damage
amount = -amount
if(amount > 0)
blood_volume -= 3 * amount //5x was too much, this is punishing enough.
@@ -173,7 +175,7 @@
var/list/obj/item/bodypart/parts = list()
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
if(status && !status[BP.status])
if(status && !status.Find(BP.status))
continue
if((brute && BP.brute_dam) || (burn && BP.burn_dam) || (stamina && BP.stamina_dam))
parts += BP
+1 -1
View File
@@ -5,7 +5,7 @@
silent = FALSE
losebreath = 0
if(!gibbed)
if(!gibbed && !HAS_TRAIT(src, TRAIT_DEATHCOMA))
emote("deathgasp")
. = ..()
@@ -0,0 +1,165 @@
//////////////////////////////////////
//SYSTEM CORRUPTION FOR ROBOT-PEOPLE//
//////////////////////////////////////
//Moved into its own file for easier accessability & less cluttering of carbon/life.dm. Used in BiologicalLife()
#define CORRUPTION_CHECK_INTERVAL 10 //Life() is called once every second, so ten seconds interval.
#define CORRUPTION_THRESHHOLD_MINOR 10 //Above: Annoyances, to remind you you should get your corruption fixed.
#define CORRUPTION_THRESHHOLD_MAJOR 35 //Above: Very annoying stuff, go get fixed.
#define CORRUPTION_THRESHHOLD_CRITICAL 65 //Above: Extremely annoying stuff, possibly life-threatening
/mob/living/carbon/proc/handle_corruption()
if(!HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM)) //Only robot-people need to care about this
return
corruption_timer++
var/corruption = getToxLoss(toxins_type = TOX_SYSCORRUPT)
var/corruption_state
var/timer_req = CORRUPTION_CHECK_INTERVAL
switch(corruption)
if(0 to CORRUPTION_THRESHHOLD_MINOR)
timer_req = INFINITY //Below minor corruption you are fiiine
corruption_state = "<font color='green'>None</font>" //This should never happen, but have it anyways.
if(CORRUPTION_THRESHHOLD_MINOR to CORRUPTION_THRESHHOLD_MAJOR)
corruption_state = "<font color='blue'>Minor</font>"
if(CORRUPTION_THRESHHOLD_MAJOR to CORRUPTION_THRESHHOLD_CRITICAL)
timer_req -= 1
corruption_state = "<font color='orange'>Major</font>"
if(CORRUPTION_THRESHHOLD_CRITICAL to INFINITY)
timer_req -= 2
corruption_state = "<font color='red'>Critical</font>"
if(corruption_timer < timer_req)
return
corruption_timer = 0
if(!prob(corruption)) //Lucky you beat the rng roll!
return
var/list/whatmighthappen = list()
whatmighthappen += list("avoided" = 3, "dropthing" = 1, "movetile" = 1, "shortdeaf" = 1, "flopover" = 1, "nutriloss" = 1, "selfflash" = 1, "harmies" = 1)
if(corruption >= CORRUPTION_THRESHHOLD_MAJOR)
whatmighthappen += list("longdeaf" = 1, "longknockdown" = 1, "shortlimbdisable" = 1, "shortblind" = 1, "shortstun" = 1, "shortmute" = 1, "vomit" = 1, "halluscinate" = 1)
if(corruption >= CORRUPTION_THRESHHOLD_CRITICAL)
whatmighthappen += list("receporgandamage" = 1, "longlimbdisable" = 1, "blindmutedeaf" = 1, "longstun" = 1, "sleep" = 1, "inducetrauma" = 1, "amplifycorrupt" = 1, "changetemp" = 1)
var/event = pickweight(whatmighthappen)
log_message("has been affected by [event] due to system corruption of [corruption], with a corruption state of [corruption_state]", LOG_ATTACK)
switch(event)
if("avoided")
to_chat(src, "<span class='notice'>System malfunction avoided by hardware safeguards - intervention recommended.</span>")
adjustToxLoss(-0.2, toxins_type = TOX_SYSCORRUPT) //If you roll this, your system safeguards caught onto the system corruption and neutralised a bit of it.
if("dropthing")
drop_all_held_items()
to_chat(src, "<span class='warning'>Error - Malfunction in arm circuitry.</span>")
if("movetile")
if(CHECK_MOBILITY(src, MOBILITY_MOVE) && !ismovable(loc))
step(src, pick(GLOB.cardinals))
to_chat(src, "<span class='warning'>Error - Malfunction in movement control subsystem.</span>")
if("shortdeaf")
ADD_TRAIT(src, TRAIT_DEAF, CORRUPTED_SYSTEM)
addtimer(CALLBACK(src, .proc/reenable_hearing), 5 SECONDS)
to_chat(src, "<span class='hear'><b>ZZZZT</b></span>")
if("flopover")
DefaultCombatKnockdown(1)
to_chat(src, "<span class='warning'>Error - Malfunction in actuator circuitry.</span>")
if("nutriloss")
nutrition = max(0, nutrition - 50)
to_chat(src, "<span class='warning'>Power surge detected in internal battery cell.</span>")
if("selfflash")
if(flash_act(override_protection = 1))
confused += 4
to_chat(src, "<span class='warning'>Error - Sensory system overload detected!</span>")
if("harmies")
a_intent_change(INTENT_HARM)
to_chat(src, "<span class='notice'>Intent subsystem successfully recalibrated.</span>")
if("longdeaf")
ADD_TRAIT(src, TRAIT_DEAF, CORRUPTED_SYSTEM)
addtimer(CALLBACK(src, .proc/reenable_hearing), 20 SECONDS)
to_chat(src, "<span class='notice'>Hearing subsystem successfully shutdown.</span>")
if("longknockdown")
DefaultCombatKnockdown(50)
to_chat(src, "<span class='warning'>Significant error in actuator subsystem - Rebooting.</span>")
if("shortlimbdisable")
var/disabled_type = pick(list(TRAIT_PARALYSIS_L_ARM, TRAIT_PARALYSIS_R_ARM, TRAIT_PARALYSIS_L_LEG, TRAIT_PARALYSIS_R_LEG))
ADD_TRAIT(src, disabled_type, CORRUPTED_SYSTEM)
addtimer(CALLBACK(src, .proc/reenable_limb, disabled_type), 5 SECONDS)
to_chat(src, "<span class='warning'>Error - Limb control subsystem partially shutdown, rebooting.</span>")
if("shortblind")
ADD_TRAIT(src, TRAIT_BLIND, CORRUPTED_SYSTEM)
addtimer(CALLBACK(src, .proc/reenable_vision), 5 SECONDS)
to_chat(src, "<span class='warning'>Visual receptor shutdown detected - Initiating reboot.</span>")
if("shortstun")
Stun(30)
to_chat(src, "<span class='warning'>Deadlock detected in primary systems, error code [rand(101, 999)].</span>")
if("shortmute")
ADD_TRAIT(src, TRAIT_MUTE, CORRUPTED_SYSTEM)
addtimer(CALLBACK(src, .proc/reenable_speech), 5 SECONDS)
to_chat(src, "<span class='notice'>Communications matrix successfully shutdown for maintenance.</span>")
if("vomit")
to_chat(src, "<span class='notice'>Ejecting contaminant.</span>")
vomit()
if("halluscinate")
hallucination += 20 //Doesn't give a cue
if("receporgandamage")
adjustOrganLoss(ORGAN_SLOT_EARS, rand(10, 20))
adjustOrganLoss(ORGAN_SLOT_EYES, rand(10, 20))
to_chat(src, "<span class='warning'>Power spike detected in auditory and visual systems!</span>")
if("longlimbdisable")
var/disabled_type = pick(list(TRAIT_PARALYSIS_L_ARM, TRAIT_PARALYSIS_R_ARM, TRAIT_PARALYSIS_L_LEG, TRAIT_PARALYSIS_R_LEG))
ADD_TRAIT(src, disabled_type, CORRUPTED_SYSTEM)
addtimer(CALLBACK(src, .proc/reenable_limb, disabled_type), 25 SECONDS)
to_chat(src, "<span class='warning'>Fatal error in limb control subsystem - rebooting.</span>")
if("blindmutedeaf")
ADD_TRAIT(src, TRAIT_BLIND, CORRUPTED_SYSTEM)
addtimer(CALLBACK(src, .proc/reenable_vision), (rand(10, 25)) SECONDS)
ADD_TRAIT(src, TRAIT_DEAF, CORRUPTED_SYSTEM)
addtimer(CALLBACK(src, .proc/reenable_hearing), (rand(15, 35)) SECONDS)
ADD_TRAIT(src, TRAIT_MUTE, CORRUPTED_SYSTEM)
addtimer(CALLBACK(src, .proc/reenable_speech), (rand(20, 45)) SECONDS)
to_chat(src, "<span class='warning'>Fatal error in multiple systems - Performing recovery.</span>")
if("longstun")
Stun(80)
to_chat(src, "<span class='warning'Critical divide-by-zero error detected - Failsafe initiated.</span>")
if("sleep")
addtimer(CALLBACK(src, .proc/forcesleep), (rand(6, 10)) SECONDS)
to_chat(src, "<span class='warning'>Priority 1 shutdown order received in operating system - Preparing powerdown.</span>")
if("inducetrauma")
to_chat(src, "<span class='warning'>Major interference detected in main operating matrix - Complications possible.</span>")
var/resistance = pick(
65;TRAUMA_RESILIENCE_BASIC,
35;TRAUMA_RESILIENCE_SURGERY)
var/trauma_type = pickweight(list(
BRAIN_TRAUMA_MILD = 80,
BRAIN_TRAUMA_SEVERE = 10))
gain_trauma_type(trauma_type, resistance) //Gaining the trauma will inform them, but we'll tell them too so they know what the reason was.
if("amplifycorrupt")
adjustToxLoss(5, toxins_type = TOX_SYSCORRUPT)
to_chat(src, "<span class='warning'>System safeguards failing - Action urgently required.</span>")
if("changetemp")
adjust_bodytemperature(rand(150, 250))
to_chat(src, "<span class='warning'>Warning - Fatal coolant flow error at node [rand(6, 99)]!</span>") //This is totally not a reference to anything.
/mob/living/carbon/proc/reenable_limb(disabled_limb)
REMOVE_TRAIT(src, disabled_limb, CORRUPTED_SYSTEM)
to_chat(src, "<span class='notice'>Limb control subsystem successfully rebooted.</span>")
/mob/living/carbon/proc/reenable_hearing()
REMOVE_TRAIT(src, TRAIT_DEAF, CORRUPTED_SYSTEM)
to_chat(src, "<span class='notice'>Hearing restored.</span>")
/mob/living/carbon/proc/reenable_vision()
REMOVE_TRAIT(src, TRAIT_BLIND, CORRUPTED_SYSTEM)
to_chat(src, "<span class='notice'>Visual receptors back online.</span>")
/mob/living/carbon/proc/reenable_speech()
REMOVE_TRAIT(src, TRAIT_MUTE, CORRUPTED_SYSTEM)
to_chat(src, "<span class='notice'>Communications subsystem operational.</span>")
/mob/living/carbon/proc/forcesleep(time = 100)
to_chat(src, "<span class='notice'>Preparations complete, powering down.</span>")
Sleeping(time, 0)
#undef CORRUPTION_CHECK_INTERVAL
#undef CORRUPTION_THRESHHOLD_MINOR
#undef CORRUPTION_THRESHHOLD_MAJOR
#undef CORRUPTION_THRESHHOLD_CRITICAL
@@ -212,6 +212,7 @@
// called when something steps onto a human
// this could be made more general, but for now just handle mulebot
/mob/living/carbon/human/Crossed(atom/movable/AM)
SEND_SIGNAL(src, COMSIG_MOVABLE_CROSSED, AM)
var/mob/living/simple_animal/bot/mulebot/MB = AM
if(istype(MB))
MB.RunOver(src)
@@ -1,4 +1,6 @@
/mob/living/carbon/human/getarmor(def_zone, type)
if(HAS_TRAIT(src, TRAIT_ARMOR_BROKEN)) //trait that makes it act as if you have no armor at all, you take natural damage from all sources
return 0
var/armorval = 0
var/organnum = 0
@@ -18,7 +20,6 @@
organnum++
return (armorval/max(organnum, 1))
/mob/living/carbon/human/proc/checkarmor(obj/item/bodypart/def_zone, d_type)
if(!d_type || !def_zone)
return 0
@@ -410,6 +411,8 @@
if(isrobotic(src))
apply_status_effect(/datum/status_effect/no_combat_mode/robotic_emp, severity / 20)
severity *= 0.5
if(HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM))
severity *= 0.5 //Robotpeople take less limb damage, but instead suffer system corruption (see carbon emp_act)
for(var/obj/item/bodypart/L in src.bodyparts)
if(L.is_robotic_limb())
if(!informed)
@@ -14,6 +14,7 @@
blocks_emissive = EMISSIVE_BLOCK_UNIQUE
block_parry_data = /datum/block_parry_data/unarmed/human
default_block_parry_data = /datum/block_parry_data/unarmed/human
//Hair colour and style
var/hair_color = "000"
@@ -98,20 +99,54 @@
parry_failed_clickcd_duration = 0.4
parry_data = list( // yeah it's snowflake
"HUMAN_PARRY_STAGGER" = 3 SECONDS,
"HUMAN_PARRY_PUNCH" = TRUE,
"HUMAN_PARRY_MININUM_EFFICIENCY" = 0.9
"UNARMED_PARRY_STAGGER" = 3 SECONDS,
"UNARMED_PARRY_PUNCH" = TRUE,
"UNARMED_PARRY_MININUM_EFFICIENCY" = 90
)
/mob/living/carbon/human/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time)
/mob/living/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time)
var/datum/block_parry_data/D = return_block_parry_datum(block_parry_data)
. = ..()
if(!owner.Adjacent(attacker))
return ..()
if(parry_efficiency < D.parry_data["HUMAN_PARRY_MINIMUM_EFFICIENCY"])
return ..()
return
if(parry_efficiency < D.parry_data["UNARMED_PARRY_MINIMUM_EFFICIENCY"])
return
visible_message("<span class='warning'>[src] strikes back perfectly at [attacker], staggering them!</span>")
if(D.parry_data["HUMAN_PARRY_PUNCH"])
if(D.parry_data["UNARMED_PARRY_PUNCH"])
UnarmedAttack(attacker, TRUE, INTENT_HARM, ATTACK_IS_PARRY_COUNTERATTACK | ATTACK_IGNORE_ACTION | ATTACK_IGNORE_CLICKDELAY | NO_AUTO_CLICKDELAY_HANDLING)
var/mob/living/L = attacker
if(istype(L))
L.Stagger(D.parry_data["HUMAN_PARRY_STAGGER"])
L.Stagger(D.parry_data["UNARMED_PARRY_STAGGER"])
/// Unarmed parry data for pugilists
/datum/block_parry_data/unarmed/pugilist
parry_respect_clickdelay = FALSE
parry_stamina_cost = 4
parry_attack_types = ATTACK_TYPE_UNARMED | ATTACK_TYPE_PROJECTILE | ATTACK_TYPE_TACKLE | ATTACK_TYPE_THROWN | ATTACK_TYPE_MELEE
parry_flags = PARRY_DEFAULT_HANDLE_FEEDBACK | PARRY_LOCK_ATTACKING
parry_time_windup = 0
parry_time_spindown = 0
parry_time_active = 5
parry_time_perfect = 1.5
parry_time_perfect_leeway = 1.5
parry_imperfect_falloff_percent = 20
parry_efficiency_perfect = 100
parry_efficiency_perfect_override = list(
ATTACK_TYPE_PROJECTILE_TEXT = 60,
)
parry_efficiency_considered_successful = 0.01
parry_efficiency_to_counterattack = 0.01
parry_max_attacks = INFINITY
parry_failed_cooldown_duration = 1.5 SECONDS
parry_failed_stagger_duration = 0
parry_cooldown = 0
parry_failed_clickcd_duration = 0.8
parry_data = list( // yeah it's snowflake
"UNARMED_PARRY_STAGGER" = 3 SECONDS,
"UNARMED_PARRY_PUNCH" = TRUE,
"UNARMED_PARRY_MININUM_EFFICIENCY" = 90
)
@@ -100,8 +100,3 @@
if(dna.species.space_move(src))
return TRUE
return ..()
/mob/living/carbon/human/CanPass(atom/movable/mover, turf/target)
if(dna.species.species_pass_check())
return TRUE
return ..()
@@ -0,0 +1,112 @@
/datum/action/innate/ability/slime_blobform
name = "Puddle Transformation"
check_flags = AB_CHECK_CONSCIOUS
button_icon_state = "slimepuddle"
icon_icon = 'icons/mob/actions/actions_slime.dmi'
background_icon_state = "bg_alien"
required_mobility_flags = MOBILITY_STAND
var/is_puddle = FALSE
var/in_transformation_duration = 12
var/out_transformation_duration = 7
var/puddle_into_effect = /obj/effect/temp_visual/slime_puddle
var/puddle_from_effect = /obj/effect/temp_visual/slime_puddle/reverse
var/puddle_icon = 'icons/mob/mob.dmi'
var/puddle_state = "puddle"
var/mutable_appearance/tracked_overlay
var/datum/component/squeak/squeak
var/transforming = FALSE
var/last_use
/datum/action/innate/ability/slime_blobform/IsAvailable()
if(!transforming)
return ..()
else
return FALSE
/datum/action/innate/ability/slime_blobform/Remove(mob/M)
if(is_puddle)
detransform()
return ..()
/datum/action/innate/ability/slime_blobform/Activate()
var/mob/living/carbon/human/H = owner
//if they have anything stuck to their hands, we immediately say 'no' and return
for(var/obj/item/I in H.held_items)
if(HAS_TRAIT(I, TRAIT_NODROP))
to_chat(owner, "There's something stuck to your hand, stopping you from transforming!")
return
if(IsAvailable())
transforming = TRUE
UpdateButtonIcon()
var/mutcolor = owner.get_ability_property(INNATE_ABILITY_SLIME_BLOBFORM, PROPERTY_BLOBFORM_COLOR) || ("#" + H.dna.features["mcolor"])
if(!is_puddle)
if(CHECK_MOBILITY(H, MOBILITY_USE)) //if we can use items, we can turn into a puddle
is_puddle = TRUE //so we know which transformation to use when its used
ADD_TRAIT(H, TRAIT_HUMAN_NO_RENDER, SLIMEPUDDLE_TRAIT)
owner.cut_overlays() //we dont show our normal sprite, we show a puddle sprite
var/obj/effect/puddle_effect = new puddle_into_effect(get_turf(owner), owner.dir)
puddle_effect.color = mutcolor
H.Stun(in_transformation_duration, ignore_canstun = TRUE) //cant move while transforming
//series of traits that make up the puddle behaviour
ADD_TRAIT(H, TRAIT_PARALYSIS_L_ARM, SLIMEPUDDLE_TRAIT)
ADD_TRAIT(H, TRAIT_PARALYSIS_R_ARM, SLIMEPUDDLE_TRAIT)
ADD_TRAIT(H, TRAIT_MOBILITY_NOPICKUP, SLIMEPUDDLE_TRAIT)
ADD_TRAIT(H, TRAIT_MOBILITY_NOUSE, SLIMEPUDDLE_TRAIT)
ADD_TRAIT(H, TRAIT_SPRINT_LOCKED, SLIMEPUDDLE_TRAIT)
ADD_TRAIT(H, TRAIT_COMBAT_MODE_LOCKED, SLIMEPUDDLE_TRAIT)
ADD_TRAIT(H, TRAIT_MOBILITY_NOREST, SLIMEPUDDLE_TRAIT)
ADD_TRAIT(H, TRAIT_ARMOR_BROKEN, SLIMEPUDDLE_TRAIT)
H.update_disabled_bodyparts(silent = TRUE) //silently update arms to be paralysed
H.add_movespeed_modifier(/datum/movespeed_modifier/slime_puddle)
H.layer -= 1 //go one layer down so people go over you
ENABLE_BITFIELD(H.pass_flags, PASSMOB) //this actually lets people pass over you
squeak = H.AddComponent(/datum/component/squeak, custom_sounds = list('sound/effects/blobattack.ogg')) //blorble noise when people step on you
//if the user is a changeling, retract their sting
H.unset_sting()
sleep(in_transformation_duration) //wait for animation to end
//set the puddle overlay up
var/mutable_appearance/puddle_overlay = mutable_appearance(icon = puddle_icon, icon_state = puddle_state)
puddle_overlay.color = mutcolor
tracked_overlay = puddle_overlay
owner.add_overlay(puddle_overlay)
transforming = FALSE
UpdateButtonIcon()
else
detransform()
else
to_chat(owner, "<span class='warning'>You need to be standing up to do this!") //just assume they're a slime because it's such a weird edgecase to have it and not be one (it shouldn't even be possible)
/datum/action/innate/ability/slime_blobform/proc/detransform()
var/mob/living/carbon/human/H = owner
//like the above, but reverse everything done!
H.cut_overlay(tracked_overlay)
var/obj/effect/puddle_effect = new puddle_from_effect(get_turf(owner), owner.dir)
puddle_effect.color = tracked_overlay.color
H.Stun(out_transformation_duration, ignore_canstun = TRUE)
sleep(out_transformation_duration)
REMOVE_TRAIT(H, TRAIT_PARALYSIS_L_ARM, SLIMEPUDDLE_TRAIT)
REMOVE_TRAIT(H, TRAIT_PARALYSIS_R_ARM, SLIMEPUDDLE_TRAIT)
REMOVE_TRAIT(H, TRAIT_MOBILITY_NOPICKUP, SLIMEPUDDLE_TRAIT)
REMOVE_TRAIT(H, TRAIT_MOBILITY_NOUSE, SLIMEPUDDLE_TRAIT)
REMOVE_TRAIT(H, TRAIT_SPRINT_LOCKED, SLIMEPUDDLE_TRAIT)
REMOVE_TRAIT(H, TRAIT_COMBAT_MODE_LOCKED, SLIMEPUDDLE_TRAIT)
REMOVE_TRAIT(H, TRAIT_MOBILITY_NOREST, SLIMEPUDDLE_TRAIT)
REMOVE_TRAIT(H, TRAIT_ARMOR_BROKEN, SLIMEPUDDLE_TRAIT)
REMOVE_TRAIT(H, TRAIT_HUMAN_NO_RENDER, SLIMEPUDDLE_TRAIT)
H.update_disabled_bodyparts(silent = TRUE)
H.remove_movespeed_modifier(/datum/movespeed_modifier/slime_puddle)
H.layer += 1 //go one layer back above!
DISABLE_BITFIELD(H.pass_flags, PASSMOB)
is_puddle = FALSE
if(squeak)
squeak.RemoveComponent()
transforming = FALSE
UpdateButtonIcon()
@@ -0,0 +1,208 @@
/datum/action/innate/ability/humanoid_customization
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/ability/humanoid_customization/Activate()
if(owner.get_ability_property(INNATE_ABILITY_HUMANOID_CUSTOMIZATION, PROPERTY_CUSTOMIZATION_SILENT))
owner.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()
///////
/////// NOTICE: This currently doens't support skin tone - if anyone wants to add this to non slimes, it's up to YOU to do this.
////// (someone should also add genital color switching, more mutant color selection)
///// maybe just make this entire thing tgui based. maybe.
///////
/datum/action/innate/ability/humanoid_customization/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("Body Color","Hair Style", "Genitals", "Tail", "Snout", "Markings", "Ears", "Taur body", "Penis", "Vagina", "Penis Length", "Breast Size", "Breast Shape", "Cancel")
if(select_alteration == "Body Color")
var/new_color = input(owner, "Choose your skin color:", "Race change","#"+H.dna.features["mcolor"]) as color|null
if(new_color)
var/temp_hsv = RGBtoHSV(new_color)
if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) // mutantcolors must be bright
H.dna.features["mcolor"] = sanitize_hexcolor(new_color, 6)
H.update_body()
H.update_hair()
else
to_chat(H, "<span class='notice'>Invalid color. Your color is not bright enough.</span>")
else if(select_alteration == "Hair Style")
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/ears/mam_ears/instance = GLOB.mam_ears_list[path]
if(istype(instance, /datum/sprite_accessory))
var/datum/sprite_accessory/S = instance
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
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/snouts/mam_snouts/instance = GLOB.mam_snouts_list[path]
if(istype(instance, /datum/sprite_accessory))
var/datum/sprite_accessory/S = instance
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
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("None")
for(var/path in GLOB.mam_body_markings_list)
var/datum/sprite_accessory/mam_body_markings/instance = GLOB.mam_body_markings_list[path]
if(istype(instance, /datum/sprite_accessory))
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
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/tails/mam_tails/instance = GLOB.mam_tails_list[path]
if(istype(instance, /datum/sprite_accessory))
var/datum/sprite_accessory/S = instance
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
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/min_D = CONFIG_GET(number/penis_min_inches_prefs)
var/max_D = CONFIG_GET(number/penis_max_inches_prefs)
var/new_length = input(owner, "Penis length in inches:\n([min_D]-[max_D])", "Genital Alteration") as num|null
if(new_length)
H.dna.features["cock_length"] = clamp(round(new_length), min_D, max_D)
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 = input(owner, "Breast Size", "Genital Alteration") as null|anything in CONFIG_GET(keyed_list/breasts_cups_prefs)
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
@@ -0,0 +1,49 @@
/datum/action/innate/ability/limb_regrowth
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"
required_mobility_flags = NONE
/datum/action/innate/ability/limb_regrowth/IsAvailable(silent = FALSE)
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
var/mode = H.get_ability_property(INNATE_ABILITY_LIMB_REGROWTH, PROPERTY_LIMB_REGROWTH_USAGE_TYPE)
switch(mode)
if(REGROWTH_USES_BLOOD)
if(H.blood_volume >= (BLOOD_VOLUME_OKAY*H.blood_ratio)+40)
return TRUE
else
return FALSE
return 0
/datum/action/innate/ability/limb_regrowth/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>")
var/mode = H.get_ability_property(INNATE_ABILITY_LIMB_REGROWTH, PROPERTY_LIMB_REGROWTH_USAGE_TYPE)
switch(mode)
if(REGROWTH_USES_BLOOD)
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>")
+2 -2
View File
@@ -268,9 +268,9 @@
return round(thermal_protection/max_protection, 0.001)
/mob/living/carbon/human/handle_random_events()
//Puke if toxloss is too high
//Puke if toxloss is too high and we aren't a robot, because those have advanced toxins (corruption) handling
if(!stat)
if(getToxLoss() >= 45 && nutrition > 20)
if(getToxLoss() >= 45 && nutrition > 20 && !HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM))
lastpuke += prob(50)
if(lastpuke >= 50) // about 25 second delay I guess
vomit(20, toxic = TRUE)
@@ -7,6 +7,7 @@
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/stamina_buffer_mod = 1 // % of stamina buffer
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)
+64 -33
View File
@@ -175,6 +175,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
//Called when cloning, copies some vars that should be kept
/datum/species/proc/copy_properties_from(datum/species/old_species)
mutant_bodyparts["limbs_id"] = old_species.mutant_bodyparts["limbs_id"]
eye_type = old_species.eye_type
mutanttongue = old_species.mutanttongue
return
//Please override this locally if you want to define when what species qualifies for what rank if human authority is enforced.
@@ -668,7 +671,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.remove_overlay(BODY_FRONT_LAYER)
H.remove_overlay(HORNS_LAYER)
if(!mutant_bodyparts)
if(!length(mutant_bodyparts))
return
var/tauric = mutant_bodyparts["taur"] && H.dna.features["taur"] && H.dna.features["taur"] != "None"
@@ -746,14 +749,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
)
var/g = (H.dna.features["body_model"] == FEMALE) ? "f" : "m"
var/list/colorlist = list()
var/husk = HAS_TRAIT(H, TRAIT_HUSK)
colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features["mcolor"]]00")
colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features["mcolor2"]]00")
colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features["mcolor3"]]00")
colorlist += husk ? list(0, 0, 0) : list(0, 0, 0, hair_alpha)
for(var/index in 1 to colorlist.len)
colorlist[index] /= 255
for(var/layer in relevant_layers)
var/list/standing = list()
@@ -775,6 +771,22 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(S.center)
accessory_overlay = center_image(accessory_overlay, S.dimension_x, S.dimension_y)
var/advanced_color_system = (H.dna.features["color_scheme"] == ADVANCED_CHARACTER_COLORING)
var/mutant_string = S.mutant_part_string
if(mutant_string == "tailwag") //wagging tails should be coloured the same way as your tail
mutant_string = "tail"
var/primary_string = advanced_color_system ? "[mutant_string]_primary" : "mcolor"
var/secondary_string = advanced_color_system ? "[mutant_string]_secondary" : "mcolor2"
var/tertiary_string = advanced_color_system ? "[mutant_string]_tertiary" : "mcolor3"
//failsafe: if there's no value for any of these, set it to white
if(!H.dna.features[primary_string])
H.dna.features[primary_string] = advanced_color_system ? H.dna.features["mcolor"] : "FFFFFF"
if(!H.dna.features[secondary_string])
H.dna.features[secondary_string] = advanced_color_system ? H.dna.features["mcolor2"] : "FFFFFF"
if(!H.dna.features[tertiary_string])
H.dna.features[tertiary_string] = advanced_color_system ? H.dna.features["mcolor3"] : "FFFFFF"
if(!husk)
if(!forced_colour)
switch(S.color_src)
@@ -784,20 +796,36 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(fixed_mut_color)
accessory_overlay.color = "#[fixed_mut_color]"
else
accessory_overlay.color = "#[H.dna.features["mcolor"]]"
accessory_overlay.color = "#[H.dna.features[primary_string]]"
if(MUTCOLORS2)
if(fixed_mut_color2)
accessory_overlay.color = "#[fixed_mut_color2]"
else
accessory_overlay.color = "#[H.dna.features["mcolor2"]]"
accessory_overlay.color = "#[H.dna.features[primary_string]]"
if(MUTCOLORS3)
if(fixed_mut_color3)
accessory_overlay.color = "#[fixed_mut_color3]"
else
accessory_overlay.color = "#[H.dna.features["mcolor3"]]"
accessory_overlay.color = "#[H.dna.features[primary_string]]"
if(MATRIXED)
accessory_overlay.color = list(colorlist)
var/list/accessory_colorlist = list()
if(S.matrixed_sections == MATRIX_RED || S.matrixed_sections == MATRIX_RED_GREEN || S.matrixed_sections == MATRIX_RED_BLUE || S.matrixed_sections == MATRIX_ALL)
accessory_colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features[primary_string]]00")
else
accessory_colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("00000000")
if(S.matrixed_sections == MATRIX_GREEN || S.matrixed_sections == MATRIX_RED_GREEN || S.matrixed_sections == MATRIX_GREEN_BLUE || S.matrixed_sections == MATRIX_ALL)
accessory_colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features[secondary_string]]00")
else
accessory_colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("00000000")
if(S.matrixed_sections == MATRIX_BLUE || S.matrixed_sections == MATRIX_RED_BLUE || S.matrixed_sections == MATRIX_GREEN_BLUE || S.matrixed_sections == MATRIX_ALL)
accessory_colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features[tertiary_string]]00")
else
accessory_colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("00000000")
accessory_colorlist += husk ? list(0, 0, 0) : list(0, 0, 0, hair_alpha)
for(var/index in 1 to accessory_colorlist.len)
accessory_colorlist[index] /= 255
accessory_overlay.color = list(accessory_colorlist)
if(HAIR)
if(hair_color == "mutcolor")
@@ -820,7 +848,14 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(bodypart == "tail")
accessory_overlay.icon_state = "m_tail_husk_[layertext]"
if(S.color_src == MATRIXED)
accessory_overlay.color = colorlist
var/list/accessory_colorlist = list()
accessory_colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features[primary_string]]00")
accessory_colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features[secondary_string]]00")
accessory_colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features[tertiary_string]]00")
accessory_colorlist += husk ? list(0, 0, 0) : list(0, 0, 0, hair_alpha)
for(var/index in 1 to accessory_colorlist.len)
accessory_colorlist[index] /= 255
accessory_overlay.color = list(accessory_colorlist)
if(OFFSET_MUTPARTS in H.dna.species.offset_features)
accessory_overlay.pixel_x += H.dna.species.offset_features[OFFSET_MUTPARTS][1]
@@ -837,23 +872,22 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(S.center)
extra_accessory_overlay = center_image(extra_accessory_overlay, S.dimension_x, S.dimension_y)
switch(S.extra_color_src) //change the color of the extra overlay
if(MUTCOLORS)
if(fixed_mut_color)
extra_accessory_overlay.color = "#[fixed_mut_color]"
else
extra_accessory_overlay.color = "#[H.dna.features["mcolor"]]"
extra_accessory_overlay.color = "#[H.dna.features[secondary_string]]"
if(MUTCOLORS2)
if(fixed_mut_color2)
extra_accessory_overlay.color = "#[fixed_mut_color2]"
else
extra_accessory_overlay.color = "#[H.dna.features["mcolor2"]]"
extra_accessory_overlay.color = "#[H.dna.features[secondary_string]]"
if(MUTCOLORS3)
if(fixed_mut_color3)
extra_accessory_overlay.color = "#[fixed_mut_color3]"
else
extra_accessory_overlay.color = "#[H.dna.features["mcolor3"]]"
extra_accessory_overlay.color = "#[H.dna.features[secondary_string]]"
if(HAIR)
if(hair_color == "mutcolor")
extra_accessory_overlay.color = "#[H.dna.features["mcolor3"]]"
@@ -889,17 +923,17 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(fixed_mut_color)
extra2_accessory_overlay.color = "#[fixed_mut_color]"
else
extra2_accessory_overlay.color = "#[H.dna.features["mcolor"]]"
extra2_accessory_overlay.color = "#[H.dna.features[tertiary_string]]"
if(MUTCOLORS2)
if(fixed_mut_color2)
extra2_accessory_overlay.color = "#[fixed_mut_color2]"
else
extra2_accessory_overlay.color = "#[H.dna.features["mcolor2"]]"
extra2_accessory_overlay.color = "#[H.dna.features[tertiary_string]]"
if(MUTCOLORS3)
if(fixed_mut_color3)
extra2_accessory_overlay.color = "#[fixed_mut_color3]"
else
extra2_accessory_overlay.color = "#[H.dna.features["mcolor3"]]"
extra2_accessory_overlay.color = "#[H.dna.features[tertiary_string]]"
if(HAIR)
if(hair_color == "mutcolor3")
extra2_accessory_overlay.color = "#[H.dna.features["mcolor"]]"
@@ -916,7 +950,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
standing += extra2_accessory_overlay
H.overlays_standing[layernum] = standing
H.apply_overlay(BODY_BEHIND_LAYER)
@@ -1284,6 +1317,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
radiation = 0
return TRUE
if(HAS_TRAIT(H, TRAIT_ROBOTIC_ORGANISM))
return //Robots are hardened against radiation, but suffer system corruption at very high levels.
if(radiation > RAD_MOB_KNOCKDOWN && prob(RAD_MOB_KNOCKDOWN_PROB))
if(CHECK_MOBILITY(H, MOBILITY_STAND))
H.emote("collapse")
@@ -1451,9 +1487,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
target.apply_damage(damage*1.5, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
target.apply_damage(damage*0.5, STAMINA, affecting, armor_block)
log_combat(user, target, "kicked")
else if(HAS_TRAIT(user, TRAIT_MAULER)) // mauler punches deal 1.3x raw damage + 1x stam damage, and have some armor pierce
target.apply_damage(damage*1.3, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
target.apply_damage(damage, STAMINA, affecting, armor_block)
else if(HAS_TRAIT(user, TRAIT_MAULER)) // mauler punches deal 1.1x raw damage + 1.3x stam damage, and have some armor pierce
target.apply_damage(damage*1.1, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
target.apply_damage(damage*1.3, STAMINA, affecting, armor_block)
log_combat(user, target, "punched (mauler)")
else //other attacks deal full raw damage + 2x in stamina damage
target.apply_damage(damage, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
@@ -1689,7 +1725,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(BODY_ZONE_HEAD)
if(!I.get_sharpness() && armor_block < 50)
if(prob(I.force))
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 20)
if(HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM))
H.adjustToxLoss(5, toxins_type = TOX_SYSCORRUPT) //Bonk! - Effectively 5 bonus damage
else
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 20)
if(H.stat == CONSCIOUS)
H.visible_message("<span class='danger'>[H] has been knocked senseless!</span>", \
"<span class='userdanger'>You have been knocked senseless!</span>")
@@ -1963,14 +2002,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(HAS_BONE in species_traits)
. |= BIO_JUST_BONE
//a check for if you should render any overlays or not
/datum/species/proc/should_render(mob/living/carbon/human/H)
return TRUE
//a check for if you want to forcibly make CanPass return TRUE for the mob with this species
/datum/species/proc/species_pass_check()
return FALSE
/////////////
//BREATHING//
/////////////
@@ -3,12 +3,12 @@
id = SPECIES_ANDROID
say_mod = "states"
species_traits = list(NOBLOOD,NOGENITALS,NOAROUSAL,ROBOTIC_LIMBS)
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_NOFIRE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_LIMBATTACHMENT)
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_NOFIRE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_LIMBATTACHMENT, TRAIT_ROBOTIC_ORGANISM)
inherent_biotypes = MOB_ROBOTIC|MOB_HUMANOID
meat = null
gib_types = /obj/effect/gibspawner/robot
damage_overlay_type = "synth"
mutanttongue = /obj/item/organ/tongue/robot
species_language_holder = /datum/language_holder/synthetic
limbs_id = "synth"
limbs_id = SPECIES_SYNTH
species_category = SPECIES_CATEGORY_ROBOT
@@ -7,7 +7,7 @@
use_skintones = USE_SKINTONES_GRAYSCALE_CUSTOM
no_equip = list(SLOT_BACK)
blacklisted = 1
limbs_id = "human"
limbs_id = SPECIES_HUMAN
skinned_type = /obj/item/stack/sheet/animalhide/human
species_category = SPECIES_CATEGORY_BASIC //they're a kind of human
@@ -130,7 +130,7 @@
/datum/species/angel/proc/ToggleFlight(mob/living/carbon/human/H,flight)
if(flight && CanFly(H))
stunmod = 2
speedmod = -0.35
speedmod = -0.1
H.setMovetype(H.movement_type | FLYING)
override_float = TRUE
H.pass_flags |= PASSTABLE
@@ -1,6 +1,6 @@
/datum/species/arachnid
name = "Arachnid"
id = "arachnid"
id = SPECIES_ARACHNID
override_bp_icon = 'icons/mob/arachnid_parts.dmi'
say_mod = "chitters"
default_color = "00FF00"
@@ -59,10 +59,10 @@
SW?.Remove(H)
/datum/action/innate/spin_web
name = "Spin Web"
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
icon_icon = 'icons/mob/actions/actions_animal.dmi'
button_icon_state = "lay_web"
name = "Spin Web"
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
icon_icon = 'icons/mob/actions/actions_animal.dmi'
button_icon_state = "lay_web"
/datum/action/innate/spin_cocoon
name = "Spin Cocoon"
@@ -139,6 +139,18 @@
if(E.web_ready == FALSE)
to_chat(H, "<span class='warning'>You need to wait awhile to regenerate web fluid.</span>")
return
if(!H.Adjacent(A)) //No.
return
if(!isliving(A) && A.anchored)
to_chat(H, "<span class='warning'>[A] is bolted to the floor!</span>")
return
if(istype(A, /obj/structure/arachnid))
to_chat(H, "<span class='warning'>No double wrapping.</span>")
return
if(istype(A, /obj/effect))
to_chat(H, "<span class='warning'>You cannot wrap this.</span>")
return
H.visible_message("<span class='danger'>[H] starts to wrap [A] into a cocoon!</span>","<span class='warning'>You start to wrap [A] into a cocoon.</span>")
if(!do_after(H, 10 SECONDS, 1, A))
to_chat(H, "<span class='warning'>Your web spinning was interrupted!</span>")
return
@@ -152,4 +164,4 @@
else
A.forceMove(C)
H.visible_message("<span class='danger'>[H] wraps [A] into a cocoon!</span>")
return
return
@@ -11,7 +11,7 @@
mutanttongue = /obj/item/organ/tongue/dullahan
mutantears = /obj/item/organ/ears/dullahan
blacklisted = TRUE
limbs_id = "human"
limbs_id = SPECIES_HUMAN
skinned_type = /obj/item/stack/sheet/animalhide/human
has_field_of_vision = FALSE //Too much of a trouble, their vision is already bound to their severed head.
species_category = SPECIES_CATEGORY_UNDEAD
@@ -27,7 +27,7 @@
/datum/species/dullahan/check_roundstart_eligible()
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
return TRUE
return FALSE
return ..()
/datum/species/dullahan/on_species_gain(mob/living/carbon/human/H, datum/species/old_species)
. = ..()
@@ -2,7 +2,7 @@
/datum/species/human/felinid
name = "Felinid"
id = SPECIES_FELINID
limbs_id = "human"
limbs_id = SPECIES_HUMAN
mutant_bodyparts = list("mam_tail" = "Cat", "mam_ears" = "Cat", "deco_wings" = "None")
@@ -5,7 +5,7 @@
default_color = "00FF00"
blacklisted = 0
sexes = 0
inherent_traits = list(TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NO_PROCESS_FOOD)
inherent_traits = list(TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NO_PROCESS_FOOD, TRAIT_ROBOTIC_ORGANISM)
species_traits = list(MUTCOLORS,NOEYES,NOTRANSSTING,HAS_FLESH,HAS_BONE,HAIR,ROBOTIC_LIMBS)
hair_alpha = 210
inherent_biotypes = MOB_ROBOTIC|MOB_HUMANOID
@@ -15,9 +15,6 @@
exotic_bloodtype = "GEL"
exotic_blood_color = "BLOOD_COLOR_SLIME"
damage_overlay_type = ""
var/datum/action/innate/regenerate_limbs/regenerate_limbs
var/datum/action/innate/slime_change/slime_change
var/datum/action/innate/slime_puddle/slime_puddle
liked_food = TOXIC | MEAT
disliked_food = null
toxic_food = ANTITOXIC
@@ -37,27 +34,19 @@
icon_state = "brain-slime"
/datum/species/jelly/on_species_loss(mob/living/carbon/C)
if(slime_puddle && slime_puddle.is_puddle)
slime_puddle.Activate()
if(regenerate_limbs)
regenerate_limbs.Remove(C)
if(slime_change)
slime_change.Remove(C)
if(slime_puddle)
slime_puddle.Remove(C)
C.faction -= "slime"
if(ishuman(C))
var/mob/living/carbon/human/H = C
H.remove_ability_from_source(list(INNATE_ABILITY_SLIME_BLOBFORM, INNATE_ABILITY_LIMB_REGROWTH, INNATE_ABILITY_HUMANOID_CUSTOMIZATION), ABILITY_SOURCE_SPECIES)
..()
C.faction -= "slime"
/datum/species/jelly/on_species_gain(mob/living/carbon/C, datum/species/old_species)
..()
if(ishuman(C))
regenerate_limbs = new
regenerate_limbs.Grant(C)
slime_change = new
slime_change.Grant(C)
slime_puddle = new
slime_puddle.Grant(C)
var/mob/living/carbon/human/H = C
H.grant_ability_from_source(list(INNATE_ABILITY_SLIME_BLOBFORM, INNATE_ABILITY_LIMB_REGROWTH, INNATE_ABILITY_HUMANOID_CUSTOMIZATION), ABILITY_SOURCE_SPECIES)
H.set_ability_property(INNATE_ABILITY_LIMB_REGROWTH, PROPERTY_LIMB_REGROWTH_USAGE_TYPE, REGROWTH_USES_BLOOD)
C.faction |= "slime"
/datum/species/jelly/handle_body(mob/living/carbon/human/H)
@@ -65,18 +54,6 @@
//update blood color to body color
exotic_blood_color = "#" + H.dna.features["mcolor"]
/datum/species/jelly/should_render()
if(slime_puddle && slime_puddle.is_puddle)
return FALSE
else
return ..()
/datum/species/jelly/species_pass_check()
if(slime_puddle && slime_puddle.is_puddle)
return TRUE
else
return ..()
/datum/species/jelly/spec_life(mob/living/carbon/human/H)
if(H.stat == DEAD || HAS_TRAIT(H, TRAIT_NOMARROW)) //can't farm slime jelly from a dead slime/jelly person indefinitely, and no regeneration for blooduskers
return
@@ -94,8 +71,6 @@
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()
@@ -111,47 +86,6 @@
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"
required_mobility_flags = NONE
/datum/action/innate/regenerate_limbs/IsAvailable(silent = FALSE)
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.
@@ -468,7 +402,7 @@
/datum/species/jelly/roundstartslime
name = "Xenobiological Slime Hybrid"
id = SPECIES_SLIME_HYBRID
limbs_id = "slime"
limbs_id = SPECIES_SLIME
default_color = "00FFFF"
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR)
inherent_traits = list(TRAIT_TOXINLOVER)
@@ -480,296 +414,7 @@
heatmod = 1
burnmod = 1
allowed_limb_ids = list("slime","stargazer","lum")
/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("Body Color","Hair Style", "Genitals", "Tail", "Snout", "Markings", "Ears", "Taur body", "Penis", "Vagina", "Penis Length", "Breast Size", "Breast Shape", "Cancel")
if(select_alteration == "Body Color")
var/new_color = input(owner, "Choose your skin color:", "Race change","#"+H.dna.features["mcolor"]) as color|null
if(new_color)
var/temp_hsv = RGBtoHSV(new_color)
if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) // mutantcolors must be bright
H.dna.features["mcolor"] = sanitize_hexcolor(new_color, 6)
H.update_body()
H.update_hair()
else
to_chat(H, "<span class='notice'>Invalid color. Your color is not bright enough.</span>")
else if(select_alteration == "Hair Style")
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/ears/mam_ears/instance = GLOB.mam_ears_list[path]
if(istype(instance, /datum/sprite_accessory))
var/datum/sprite_accessory/S = instance
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
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/snouts/mam_snouts/instance = GLOB.mam_snouts_list[path]
if(istype(instance, /datum/sprite_accessory))
var/datum/sprite_accessory/S = instance
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
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("None")
for(var/path in GLOB.mam_body_markings_list)
var/datum/sprite_accessory/mam_body_markings/instance = GLOB.mam_body_markings_list[path]
if(istype(instance, /datum/sprite_accessory))
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
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/tails/mam_tails/instance = GLOB.mam_tails_list[path]
if(istype(instance, /datum/sprite_accessory))
var/datum/sprite_accessory/S = instance
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
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/min_D = CONFIG_GET(number/penis_min_inches_prefs)
var/max_D = CONFIG_GET(number/penis_max_inches_prefs)
var/new_length = input(owner, "Penis length in inches:\n([min_D]-[max_D])", "Genital Alteration") as num|null
if(new_length)
H.dna.features["cock_length"] = clamp(round(new_length), min_D, max_D)
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 = input(owner, "Breast Size", "Genital Alteration") as null|anything in CONFIG_GET(keyed_list/breasts_cups_prefs)
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
/datum/action/innate/slime_puddle
name = "Puddle Transformation"
check_flags = AB_CHECK_CONSCIOUS
button_icon_state = "slimepuddle"
icon_icon = 'icons/mob/actions/actions_slime.dmi'
background_icon_state = "bg_alien"
required_mobility_flags = MOBILITY_STAND
var/is_puddle = FALSE
var/in_transformation_duration = 12
var/out_transformation_duration = 7
var/puddle_into_effect = /obj/effect/temp_visual/slime_puddle
var/puddle_from_effect = /obj/effect/temp_visual/slime_puddle/reverse
var/puddle_icon = 'icons/mob/mob.dmi'
var/puddle_state = "puddle"
var/tracked_overlay
var/datum/component/squeak/squeak
var/transforming = FALSE
var/last_use
/datum/action/innate/slime_puddle/IsAvailable()
if(!transforming)
return ..()
else
return FALSE
/datum/action/innate/slime_puddle/Activate()
if(isjellyperson(owner) && IsAvailable())
transforming = TRUE
UpdateButtonIcon()
var/mob/living/carbon/human/H = owner
var/mutcolor = "#" + H.dna.features["mcolor"]
if(!is_puddle)
if(CHECK_MOBILITY(H, MOBILITY_USE))
is_puddle = TRUE
owner.cut_overlays()
var/obj/effect/puddle_effect = new puddle_into_effect(get_turf(owner), owner.dir)
puddle_effect.color = mutcolor
H.Stun(in_transformation_duration, ignore_canstun = TRUE)
ADD_TRAIT(H, TRAIT_PARALYSIS_L_ARM, SLIMEPUDDLE_TRAIT)
ADD_TRAIT(H, TRAIT_PARALYSIS_R_ARM, SLIMEPUDDLE_TRAIT)
ADD_TRAIT(H, TRAIT_MOBILITY_NOPICKUP, SLIMEPUDDLE_TRAIT)
ADD_TRAIT(H, TRAIT_MOBILITY_NOUSE, SLIMEPUDDLE_TRAIT)
ADD_TRAIT(H, TRAIT_SPRINT_LOCKED, SLIMEPUDDLE_TRAIT)
ADD_TRAIT(H, TRAIT_COMBAT_MODE_LOCKED, SLIMEPUDDLE_TRAIT)
ADD_TRAIT(H, TRAIT_MOBILITY_NOREST, SLIMEPUDDLE_TRAIT)
H.add_movespeed_modifier(/datum/movespeed_modifier/slime_puddle)
H.update_disabled_bodyparts(silent = TRUE)
H.layer -= 1 //go one layer down so people go over you
ENABLE_BITFIELD(H.pass_flags, PASSMOB)
squeak = H.AddComponent(/datum/component/squeak, custom_sounds = list('sound/effects/blobattack.ogg'))
sleep(in_transformation_duration)
var/mutable_appearance/puddle_overlay = mutable_appearance(icon = puddle_icon, icon_state = puddle_state)
puddle_overlay.color = mutcolor
tracked_overlay = puddle_overlay
owner.add_overlay(puddle_overlay)
transforming = FALSE
UpdateButtonIcon()
else
owner.cut_overlay(tracked_overlay)
var/obj/effect/puddle_effect = new puddle_from_effect(get_turf(owner), owner.dir)
puddle_effect.color = mutcolor
H.Stun(out_transformation_duration, ignore_canstun = TRUE)
sleep(out_transformation_duration)
REMOVE_TRAIT(H, TRAIT_PARALYSIS_L_ARM, SLIMEPUDDLE_TRAIT)
REMOVE_TRAIT(H, TRAIT_PARALYSIS_R_ARM, SLIMEPUDDLE_TRAIT)
REMOVE_TRAIT(H, TRAIT_MOBILITY_NOPICKUP, SLIMEPUDDLE_TRAIT)
REMOVE_TRAIT(H, TRAIT_MOBILITY_NOUSE, SLIMEPUDDLE_TRAIT)
REMOVE_TRAIT(H, TRAIT_SPRINT_LOCKED, SLIMEPUDDLE_TRAIT)
REMOVE_TRAIT(H, TRAIT_COMBAT_MODE_LOCKED, SLIMEPUDDLE_TRAIT)
REMOVE_TRAIT(H, TRAIT_MOBILITY_NOREST, SLIMEPUDDLE_TRAIT)
H.update_disabled_bodyparts(silent = TRUE)
H.remove_movespeed_modifier(/datum/movespeed_modifier/slime_puddle)
H.layer += 1 //go one layer back above!
DISABLE_BITFIELD(H.pass_flags, PASSMOB)
is_puddle = FALSE
if(squeak)
squeak.RemoveComponent()
owner.regenerate_icons()
transforming = FALSE
UpdateButtonIcon()
else
to_chat(owner, "<span class='warning'>You need to be standing up to do this!") //just assume they're a slime because it's such a weird edgecase to have it and not be one (it shouldn't even be possible)
allowed_limb_ids = list(SPECIES_SLIME,SPECIES_STARGAZER,SPECIES_SLIME_LUMI)
///////////////////////////////////LUMINESCENTS//////////////////////////////////////////
@@ -28,7 +28,7 @@
tail_type = "tail_lizard"
wagging_type = "waggingtail_lizard"
species_category = "lizard"
species_category = SPECIES_CATEGORY_LIZARD
/datum/species/lizard/random_name(gender,unique,lastname)
if(unique)
@@ -47,7 +47,7 @@
/datum/species/lizard/ashwalker
name = "Ash Walker"
id = SPECIES_ASHWALKER
limbs_id = "lizard"
limbs_id = SPECIES_LIZARD
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE)
inherent_traits = list(TRAIT_CHUNKYFINGERS)
mutantlungs = /obj/item/organ/lungs/ashwalker
@@ -10,6 +10,7 @@
burnmod = 1.25
heatmod = 1.5
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/plant
exotic_blood_color = BLOOD_COLOR_PLANT
disliked_food = MEAT | DAIRY
liked_food = VEGETABLES | FRUIT | GRAIN
species_language_holder = /datum/language_holder/sylvan
@@ -69,7 +70,7 @@
id = SPECIES_POD_WEAK
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS)
mutant_bodyparts = list("mcolor" = "FFFFFF","mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs")
limbs_id = "pod"
limbs_id = SPECIES_POD
light_nutrition_gain_factor = 3
light_bruteheal = -0.2
light_burnheal = -0.2
@@ -33,7 +33,7 @@
/datum/species/shadow/nightmare
name = "Nightmare"
id = SPECIES_NIGHTMARE
limbs_id = "shadow"
limbs_id = SPECIES_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)
@@ -141,7 +141,7 @@
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"))
if(!(owner.dna.species.id == SPECIES_SHADOW || owner.dna.species.id == SPECIES_NIGHTMARE))
var/mob/living/carbon/old_owner = owner
Remove(HEART_SPECIAL_SHADOWIFY)
old_owner.set_species(/datum/species/shadow)
@@ -32,7 +32,7 @@
/datum/species/skeleton/space
name = "Spooky Spacey Skeleton"
id = SPECIES_SKELETON_SPACE
limbs_id = "skeleton"
limbs_id = SPECIES_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)
@@ -4,7 +4,7 @@
say_mod = "beeps"
default_color = "00FF00"
species_traits = list(MUTCOLORS,NOTRANSSTING,EYECOLOR,LIPS,HAIR,ROBOTIC_LIMBS,HAS_FLESH,HAS_BONE)
inherent_traits = list(TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NO_PROCESS_FOOD)
inherent_traits = list(TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NO_PROCESS_FOOD, TRAIT_ROBOTIC_ORGANISM)
inherent_biotypes = MOB_ROBOTIC|MOB_HUMANOID
mutant_bodyparts = list("ipc_antenna" = "Synthetic Lizard - Antennae","mam_tail" = "Synthetic Lizard", "mam_snouts" = "Synthetic Lizard - Snout", "legs" = "Digitigrade", "mam_body_markings" = "Synthetic Lizard - Plates", "taur" = "None")
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ipc
@@ -11,7 +11,7 @@
meat = null
gib_types = /obj/effect/gibspawner/robot
damage_overlay_type = "synth"
limbs_id = "synth"
limbs_id = SPECIES_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
@@ -80,7 +80,7 @@
qdel(fake_species)
fake_species = null
meat = initial(meat)
limbs_id = "synth"
limbs_id = SPECIES_SYNTH
use_skintones = FALSE
sexes = 0
fixed_mut_color = ""
@@ -11,12 +11,17 @@
mutant_heart = /obj/item/organ/heart/vampire
mutanttongue = /obj/item/organ/tongue/vampire
blacklisted = TRUE
limbs_id = "human"
limbs_id = SPECIES_HUMAN
skinned_type = /obj/item/stack/sheet/animalhide/human
var/info_text = "You are a <span class='danger'>Vampire</span>. You will slowly but constantly lose blood if outside of a coffin. If inside a coffin, you will slowly heal. You may gain more blood by grabbing a live victim and using your drain ability."
species_category = SPECIES_CATEGORY_UNDEAD
var/batform_enabled = TRUE
/datum/species/vampire/check_roundstart_eligible()
/datum/species/vampire/roundstart
id = SPECIES_VAMPIRE_WEAK
batform_enabled = FALSE
/datum/species/vampire/roundstart/check_roundstart_eligible()
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
return TRUE
return FALSE
@@ -27,8 +32,9 @@
if(!C.dna.skin_tone_override)
C.skin_tone = "albino"
C.update_body(0)
var/obj/effect/proc_holder/spell/targeted/shapeshift/bat/B = new
C.AddSpell(B)
if(batform_enabled)
var/obj/effect/proc_holder/spell/targeted/shapeshift/bat/B = new
C.AddSpell(B)
/datum/species/vampire/on_species_loss(mob/living/carbon/C)
. = ..()
@@ -153,16 +159,33 @@
to_chat(caster, "<span class='warning'>You're already shapeshifted!</span>")
return
if(!ishuman(caster))
to_chat(caster, "<span class='warning'>You need to be humanoid to be able to do this!</span>")
return
var/mob/living/carbon/human/human_caster = caster
var/mob/living/shape = new shapeshift_type(caster.loc)
H = new(shape,src,caster)
H = new(shape,src,human_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))))
if((human_caster.blood_volume <= (BLOOD_VOLUME_BAD*human_caster.blood_ratio)) || (ventcrawl_nude_only && length(human_caster.get_equipped_items(include_pockets = TRUE))))
SA.ventcrawler = FALSE
if(transfer_name)
H.name = caster.name
H.name = human_caster.name
clothes_req = NONE
mobs_whitelist = null
mobs_blacklist = null
/obj/effect/proc_holder/spell/targeted/shapeshift/bat/cast(list/targets, mob/user = usr)
if(!(locate(/obj/shapeshift_holder) in targets[1]))
if(!ishuman(user))
to_chat(user, "<span class='warning'>You need to be humanoid to be able to do this!</span>")
return
var/mob/living/carbon/human/human_user = user
if(!(human_user.dna?.species?.id == SPECIES_VAMPIRE))
to_chat(user, "<span class='warning'>You don't seem to be able to shapeshift..</span>")
return
return ..()
@@ -3,7 +3,7 @@
/datum/species/zombie
// 1spooky
name = "High-Functioning Zombie"
id = "zombie"
id = SPECIES_ZOMBIE
say_mod = "moans"
sexes = 0
blacklisted = 1
@@ -19,7 +19,7 @@
/datum/species/zombie/notspaceproof
id = "notspaceproofzombie"
limbs_id = "zombie"
limbs_id = SPECIES_ZOMBIE
blacklisted = 0
inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_RADIMMUNE,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NOBREATH,TRAIT_NODEATH,TRAIT_FAKEDEATH)
@@ -31,7 +31,7 @@
/datum/species/zombie/infectious
name = "Infectious Zombie"
id = "memezombies"
limbs_id = "zombie"
limbs_id = SPECIES_ZOMBIE
inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NOBREATH,TRAIT_NODEATH,TRAIT_NOSOFTCRIT, TRAIT_FAKEDEATH)
mutanthands = /obj/item/zombie_hand
armor = 20 // 120 damage to KO a zombie, which kills it
@@ -100,7 +100,7 @@
/datum/species/krokodil_addict
name = SPECIES_HUMAN
id = "goofzombies"
limbs_id = "zombie" //They look like zombies
limbs_id = SPECIES_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
@@ -48,18 +48,22 @@ There are several things that need to be remembered:
*/
/mob/living/carbon/human/ComponentInitialize()
. = ..()
RegisterSignal(src, SIGNAL_TRAIT(TRAIT_HUMAN_NO_RENDER), /mob.proc/regenerate_icons)
//HAIR OVERLAY
/mob/living/carbon/human/update_hair()
if(dna.species.should_render())
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
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()
if(dna.species.should_render())
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
dna.species.handle_mutant_bodyparts(src)
/mob/living/carbon/human/update_body(update_genitals = FALSE)
if(dna.species.should_render())
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
remove_overlay(BODY_LAYER)
dna.species.handle_body(src)
..()
@@ -69,11 +73,10 @@ There are several things that need to be remembered:
/mob/living/carbon/human/update_fire()
..((fire_stacks > 3) ? "Standing" : "Generic_mob_burning")
/* --------------------------------------- */
//For legacy support.
/mob/living/carbon/human/regenerate_icons()
if(dna.species.should_render())
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
if(!..())
icon_render_key = null //invalidate bodyparts cache
update_body(TRUE)
@@ -102,7 +105,7 @@ There are several things that need to be remembered:
//vvvvvv UPDATE_INV PROCS vvvvvv
/mob/living/carbon/human/update_inv_w_uniform()
if(dna.species.should_render())
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
remove_overlay(UNIFORM_LAYER)
if(client && hud_used)
@@ -154,7 +157,7 @@ There are several things that need to be remembered:
update_mutant_bodyparts()
/mob/living/carbon/human/update_inv_wear_id()
if(dna.species.should_render())
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
remove_overlay(ID_LAYER)
if(client && hud_used)
@@ -179,7 +182,7 @@ There are several things that need to be remembered:
/mob/living/carbon/human/update_inv_gloves()
if(dna.species.should_render())
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
remove_overlay(GLOVES_LAYER)
if(client && hud_used && hud_used.inv_slots[SLOT_GLOVES])
@@ -213,7 +216,7 @@ There are several things that need to be remembered:
/mob/living/carbon/human/update_inv_glasses()
if(dna.species.should_render())
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
remove_overlay(GLASSES_LAYER)
if(!get_bodypart(BODY_ZONE_HEAD)) //decapitated
@@ -240,7 +243,7 @@ There are several things that need to be remembered:
apply_overlay(GLASSES_LAYER)
/mob/living/carbon/human/update_inv_ears()
if(dna.species.should_render())
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
remove_overlay(EARS_LAYER)
if(!get_bodypart(BODY_ZONE_HEAD)) //decapitated
@@ -266,7 +269,7 @@ There are several things that need to be remembered:
apply_overlay(EARS_LAYER)
/mob/living/carbon/human/update_inv_shoes()
if(dna.species.should_render())
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
remove_overlay(SHOES_LAYER)
if(get_num_legs(FALSE) <2)
@@ -304,7 +307,7 @@ There are several things that need to be remembered:
apply_overlay(SHOES_LAYER)
/mob/living/carbon/human/update_inv_s_store()
if(dna.species.should_render())
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
remove_overlay(SUIT_STORE_LAYER)
if(client && hud_used)
@@ -328,7 +331,7 @@ There are several things that need to be remembered:
apply_overlay(SUIT_STORE_LAYER)
/mob/living/carbon/human/update_inv_head()
if(dna.species.should_render())
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
remove_overlay(HEAD_LAYER)
if(!get_bodypart(BODY_ZONE_HEAD)) //Decapitated
@@ -368,7 +371,7 @@ There are several things that need to be remembered:
update_mutant_bodyparts()
/mob/living/carbon/human/update_inv_belt()
if(dna.species.should_render())
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
remove_overlay(BELT_LAYER)
if(client && hud_used)
@@ -390,7 +393,7 @@ There are several things that need to be remembered:
apply_overlay(BELT_LAYER)
/mob/living/carbon/human/update_inv_wear_suit()
if(dna.species.should_render())
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
remove_overlay(SUIT_LAYER)
if(client && hud_used)
@@ -477,7 +480,7 @@ There are several things that need to be remembered:
/mob/living/carbon/human/update_inv_wear_mask()
if(dna.species.should_render())
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
remove_overlay(FACEMASK_LAYER)
if(!get_bodypart(BODY_ZONE_HEAD)) //Decapitated
@@ -518,7 +521,7 @@ There are several things that need to be remembered:
update_mutant_bodyparts() //e.g. upgate needed because mask now hides lizard snout
/mob/living/carbon/human/update_inv_back()
if(dna.species.should_render())
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
..()
var/mutable_appearance/back_overlay = overlays_standing[BACK_LAYER]
if(back_overlay)
@@ -669,6 +672,7 @@ use_mob_overlay_icon: if FALSE, it will always use the default_icon_file even if
//produces a key based on the human's limbs
/mob/living/carbon/human/generate_icon_render_key()
. = "[dna.species.mutant_bodyparts["limbs_id"]]"
. += "[dna.features["color_scheme"]]"
if(dna.check_mutation(HULK))
. += "-coloured-hulk"
@@ -708,6 +712,11 @@ use_mob_overlay_icon: if FALSE, it will always use the default_icon_file even if
. += "-[BP.dmg_overlay_type]"
if(BP.body_markings)
. += "-[BP.body_markings]"
if(length(BP.markings_color) && length(BP.markings_color[1]))
for(var/color in BP.markings_color[1])
. += "-[color]"
if(BP.icon)
. += "-[BP.icon]"
else
. += "-no_marking"
@@ -741,7 +750,7 @@ use_mob_overlay_icon: if FALSE, it will always use the default_icon_file even if
if(!dna.species)
return
if(dna.species.should_render())
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
return
var/obj/item/bodypart/HD = get_bodypart("head")
+20 -1
View File
@@ -14,10 +14,29 @@
return legcuffed
return null
/mob/living/carbon/proc/equip_in_one_of_slots(obj/item/I, list/slots, qdel_on_fail = 1)
/mob/living/carbon/proc/equip_in_one_of_slots(obj/item/I, list/slots, qdel_on_fail = 1, critical = FALSE)
for(var/slot in slots)
if(equip_to_slot_if_possible(I, slots[slot], qdel_on_fail = 0, disable_warning = TRUE))
return slot
if(critical) //it is CRITICAL they get this item, no matter what
//do they have a backpack?
var/obj/item/backpack = get_item_by_slot(SLOT_BACK)
if(!backpack)
//nothing on their back
backpack = new /obj/item/storage/backpack(get_turf(src))
if(equip_to_slot(backpack, SLOT_BACK)) //worst-case-scenario, something that shouldnt wear a backpack gets one
I.forceMove(backpack)
return SLOT_BACK
else if(istype(backpack) && SEND_SIGNAL(backpack, COMSIG_CONTAINS_STORAGE))
//place it in here, regardless of storage capacity
I.forceMove(backpack)
return SLOT_BACK
else
//this should NEVER happen, but if it does, report it with the appropriate information
var/conclusion = qdel_on_fail ? "deleted" : "not moved, staying at current position [I.x], [I.y], [I.z]"
message_admins("User [src] failed to get item of critical importance: [I]. Result: item is [conclusion]")
//it's not dropped at their turf as this is generally un-safe for midround antags and we don't know their status
if(qdel_on_fail)
qdel(I)
return null
+10 -2
View File
@@ -25,6 +25,9 @@
if(stat != DEAD)
handle_liver()
if(stat != DEAD)
handle_corruption()
/mob/living/carbon/PhysicalLife(seconds, times_fired)
if(!(. = ..()))
@@ -406,7 +409,7 @@
for(var/thing in all_wounds)
var/datum/wound/W = thing
if(W.processes) // meh
W.handle_process()
W.handle_process()
/mob/living/carbon/handle_mutations_and_radiation()
if(dna && dna.temporary_mutations.len)
@@ -438,7 +441,12 @@
radiation -= min(radiation, RAD_LOSS_PER_TICK)
if(radiation > RAD_MOB_SAFE)
adjustToxLoss(log(radiation-RAD_MOB_SAFE)*RAD_TOX_COEFFICIENT)
if(!HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM))
adjustToxLoss(log(radiation-RAD_MOB_SAFE)*RAD_TOX_COEFFICIENT)
else
var/rad_threshold = HAS_TRAIT(src, TRAIT_ROBOT_RADSHIELDING) ? RAD_UPGRADED_ROBOT_SAFE : RAD_DEFAULT_ROBOT_SAFE
if(radiation > rad_threshold)
adjustToxLoss(log(radiation-rad_threshold)*RAD_TOX_COEFFICIENT, toxins_type = TOX_SYSCORRUPT) //Robots are less resistant to rads, unless upgraded in which case they are fine at higher levels than organics.
/mob/living/carbon/handle_stomach()
set waitfor = 0
@@ -77,4 +77,4 @@
/mob/living/carbon/monkey/update_hud_back(obj/item/I)
if(client && hud_used && hud_used.hud_shown)
I.screen_loc = ui_monkey_back
client.screen += I
client.screen += I
+1 -1
View File
@@ -17,4 +17,4 @@
if(T)
return T.could_speak_language(language)
else
return initial(language.flags) & TONGUELESS_SPEECH
return initial(language.flags) & TONGUELESS_SPEECH
+29 -4
View File
@@ -168,20 +168,45 @@
updatehealth()
return amount
/mob/living/proc/getToxLoss()
return toxloss
//By default, returns toxins damage no matter what kind of tox damage the target is using.
/mob/living/proc/getToxLoss(toxins_type = TOX_OMNI)
if(toxins_type == TOX_OMNI)
return toxloss
/mob/living/proc/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE)
var/affected_by = TOX_DEFAULT
if(HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM))
affected_by = TOX_SYSCORRUPT
if(toxins_type != affected_by)
return 0
else
return toxloss
/mob/living/proc/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE, toxins_type = TOX_DEFAULT)
if(!forced && (status_flags & GODMODE))
return FALSE
var/affected_by = TOX_DEFAULT
if(HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM))
affected_by = TOX_SYSCORRUPT
if(toxins_type != TOX_OMNI && toxins_type != affected_by)
return FALSE
toxloss = clamp((toxloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
if(updating_health)
updatehealth()
return amount
/mob/living/proc/setToxLoss(amount, updating_health = TRUE, forced = FALSE)
//Defaults to omni here because setToxLoss is used by very few things that usually want to set all types
/mob/living/proc/setToxLoss(amount, updating_health = TRUE, forced = FALSE, toxins_type = TOX_OMNI)
if(!forced && (status_flags & GODMODE))
return FALSE
var/affected_by = TOX_DEFAULT
if(HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM))
affected_by = TOX_SYSCORRUPT
if(toxins_type != TOX_OMNI && toxins_type != affected_by)
return FALSE
toxloss = amount
if(updating_health)
updatehealth()
+5
View File
@@ -66,6 +66,10 @@
GLOB.alive_mob_list -= src
if(!gibbed)
GLOB.dead_mob_list += src
if(ckey)
var/datum/preferences/P = GLOB.preferences_datums[ckey]
if(P)
P.respawn_time_of_death = world.time
set_drugginess(0)
set_disgust(0)
SetSleeping(0, 0)
@@ -78,6 +82,7 @@
update_mobility()
med_hud_set_health()
med_hud_set_status()
clear_typing_indicator()
if(!gibbed && !QDELETED(src))
addtimer(CALLBACK(src, .proc/med_hud_set_status), (DEFIB_TIME_LIMIT * 10) + 1)
stop_pulling()
+2 -13
View File
@@ -443,6 +443,7 @@
key = "me"
key_third_person = "custom"
message = null
emote_type = EMOTE_BOTH
/datum/emote/living/custom/proc/check_invalid(mob/user, input)
if(stop_bad_mime.Find(input, 1, 1))
@@ -462,24 +463,12 @@
else if(!params)
var/custom_emote = stripped_multiline_input_or_reflect(user, "Choose an emote to display.", "Custom Emote", null, MAX_MESSAGE_LEN)
if(custom_emote && !check_invalid(user, custom_emote))
var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable")
switch(type)
if("Visible")
emote_type = EMOTE_VISIBLE
if("Hearable")
emote_type = EMOTE_AUDIBLE
else
alert("Unable to use this emote, must be either hearable or visible.")
return
message = custom_emote
else
message = params
if(type_override)
emote_type = type_override
message = user.say_emphasis(message)
. = ..()
message = null
emote_type = EMOTE_VISIBLE
/datum/emote/living/custom/replace_pronoun(mob/user, message)
return message
@@ -520,7 +509,7 @@
message = "beeps."
message_param = "beeps at %t."
sound = 'sound/machines/twobeep.ogg'
mob_type_allowed_typecache = list(/mob/living/brain, /mob/living/silicon, /mob/living/carbon/human)
mob_type_allowed_typecache = list(/mob/living/brain, /mob/living/silicon, /mob/living/carbon/human, /mob/camera/aiEye)
/datum/emote/living/circle
key = "circle"
+1 -1
View File
@@ -3,7 +3,7 @@
* Splits off into PhysicalLife() and BiologicalLife(). Override those instead of this.
*/
/mob/living/proc/Life(seconds, times_fired)
SHOULD_NOT_SLEEP(TRUE)
//SHOULD_NOT_SLEEP(TRUE)
if(mob_transforming)
return
+19 -3
View File
@@ -34,6 +34,7 @@
ranged_ability.remove_ranged_ability(src)
if(buckled)
buckled.unbuckle_mob(src,force=1)
QDEL_LIST_ASSOC_VAL(ability_actions)
remove_from_all_data_huds()
GLOB.mob_living_list -= src
@@ -258,6 +259,16 @@
AM.setDir(current_dir)
now_pushing = FALSE
// i wish to have a "friendly chat" with whoever made three tail variables instead of one
/mob/proc/has_tail()
return FALSE
/mob/living/carbon/human/has_tail()
if(!dna || !dna.species)
return ..()
var/list/L = dna.species.mutant_bodyparts // caches list because i refuse to type it out and because performance
return (L["mam_tail"] && (L["mam_tail"] != "None")) || (L["tail_human"] && (L["tail_human"] != "None")) || (L["tail_lizard"] && (L["tail_lizard"] != "None"))
/mob/living/start_pulling(atom/movable/AM, state, force = pull_force, supress_message = FALSE)
if(!AM || !src)
return FALSE
@@ -296,9 +307,14 @@
log_combat(src, M, "grabbed", addition="passive grab")
if(!supress_message && !(iscarbon(AM) && HAS_TRAIT(src, TRAIT_STRONG_GRABBER)))
visible_message("<span class='warning'>[src] has grabbed [M][(zone_selected == "l_arm" || zone_selected == "r_arm")? " by [M.p_their()] hands":" passively"]!</span>",
"<span class='warning'>You have grabbed [M][(zone_selected == "l_arm" || zone_selected == "r_arm")? " by [M.p_their()] hands":" passively"]!</span>", target = M,
target_message = "<span class='warning'>[src] has grabbed you[(zone_selected == "l_arm" || zone_selected == "r_arm")? " by your hands":" passively"]!</span>")
if((zone_selected == BODY_ZONE_PRECISE_GROIN) && has_tail() && M.has_tail())
visible_message("<span class='warning'>[src] coils [p_their()] tail with [M]'s, pulling [M.p_them()] along!</span>", "You entwine tails with [M], pulling [M.p_them()] along!", ignored_mobs = M)
M.show_message("<span class='warning'>[src] has entwined [p_their()] tail with yours, pulling you along!</span>", MSG_VISUAL, "<span class='warning'>You feel <b>something</b> coiling around your tail, pulling you along!</span>")
else
visible_message("<span class='warning'>[src] has grabbed [M][(zone_selected == "l_arm" || zone_selected == "r_arm")? " by [M.p_their()] hands":" passively"]!</span>",
"<span class='warning'>You have grabbed [M][(zone_selected == "l_arm" || zone_selected == "r_arm")? " by [M.p_their()] hands":" passively"]!</span>", target = M,
target_message = "<span class='warning'>[src] has grabbed you[(zone_selected == "l_arm" || zone_selected == "r_arm")? " by your hands":" passively"]!</span>")
if(!iscarbon(src))
M.LAssailant = null
else
@@ -127,7 +127,7 @@
handle_parry_ending_effects(data, effect_text)
parrying = NOT_PARRYING
parry_start_time = 0
parry_end_time_last = world.time
parry_end_time_last = world.time + (successful? 0 : data.parry_failed_cooldown_duration)
successful_parries = null
/**
@@ -154,6 +154,8 @@ GLOBAL_LIST_EMPTY(block_parry_data)
var/parry_failed_stagger_duration = 3.5 SECONDS
/// Clickdelay duration post-parry if you fail to parry an attack
var/parry_failed_clickcd_duration = 2 SECONDS
/// Parry cooldown post-parry if failed. This is ADDED to parry_cooldown!!!
var/parry_failed_cooldown_duration = 0 SECONDS
/**
* Quirky proc to get average of flags in list that are in attack_type because why is attack_type a flag.
+2 -2
View File
@@ -522,8 +522,8 @@
//called when the mob receives a bright flash
/mob/living/proc/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash)
if(get_eye_protection() < intensity && (override_blindness_check || !(HAS_TRAIT(src, TRAIT_BLIND))))
/mob/living/proc/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash, override_protection = 0)
if((override_protection || get_eye_protection() < intensity) && (override_blindness_check || !(HAS_TRAIT(src, TRAIT_BLIND))))
overlay_fullscreen("flash", type)
addtimer(CALLBACK(src, .proc/clear_fullscreen, "flash", 25), 25)
return TRUE
@@ -32,6 +32,10 @@
// Combat - Blocking/Parrying system
/// Our block_parry_data for unarmed blocks/parries. Currently only used for parrying, as unarmed block isn't implemented yet. YOU MUST RUN [get_block_parry_data(this)] INSTEAD OF DIRECTLY ACCESSING!
var/datum/block_parry_data/block_parry_data = /datum/block_parry_data // defaults to *something* because [combat_flags] dictates whether or not we can unarmed block/parry.
/// Default
var/datum/block_parry_data/default_block_parry_data = /datum/block_parry_data
/// If we're a pugilist
var/datum/block_parry_data/pugilist_block_parry_data = /datum/block_parry_data/unarmed/pugilist
// Blocking
/// The item the user is actively blocking with if any.
var/obj/item/active_block_item
+1 -9
View File
@@ -1,11 +1,3 @@
/// IN THE FUTURE, WE WILL PROBABLY REFACTOR TO LESSEN THE NEED FOR UPDATE_MOBILITY, BUT FOR NOW.. WE CAN START DOING THIS.
/// FOR BLOCKING MOVEMENT, USE TRAIT_MOBILITY_NOMOVE AS MUCH AS POSSIBLE. IT WILL MAKE REFACTORS IN THE FUTURE EASIER.
/mob/living/ComponentInitialize()
. = ..()
RegisterSignal(src, SIGNAL_TRAIT(TRAIT_MOBILITY_NOMOVE), .proc/update_mobility)
RegisterSignal(src, SIGNAL_TRAIT(TRAIT_MOBILITY_NOPICKUP), .proc/update_mobility)
RegisterSignal(src, SIGNAL_TRAIT(TRAIT_MOBILITY_NOUSE), .proc/update_mobility)
RegisterSignal(src, SIGNAL_TRAIT(TRAIT_MOBILITY_NOREST), .proc/update_mobility)
//Stuff like mobility flag updates, resting updates, etc.
@@ -148,7 +140,7 @@
L.update_pull_movespeed()
//Handle lying down, voluntary or involuntary
density = !lying
update_density()
if(lying)
set_resting(TRUE, TRUE, FALSE)
if(layer == initial(layer)) //to avoid special cases like hiding larvas.
+3 -2
View File
@@ -1,8 +1,6 @@
/mob/living/Moved()
. = ..()
update_turf_movespeed(loc)
//Hide typing indicator if we move.
clear_typing_indicator()
update_pixel_shifting(TRUE)
/mob/living/setDir(newdir, ismousemovement)
@@ -19,6 +17,9 @@
pixel_x = get_standard_pixel_x_offset(lying)
pixel_y = get_standard_pixel_y_offset(lying)
/mob/living/proc/update_density()
density = !lying && !HAS_TRAIT(src, TRAIT_LIVING_NO_DENSITY)
/mob/living/CanPass(atom/movable/mover, turf/target)
if((mover.pass_flags & PASSMOB))
return TRUE
+20
View File
@@ -0,0 +1,20 @@
/// IN THE FUTURE, WE WILL PROBABLY REFACTOR TO LESSEN THE NEED FOR UPDATE_MOBILITY, BUT FOR NOW.. WE CAN START DOING THIS.
/// FOR BLOCKING MOVEMENT, USE TRAIT_MOBILITY_NOMOVE AS MUCH AS POSSIBLE. IT WILL MAKE REFACTORS IN THE FUTURE EASIER.
/mob/living/ComponentInitialize()
. = ..()
RegisterSignal(src, SIGNAL_TRAIT(TRAIT_MOBILITY_NOMOVE), .proc/update_mobility)
RegisterSignal(src, SIGNAL_TRAIT(TRAIT_MOBILITY_NOPICKUP), .proc/update_mobility)
RegisterSignal(src, SIGNAL_TRAIT(TRAIT_MOBILITY_NOUSE), .proc/update_mobility)
RegisterSignal(src, SIGNAL_TRAIT(TRAIT_MOBILITY_NOREST), .proc/update_mobility)
RegisterSignal(src, SIGNAL_TRAIT(TRAIT_LIVING_NO_DENSITY), .proc/update_density)
RegisterSignal(src, SIGNAL_TRAIT(TRAIT_PUGILIST), .proc/update_pugilism)
/mob/living/proc/update_pugilism()
if(HAS_TRAIT(src, TRAIT_PUGILIST))
combat_flags |= COMBAT_FLAG_UNARMED_PARRY
block_parry_data = pugilist_block_parry_data
else
var/initial_combat_flags = initial(combat_flags)
if(!(initial_combat_flags & COMBAT_FLAG_UNARMED_PARRY))
combat_flags &= ~COMBAT_FLAG_UNARMED_PARRY
block_parry_data = default_block_parry_data
+1 -1
View File
@@ -2,4 +2,4 @@
update_z(null)
..()
if(!key && mind) //key and mind have become separated.
mind.active = 0 //This is to stop say, a mind.transfer_to call on a corpse causing a ghost to re-enter its body.
mind.active = 0 //This is to stop say, a mind.transfer_to call on a corpse causing a ghost to re-enter its body.
+7
View File
@@ -86,6 +86,7 @@
var/mob/living/silicon/robot/deployed_shell = null //For shell control
var/datum/action/innate/deploy_shell/deploy_action = new
var/datum/action/innate/deploy_last_shell/redeploy_action = new
var/datum/action/innate/custom_holoform/custom_holoform = new
var/chnotify = 0
@@ -152,6 +153,7 @@
aicamera = new/obj/item/camera/siliconcam/ai_camera(src)
deploy_action.Grant(src)
custom_holoform.Grant(src)
if(isturf(loc))
add_verb(src, list(/mob/living/silicon/ai/proc/ai_network_change, \
@@ -1032,3 +1034,8 @@
qdel(src)
else
return
/mob/living/silicon/ai/emote(act, m_type=1, message = null, intentional = FALSE)
if(current && eyeobj)
return eyeobj.emote(act, m_type, message, intentional, forced = TRUE)
return ..()
@@ -19,4 +19,4 @@
. += "[src]Core.exe has stopped responding! NTOS is searching for a solution to the problem..."
. += "*---------*</span>"
. += ..()
. += ..()
@@ -204,3 +204,7 @@
alpha = 100
layer = ABOVE_ALL_MOB_LAYER
plane = GAME_PLANE
/mob/camera/aiEye/emote(act, m_type=1, message = null, intentional = FALSE, forced = FALSE)
if(ai?.current)
..()
@@ -48,4 +48,4 @@
eye.dm = Everything about the AI and the AIEye.
updating.dm = Everything about triggers that will update chunks.
*/
*/
@@ -1606,4 +1606,4 @@ GLOBAL_LIST_INIT(vox_sounds_male, list("," = 'sound/vox/_comma.ogg',
"zero" = 'sound/vox/zero.ogg',
"zone" = 'sound/vox/zone.ogg',
"zulu" = 'sound/vox/zulu.ogg',))
#endif
#endif
@@ -1,28 +1,12 @@
/mob/living/silicon/verb/clear_custom_holoform()
set name = "Clear Custom Holoform"
set desc = "Clear your current custom holoform"
set category = "OOC"
/mob/living/silicon/proc/attempt_set_custom_holoform()
if(!client.prefs)
to_chat(src, "<span class='boldwarning'>No preferences datum on your client, contact an admin/coder!</span>")
return
client.prefs.custom_holoform_icon = null
client.prefs.cached_holoform_icons = null
to_chat(src, "<span class='boldnotice'>Holoform removed.</span>")
/mob/living/silicon/verb/set_custom_holoform()
set name = "Set Custom Holoform"
set desc = "Set your custom holoform using your current preferences slot and a specified set of gear."
set category = "OOC"
if(!client.prefs)
to_chat(src, "<span class='boldwarning'>No preferences datum on your client, contact an admin/coder!</span>")
return
if(client.prefs.last_custom_holoform > world.time - CUSTOM_HOLOFORM_DELAY)
to_chat(src, "<span class='warning'>You are attempting to change custom holoforms too fast!</span>")
var/icon/new_holoform = user_interface_custom_holoform(client)
client.prefs.last_custom_holoform = world.time
if(new_holoform)
client.prefs.custom_holoform_icon = new_holoform
client.prefs.cached_holoform_icons = null
client.prefs.last_custom_holoform = world.time
to_chat(src, "<span class='boldnotice'>Holoform set.</span>")
return TRUE
return FALSE
@@ -18,10 +18,10 @@
/mob/living/silicon/apply_effect(effect = 0,effecttype = EFFECT_STUN, blocked = FALSE)
return FALSE //The only effect that can hit them atm is flashes and they still directly edit so this works for now
/mob/living/silicon/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE) //immune to tox damage
/mob/living/silicon/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE, toxins_type = TOX_DEFAULT) //immune to tox damage
return FALSE
/mob/living/silicon/setToxLoss(amount, updating_health = TRUE, forced = FALSE)
/mob/living/silicon/setToxLoss(amount, updating_health = TRUE, forced = FALSE, toxins_type = TOX_OMNI)
return FALSE
/mob/living/silicon/adjustCloneLoss(amount, updating_health = TRUE, forced = FALSE) //immune to clone damage
+1 -1
View File
@@ -10,4 +10,4 @@
diag_hud_set_status()
diag_hud_set_health()
update_health_hud()
. = ..()
. = ..()
+1 -1
View File
@@ -3,4 +3,4 @@
if(laws && isobserver(user))
. += "<b>[src] has the following laws:</b>"
for(var/law in laws.get_law_list(include_zeroth = TRUE))
. += law
. += law
@@ -131,6 +131,7 @@
var/datum/action/innate/pai/chassis/AC = new /datum/action/innate/pai/chassis
var/datum/action/innate/pai/rest/AR = new /datum/action/innate/pai/rest
var/datum/action/innate/pai/light/AL = new /datum/action/innate/pai/light
var/datum/action/innate/custom_holoform/custom_holoform = new /datum/action/innate/custom_holoform
var/datum/action/language_menu/ALM = new
SW.Grant(src)
@@ -139,6 +140,7 @@
AR.Grant(src)
AL.Grant(src)
ALM.Grant(src)
custom_holoform.Grant(src)
emitter_next_use = world.time + 10 SECONDS
/mob/living/silicon/pai/ComponentInitialize()
@@ -87,7 +87,7 @@
/mob/living/silicon/pai/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE)
return take_holo_damage(amount)
/mob/living/silicon/pai/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE)
/mob/living/silicon/pai/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE, toxins_type = TOX_DEFAULT)
return FALSE
/mob/living/silicon/pai/adjustOxyLoss(amount, updating_health = TRUE, forced = FALSE)
@@ -111,7 +111,7 @@
/mob/living/silicon/pai/getFireLoss()
return emittermaxhealth - emitterhealth
/mob/living/silicon/pai/getToxLoss()
/mob/living/silicon/pai/getToxLoss(toxins_type = TOX_OMNI)
return FALSE
/mob/living/silicon/pai/getOxyLoss()
@@ -129,7 +129,7 @@
/mob/living/silicon/pai/setStaminaLoss()
return FALSE
/mob/living/silicon/pai/setToxLoss()
/mob/living/silicon/pai/setToxLoss(toxins_type = TOX_OMNI)
return FALSE
/mob/living/silicon/pai/setOxyLoss()
@@ -1,9 +1,9 @@
/datum/emote/silicon
mob_type_allowed_typecache = list(/mob/living/silicon)
mob_type_allowed_typecache = list(/mob/living/silicon, /mob/camera/aiEye)
emote_type = EMOTE_AUDIBLE
/datum/emote/sound/silicon
mob_type_allowed_typecache = list(/mob/living/silicon, /mob/living/carbon/human)
mob_type_allowed_typecache = list(/mob/living/silicon, /mob/living/carbon/human, /mob/camera/aiEye)
emote_type = EMOTE_AUDIBLE
var/unrestricted = TRUE
@@ -1022,6 +1022,32 @@
R.undeploy()
return TRUE
/datum/action/innate/custom_holoform
name = "Select Custom Holoform"
desc = "Select one of your existing avatars to use as a holoform."
icon_icon = 'icons/mob/actions/actions_silicon.dmi'
button_icon_state = "custom_holoform"
required_mobility_flags = NONE
/datum/action/innate/custom_holoform/Trigger()
if(!..())
return FALSE
var/mob/living/silicon/S = owner
//if setting the holoform succeeds, attempt to set it as the current holoform for the pAI or AI
if(S.attempt_set_custom_holoform())
if(istype(S, /mob/living/silicon/pai))
var/mob/living/silicon/pai/P = S
P.chassis = "custom"
else if(istype(S, /mob/living/silicon/ai))
var/mob/living/silicon/ai/A = S
if(A.client?.prefs?.custom_holoform_icon)
A.holo_icon = A.client.prefs.get_filtered_holoform(HOLOFORM_FILTER_AI)
else
A.holo_icon = getHologramIcon(icon('icons/mob/ai.dmi', "female"))
return TRUE
/mob/living/silicon/robot/proc/undeploy()
@@ -1043,6 +1069,8 @@
mainframe.laws.show_laws(mainframe) //Always remind the AI when switching
mainframe = null
/mob/living/silicon/robot/attack_ai(mob/user)
if(shell && (!connected_ai || connected_ai == user))
var/mob/living/silicon/ai/AI = user
@@ -122,4 +122,4 @@
var/laser
var/sleeper_g
var/sleeper_r
var/sleeper_nv
var/sleeper_nv
@@ -206,7 +206,7 @@
icon_state = "toolbox_tiles"
throwforce = 10
created_name = "Floorbot"
var/toolbox = /obj/item/storage/toolbox/mechanical
var/toolbox = /obj/item/storage/toolbox
/obj/item/bot_assembly/floorbot/Initialize()
. = ..()
@@ -225,7 +225,7 @@
name = "incomplete floorbot assembly"
icon_state = "toolbox_tiles_sensor"
/obj/item/storage/toolbox/mechanical/attackby(obj/item/stack/tile/plasteel/T, mob/user, params)
/obj/item/storage/toolbox/attackby(obj/item/stack/tile/plasteel/T, mob/user, params)
if(!istype(T, /obj/item/stack/tile/plasteel))
..()
return
@@ -574,17 +574,20 @@
if(!C.reagents.has_reagent(R.type))
return TRUE
var/list/brute_damaged_bodyparts = C.get_damaged_bodyparts(TRUE, FALSE, status = list(BODYPART_ORGANIC))
var/list/burn_damaged_bodyparts = C.get_damaged_bodyparts(FALSE, TRUE, status = list(BODYPART_ORGANIC))
//They're injured enough for it!
if((!C.reagents.has_reagent(treatment_brute_avoid)) && (C.getBruteLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_brute)))
if(brute_damaged_bodyparts.len && (!C.reagents.has_reagent(treatment_brute_avoid)) && (C.getBruteLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_brute)))
return TRUE //If they're already medicated don't bother!
if((!C.reagents.has_reagent(treatment_oxy_avoid)) && (C.getOxyLoss() >= (15 + heal_threshold)) && (!C.reagents.has_reagent(treatment_oxy)))
return TRUE
if((!C.reagents.has_reagent(treatment_fire_avoid)) && (C.getFireLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_fire)))
if(burn_damaged_bodyparts.len && (!C.reagents.has_reagent(treatment_fire_avoid)) && (C.getFireLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_fire)))
return TRUE
var/treatment_toxavoid = get_avoidchem_toxin(C)
if(((isnull(treatment_toxavoid) || !C.reagents.has_reagent(treatment_toxavoid))) && (C.getToxLoss() >= heal_threshold) && (!C.reagents.has_reagent(get_healchem_toxin(C))))
if(!HAS_TRAIT(C, TRAIT_ROBOTIC_ORGANISM) && ((isnull(treatment_toxavoid) || !C.reagents.has_reagent(treatment_toxavoid))) && (C.getToxLoss() >= heal_threshold) && (!C.reagents.has_reagent(get_healchem_toxin(C))))
return TRUE
if(treat_virus && !C.reagents.has_reagent(treatment_virus_avoid) && !C.reagents.has_reagent(treatment_virus))
@@ -44,6 +44,7 @@
var/can_repair_constructs = FALSE
var/can_repair_self = FALSE
var/runetype
var/datum/mind/original_mind
/mob/living/simple_animal/hostile/construct/Initialize()
. = ..()
@@ -66,6 +67,15 @@
CR.button.screen_loc = "6:[pos],4:-2"
CR.button.moved = "6:[pos],4:-2"
/mob/living/simple_animal/hostile/construct/Destroy()
original_mind = null
. = ..()
/mob/living/simple_animal/hostile/construct/death()
if(original_mind && !(QDELETED(original_mind)))
transfer_ckey(original_mind.current)
..()
/mob/living/simple_animal/hostile/construct/Login()
..()
to_chat(src, playstyle_string)
@@ -107,7 +117,7 @@
return
/mob/living/simple_animal/hostile/construct/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE)
return 0
return FALSE
/mob/living/simple_animal/hostile/construct/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
. = ..()
@@ -25,7 +25,7 @@
else if(damage_coeff[OXY])
. = adjustHealth(amount * damage_coeff[OXY] * CONFIG_GET(number/damage_multiplier), updating_health, forced)
/mob/living/simple_animal/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE)
/mob/living/simple_animal/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE, toxins_type = TOX_DEFAULT)
if(forced)
. = adjustHealth(amount * CONFIG_GET(number/damage_multiplier), updating_health, forced)
else if(damage_coeff[TOX])
@@ -70,4 +70,4 @@
/mob/living/simple_animal/hostile/guardian/gravitokinetic/proc/__distance_check(atom/movable/AM, OldLoc, Dir, Forced)
if(get_dist(src, AM) > gravity_power_range)
remove_gravity(AM)
remove_gravity(AM)
@@ -130,4 +130,4 @@
/mob/living/simple_animal/hostile/guardian/ranged/Recall(forced)
// To stop scout mode from moving when recalled
incorporeal_move = FALSE
. = ..()
. = ..()
@@ -292,4 +292,4 @@
if(mecha)
walk_to(mecha, target, minimum_distance, mecha.step_in)
else
..()
..()
@@ -87,7 +87,7 @@ Difficulty: Medium
return FALSE
return ..()
/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, mob/target, target_message)
/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, mob/target, target_message, omni = FALSE)
if(swooping & SWOOP_INVULNERABLE) //to suppress attack messages without overriding every single proc that could send a message saying we got hit
return
return ..()
@@ -200,7 +200,7 @@ SHITCODE AHEAD. BE ADVISED. Also comment extravaganza
loot = list(/obj/item/staff/storm)
elimination = FALSE
else if(prob(20)) //20% chance for sick lootz.
loot = list(/obj/structure/closet/crate/necropolis/tendril)
loot = list(/obj/structure/closet/crate/necropolis/tendril/all)
if(!true_spawn)
loot = null
return ..()
@@ -263,6 +263,7 @@ SHITCODE AHEAD. BE ADVISED. Also comment extravaganza
/obj/item/staff/storm
name = "staff of storms"
desc = "An ancient staff retrieved from the remains of Legion. The wind stirs as you move it."
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
icon_state = "staffofstorms"
item_state = "staffofstorms"
icon = 'icons/obj/guns/magic.dmi'
@@ -190,4 +190,4 @@
/obj/item/clothing/accessory/pandora_hope/on_uniform_dropped(obj/item/clothing/under/U, user)
var/mob/living/L = user
if(L && L.mind)
SEND_SIGNAL(L, COMSIG_CLEAR_MOOD_EVENT, "hope_lavaland")
SEND_SIGNAL(L, COMSIG_CLEAR_MOOD_EVENT, "hope_lavaland")
@@ -57,4 +57,4 @@
casingtype = /obj/item/ammo_casing/c46x30mm
projectilesound = 'sound/weapons/gunshot_smg.ogg'
loot = list(/obj/item/gun/ballistic/automatic/wt550,
/obj/effect/mob_spawn/human/corpse/nanotrasensoldier)
/obj/effect/mob_spawn/human/corpse/nanotrasensoldier)
@@ -81,4 +81,4 @@
casingtype = /obj/item/ammo_casing/c46x30mm
projectilesound = 'sound/weapons/gunshot_smg.ogg'
loot = list(/obj/item/gun/ballistic/automatic/wt550,
/obj/effect/mob_spawn/human/corpse/nanotrasensoldier)
/obj/effect/mob_spawn/human/corpse/nanotrasensoldier)
+8 -28
View File
@@ -1,53 +1,33 @@
/mob/living/simple_animal/shade
/mob/living/simple_animal/hostile/construct/shade
name = "Shade"
real_name = "Shade"
desc = "A bound spirit."
gender = PLURAL
icon = 'icons/mob/mob.dmi'
icon_state = "shade"
icon_living = "shade"
mob_biotypes = MOB_SPIRIT
maxHealth = 40
health = 40
spacewalk = TRUE
healable = 0
speak_emote = list("hisses")
emote_hear = list("wails.","screeches.")
response_help_continuous = "puts their hand through"
response_help_simple = "put your hand through"
response_disarm_continuous = "flails at"
response_disarm_simple = "flail at"
response_harm_continuous = "punches"
response_harm_simple = "punch"
speak_chance = 1
melee_damage_lower = 5
melee_damage_upper = 12
attack_verb_continuous = "metaphysically strikes"
attack_verb_simple = "metaphysically strike"
minbodytemp = 0
maxbodytemp = INFINITY
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
stop_automated_movement = 1
status_flags = 0
faction = list("cult")
status_flags = CANPUSH
movement_type = FLYING
speed = -1 //they don't have to lug a body made of runed metal around
loot = list(/obj/item/ectoplasm)
del_on_death = TRUE
initial_language_holder = /datum/language_holder/construct
blood_volume = 0
has_field_of_vision = FALSE //we are a spoopy ghost
playstyle_string = "<span class='big bold'>You are a shade!</span><b> Your job is to survive until you are granted a shell, and help out cultists with casting runes!</b>"
/mob/living/simple_animal/shade/death()
/mob/living/simple_animal/hostile/construct/shade/death()
deathmessage = "lets out a contented sigh as [p_their()] form unwinds."
..()
/mob/living/simple_animal/shade/canSuicide()
/mob/living/simple_animal/hostile/construct/shade/canSuicide()
if(istype(loc, /obj/item/soulstone)) //do not suicide inside the soulstone
return 0
return FALSE
return ..()
/mob/living/simple_animal/shade/attack_animal(mob/living/simple_animal/M)
/mob/living/simple_animal/hostile/construct/shade/attack_animal(mob/living/simple_animal/M)
if(isconstruct(M))
var/mob/living/simple_animal/hostile/construct/C = M
if(!C.can_repair_constructs)
@@ -62,7 +42,7 @@
else if(src != M)
return ..()
/mob/living/simple_animal/shade/attackby(obj/item/O, mob/user, params) //Marker -Agouri
/mob/living/simple_animal/hostile/construct/shade/attackby(obj/item/O, mob/user, params) //Marker -Agouri
if(istype(O, /obj/item/soulstone))
var/obj/item/soulstone/SS = O
SS.transfer_soul("SHADE", src, user)
@@ -53,4 +53,4 @@
/datum/emote/slime/mood/angry
key = "moodangry"
mood = "angry"
mood = "angry"
@@ -76,4 +76,4 @@
slime_mutation[2] = colour
slime_mutation[3] = colour
slime_mutation[4] = colour
return(slime_mutation)
return(slime_mutation)
+2 -9
View File
@@ -59,15 +59,8 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, typecacheof(list(
if(!client)
return
if(iscarbon(src) && ventcrawler < 2)//It must have atleast been 1 to get this far
var/failed = 0
var/list/items_list = get_equipped_items(include_pockets = TRUE)
if(items_list.len)
failed = 1
for(var/obj/item/I in held_items)
failed = 1
break
if(failed)
if(iscarbon(src) && ventcrawler == VENTCRAWLER_NUDE)
if(length(get_equipped_items(include_pockets = TRUE)) || get_num_held_items())
to_chat(src, "<span class='warning'>You can't crawl around in the ventilation ducts with items!</span>")
return