Merge remote-tracking branch 'upstream/master' into slime-legs
This commit is contained in:
@@ -17,4 +17,4 @@
|
||||
if(loc)
|
||||
if(istype(loc, /obj/item/organ/brain))
|
||||
qdel(loc)//Gets rid of the brain item
|
||||
..()
|
||||
..()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
diag_hud_set_status()
|
||||
diag_hud_set_health()
|
||||
update_health_hud()
|
||||
. = ..()
|
||||
. = ..()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user