Merge branch 'master' into typing_indicators

This commit is contained in:
kevinz000
2020-05-07 09:04:44 -07:00
committed by GitHub
540 changed files with 286326 additions and 10262 deletions
@@ -392,6 +392,8 @@
character.update_parallax_teleport()
job.standard_assign_skills(character.mind)
SSticker.minds += character.mind
var/mob/living/carbon/human/humanc
@@ -23,11 +23,7 @@
if(!pref_species)
var/rando_race = pick(GLOB.roundstart_races)
pref_species = new rando_race()
features = random_features(pref_species?.id)
if(gender == MALE || gender != FEMALE)
features["body_model"] = gender
else if(gender == PLURAL)
features["body_model"] = pick(MALE,FEMALE)
features = random_features(pref_species?.id, gender)
age = rand(AGE_MIN,AGE_MAX)
/datum/preferences/proc/update_preview_icon(equip_job = TRUE)
@@ -16,6 +16,7 @@
from doing this unless you absolutely know what you are doing, and have defined a
conversion in savefile.dm
*/
/proc/init_sprite_accessory_subtypes(prototype, list/L, list/male, list/female, roundstart = FALSE, skip_prototype = TRUE)//Roundstart argument builds a specific list for roundstart parts where some parts may be locked
if(!istype(L))
L = list()
@@ -55,19 +56,19 @@
var/gender = NEUTER //Determines if the accessory will be skipped or included in random hair generations
var/gender_specific //Something that can be worn by either gender, but looks different on each
var/color_src = MUTCOLORS //Currently only used by mutantparts so don't worry about hair and stuff. This is the source that this accessory will get its color from. Default is MUTCOLOR, but can also be HAIR, FACEHAIR, EYECOLOR and 0 if none.
var/hasinner //Decides if this sprite has an "inner" part, such as the fleshy parts on ears.
var/locked = FALSE //Is this part locked from roundstart selection? Used for parts that apply effects
var/dimension_x = 32
var/dimension_y = 32
var/center = FALSE //Should we center the sprite?
var/list/relevant_layers //list of layers that this accessory uses. As of now only used in species.handle_mutant_bodyparts(), but that's where most sprite accessories are anyway.
var/mutant_part_string //Also used in species.handle_mutant_bodyparts() to generate the overlay icon state.
var/alpha_mask_state
//Special / holdover traits for Citadel specific sprites.
var/extra = FALSE
var/extra_color_src = MUTCOLORS2 //The color source for the extra overlay.
var/extra_icon = 'modular_citadel/icons/mob/mam_tails.dmi'
var/extra2 = FALSE
var/extra2_color_src = MUTCOLORS3
var/extra2_icon = 'modular_citadel/icons/mob/mam_tails.dmi'
//for snowflake/donor specific sprites
var/list/ckeys_allowed
@@ -4,6 +4,8 @@
*******************************************/
/datum/sprite_accessory/xeno_dorsal
icon = 'modular_citadel/icons/mob/xeno_parts_greyscale.dmi'
mutant_part_string = "xenodorsal"
relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
/datum/sprite_accessory/xeno_dorsal/standard
name = "Standard"
@@ -22,9 +24,12 @@
*******************************************/
/datum/sprite_accessory/xeno_tail
icon = 'modular_citadel/icons/mob/xeno_parts_greyscale.dmi'
mutant_part_string = "tail"
relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
/datum/sprite_accessory/xeno_tail/none
name = "None"
relevant_layers = null
/datum/sprite_accessory/xeno_tail/standard
name = "Xenomorph Tail"
@@ -35,6 +40,8 @@
*******************************************/
/datum/sprite_accessory/xeno_head
icon = 'modular_citadel/icons/mob/xeno_parts_greyscale.dmi'
mutant_part_string = "xhead"
relevant_layers = list(BODY_ADJ_LAYER)
/datum/sprite_accessory/xeno_head/standard
name = "Standard"
@@ -4,10 +4,12 @@
/datum/sprite_accessory/body_markings
icon = 'icons/mob/mutant_bodyparts.dmi'
relevant_layers = list(BODY_ADJ_LAYER)
/datum/sprite_accessory/body_markings/none
name = "None"
icon_state = "none"
relevant_layers = null
/datum/sprite_accessory/body_markings/dtiger
name = "Dark Tiger Body"
@@ -45,6 +47,7 @@
icon_state = "none"
ckeys_allowed = list("yousshouldnteverbeseeingthisyoumeme")
icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
relevant_layers = null
/datum/sprite_accessory/mam_body_markings/plain
name = "Plain"
@@ -219,10 +222,12 @@
/datum/sprite_accessory/insect_fluff
icon = 'icons/mob/wings.dmi'
color_src = 0
relevant_layers = list(BODY_FRONT_LAYER)
/datum/sprite_accessory/insect_fluff/none
name = "None"
icon_state = "none"
relevant_layers = null
/datum/sprite_accessory/insect_fluff/plain
name = "Plain"
@@ -1,7 +1,8 @@
datum/sprite_accessory/caps
icon = 'icons/mob/mutant_bodyparts.dmi'
color_src = HAIR
relevant_layers = list(BODY_ADJ_LAYER)
/datum/sprite_accessory/caps/round
name = "Round"
icon_state = "round"
icon_state = "round"
@@ -1,9 +1,12 @@
/datum/sprite_accessory/ears
icon = 'icons/mob/mutant_bodyparts.dmi'
mutant_part_string = "ears"
relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER)
/datum/sprite_accessory/ears/none
name = "None"
icon_state = "none"
relevant_layers = null
/******************************************
*************** Human Ears ****************
@@ -29,9 +32,10 @@
/datum/sprite_accessory/ears/human/bigwolfinner
name = "Big Wolf (ALT)"
icon_state = "bigwolfinner"
hasinner = 1
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
color_src = MATRIXED
extra = TRUE
extra_color_src = NONE
/datum/sprite_accessory/ears/human/bigwolfdark
name = "Dark Big Wolf"
@@ -42,15 +46,17 @@
/datum/sprite_accessory/ears/human/bigwolfinnerdark
name = "Dark Big Wolf (ALT)"
icon_state = "bigwolfinnerdark"
hasinner = 1
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
color_src = MATRIXED
extra = TRUE
extra_color_src = NONE
/datum/sprite_accessory/ears/cat
name = "Cat"
icon_state = "cat"
hasinner = 1
color_src = HAIR
extra = TRUE
extra_color_src = NONE
/datum/sprite_accessory/ears/human/cow
name = "Cow"
@@ -172,10 +178,13 @@
/datum/sprite_accessory/mam_ears
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
color_src = MATRIXED
mutant_part_string = "ears"
relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER)
/datum/sprite_accessory/mam_ears/none
name = "None"
icon_state = "none"
relevant_layers = null
/datum/sprite_accessory/mam_ears/axolotl
name = "Axolotl"
@@ -196,7 +205,8 @@
/datum/sprite_accessory/mam_ears/bigwolfinner
name = "Big Wolf (ALT)"
icon_state = "bigwolfinner"
hasinner = 1
extra = TRUE
extra_color_src = NONE
/datum/sprite_accessory/mam_ears/bigwolfdark
name = "Dark Big Wolf"
@@ -205,13 +215,16 @@
/datum/sprite_accessory/mam_ears/bigwolfinnerdark
name = "Dark Big Wolf (ALT)"
icon_state = "bigwolfinnerdark"
hasinner = 1
extra = TRUE
extra_color_src = NONE
/datum/sprite_accessory/mam_ears/cat
name = "Cat"
icon_state = "cat"
hasinner = 1
icon = 'icons/mob/mutant_bodyparts.dmi'
color_src = HAIR
extra = TRUE
extra_color_src = NONE
/datum/sprite_accessory/mam_ears/catbig
name = "Cat, Big"
@@ -309,4 +322,4 @@
/datum/sprite_accessory/mam_ears/bunny
name = "Bunny"
icon_state = "bunny"
icon_state = "bunny"
@@ -1,9 +1,11 @@
/datum/sprite_accessory/frills
icon = 'icons/mob/mutant_bodyparts.dmi'
relevant_layers = list(BODY_ADJ_LAYER)
/datum/sprite_accessory/frills/none
name = "None"
icon_state = "none"
relevant_layers = null
/datum/sprite_accessory/frills/simple
name = "Simple"
@@ -15,4 +17,4 @@
/datum/sprite_accessory/frills/aquatic
name = "Aquatic"
icon_state = "aqua"
icon_state = "aqua"
@@ -1,10 +1,12 @@
/datum/sprite_accessory/horns
icon = 'icons/mob/mutant_bodyparts.dmi'
color_src = HORNCOLOR
relevant_layers = list(BODY_ADJ_LAYER)
/datum/sprite_accessory/horns/none
name = "None"
icon_state = "none"
relevant_layers = null
/datum/sprite_accessory/horns/simple
name = "Simple"
@@ -33,4 +35,4 @@
/datum/sprite_accessory/horns/guilmon
name = "Guilmon"
icon_state = "guilmon"
icon_state = "guilmon"
@@ -5,6 +5,7 @@
/datum/sprite_accessory/screen
icon = 'modular_citadel/icons/mob/ipc_screens.dmi'
color_src = null
relevant_layers = list(BODY_ADJ_LAYER)
/datum/sprite_accessory/screen/blank
name = "Blank"
@@ -21,29 +21,42 @@
/datum/sprite_accessory/taur
icon = 'modular_citadel/icons/mob/mam_taur.dmi'
extra_icon = 'modular_citadel/icons/mob/mam_taur.dmi'
extra = TRUE
extra2_icon = 'modular_citadel/icons/mob/mam_taur.dmi'
extra2 = TRUE
center = TRUE
dimension_x = 64
var/taur_mode = NONE //Must be a single specific tauric suit variation bitflag. Don't do FLAG_1|FLAG_2
var/alt_taur_mode = NONE //Same as above.
color_src = MATRIXED
recommended_species = list("human", "lizard", "insect", "mammal", "xeno", "jelly", "slimeperson", "podweak")
relevant_layers = list(BODY_ADJ_UPPER_LAYER, BODY_FRONT_LAYER)
var/taur_mode = NONE //Must be a single specific tauric suit variation bitflag. Don't do FLAG_1|FLAG_2
var/alt_taur_mode = NONE //Same as above.
var/hide_legs = USE_QUADRUPED_CLIP_MASK
/datum/sprite_accessory/taur/New()
switch(hide_legs)
if(USE_QUADRUPED_CLIP_MASK)
alpha_mask_state = "taur_mask_def"
if(USE_SNEK_CLIP_MASK)
alpha_mask_state = "taur_mask_naga"
/datum/sprite_accessory/taur/none
dimension_x = 32
center = FALSE
name = "None"
icon_state = "None"
dimension_x = 32
center = FALSE
recommended_species = null
relevant_layers = null
hide_legs = FALSE
/datum/sprite_accessory/taur/cow
name = "Cow"
icon_state = "cow"
taur_mode = STYLE_HOOF_TAURIC
alt_taur_mode = STYLE_PAW_TAURIC
color_src = MUTCOLORS
/datum/sprite_accessory/taur/cow/spotted
name = "Cow (Spotted)"
icon_state = "cow_spotted"
color_src = MATRIXED
/datum/sprite_accessory/taur/deer
name = "Deer"
@@ -56,27 +69,21 @@
name = "Drake"
icon_state = "drake"
taur_mode = STYLE_PAW_TAURIC
color_src = MUTCOLORS
extra = TRUE
/datum/sprite_accessory/taur/drider
name = "Drider"
icon_state = "drider"
color_src = MUTCOLORS
extra = TRUE
/datum/sprite_accessory/taur/eevee
name = "Eevee"
icon_state = "eevee"
taur_mode = STYLE_PAW_TAURIC
color_src = MUTCOLORS
/datum/sprite_accessory/taur/fox
name = "Fox"
icon_state = "fox"
taur_mode = STYLE_PAW_TAURIC
/datum/sprite_accessory/taur/husky
name = "Husky"
icon_state = "husky"
taur_mode = STYLE_PAW_TAURIC
extra = TRUE
/datum/sprite_accessory/taur/horse
name = "Horse"
@@ -84,15 +91,11 @@
taur_mode = STYLE_HOOF_TAURIC
alt_taur_mode = STYLE_PAW_TAURIC
/datum/sprite_accessory/taur/lab
name = "Lab"
icon_state = "lab"
taur_mode = STYLE_PAW_TAURIC
/datum/sprite_accessory/taur/naga
name = "Naga"
icon_state = "naga"
taur_mode = STYLE_SNEK_TAURIC
hide_legs = USE_SNEK_CLIP_MASK
/datum/sprite_accessory/taur/otie
name = "Otie"
@@ -104,29 +107,26 @@
icon_state = "pede"
taur_mode = STYLE_PAW_TAURIC
color_src = MUTCOLORS
/datum/sprite_accessory/taur/panther
name = "Panther"
icon_state = "panther"
taur_mode = STYLE_PAW_TAURIC
/datum/sprite_accessory/taur/shepherd
name = "Shepherd"
icon_state = "shepherd"
taur_mode = STYLE_PAW_TAURIC
extra = TRUE
extra2 = TRUE
/datum/sprite_accessory/taur/tentacle
name = "Tentacle"
icon_state = "tentacle"
taur_mode = STYLE_SNEK_TAURIC
color_src = MUTCOLORS
hide_legs = USE_SNEK_CLIP_MASK
/datum/sprite_accessory/taur/tiger
name = "Tiger"
icon_state = "tiger"
/datum/sprite_accessory/taur/canine
name = "Canine"
icon_state = "canine"
taur_mode = STYLE_PAW_TAURIC
color_src = MUTCOLORS
extra = TRUE
/datum/sprite_accessory/taur/wolf
name = "Wolf"
icon_state = "wolf"
/datum/sprite_accessory/taur/feline
name = "Feline"
icon_state = "feline"
taur_mode = STYLE_PAW_TAURIC
color_src = MUTCOLORS
extra = TRUE
@@ -1,5 +1,7 @@
/datum/sprite_accessory/snouts
icon = 'icons/mob/mutant_bodyparts.dmi'
mutant_part_string = "snout"
relevant_layers = list(BODY_ADJ_LAYER, BODY_FRONT_LAYER)
/datum/sprite_accessory/snouts/sharp
name = "Sharp"
@@ -152,11 +154,14 @@
color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
recommended_species = list("mammal", "slimeperson", "insect", "podweak")
mutant_part_string = "snout"
relevant_layers = list(BODY_ADJ_LAYER, BODY_FRONT_LAYER)
/datum/sprite_accessory/mam_snouts/none
name = "None"
icon_state = "none"
recommended_species = null
relevant_layers = null
/datum/sprite_accessory/mam_snouts/bird
name = "Beak"
@@ -383,4 +388,4 @@
/datum/sprite_accessory/mam_snouts/froundlight
name = "Round + Light (Top)"
icon_state = "froundlight"
color_src = MUTCOLORS
color_src = MUTCOLORS
@@ -1,12 +1,15 @@
/datum/sprite_accessory/spines
icon = 'icons/mob/mutant_bodyparts.dmi'
relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER)
/datum/sprite_accessory/spines_animated
icon = 'icons/mob/mutant_bodyparts.dmi'
relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER)
/datum/sprite_accessory/spines/none
name = "None"
icon_state = "none"
relevant_layers = null
/datum/sprite_accessory/spines_animated/none
name = "None"
@@ -50,4 +53,4 @@
/datum/sprite_accessory/spines_animated/aqautic
name = "Aquatic"
icon_state = "aqua"
icon_state = "aqua"
@@ -1,8 +1,12 @@
/datum/sprite_accessory/tails
icon = 'icons/mob/mutant_bodyparts.dmi'
mutant_part_string = "tail"
relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
/datum/sprite_accessory/tails_animated
icon = 'icons/mob/mutant_bodyparts.dmi'
mutant_part_string = "tailwag"
relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
/******************************************
************* Lizard Tails ****************
@@ -43,10 +47,12 @@
/datum/sprite_accessory/tails/lizard/none
name = "None"
icon_state = "None"
relevant_layers = null
/datum/sprite_accessory/tails_animated/lizard/none
name = "None"
icon_state = "None"
relevant_layers = null
/datum/sprite_accessory/tails/lizard/axolotl
name = "Axolotl"
@@ -85,10 +91,12 @@
/datum/sprite_accessory/tails/human/none
name = "None"
icon_state = "none"
relevant_layers = null
/datum/sprite_accessory/tails_animated/human/none
name = "None"
icon_state = "none"
relevant_layers = null
/datum/sprite_accessory/tails/human/ailurus
name = "Red Panda"
@@ -502,20 +510,25 @@
color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
recommended_species = list("mammal", "slimeperson", "podweak", "felinid", "insect")
mutant_part_string = "tail"
relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
/datum/sprite_accessory/mam_tails/none
name = "None"
icon_state = "none"
recommended_species = null
relevant_layers = null
/datum/sprite_accessory/mam_tails_animated
color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
mutant_part_string = "tailwag"
relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
/datum/sprite_accessory/mam_tails_animated/none
name = "None"
icon_state = "none"
color_src = MATRIXED
relevant_layers = null
/datum/sprite_accessory/mam_tails/ailurus
name = "Red Panda"
@@ -576,7 +589,7 @@
/datum/sprite_accessory/mam_tails_animated/catbig
name = "Cat, Big"
icon_state = "catbig"
/datum/sprite_accessory/mam_tails/twocat
name = "Cat, Double"
icon_state = "twocat"
@@ -3,9 +3,11 @@
/datum/sprite_accessory/wings/none
name = "None"
icon_state = "none"
relevant_layers = null
/datum/sprite_accessory/wings_open
icon = 'icons/mob/wings.dmi'
relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER)
/datum/sprite_accessory/wings_open/angel
name = "Angel"
@@ -17,6 +19,7 @@
/datum/sprite_accessory/wings
icon = 'icons/mob/wings.dmi'
relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER)
/datum/sprite_accessory/wings/angel
name = "Angel"
@@ -32,10 +35,13 @@
/datum/sprite_accessory/deco_wings
icon = 'icons/mob/wings.dmi'
color_src = WINGCOLOR
mutant_part_string = "insect_wings"
relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
/datum/sprite_accessory/deco_wings/none
name = "None"
icon_state = "none"
relevant_layers = null
/datum/sprite_accessory/deco_wings/angel
name = "Angel"
@@ -44,6 +50,7 @@
dimension_x = 46
center = TRUE
dimension_y = 34
relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER)
/datum/sprite_accessory/deco_wings/bat
name = "Bat"
@@ -130,10 +137,12 @@
/datum/sprite_accessory/insect_wings
icon = 'icons/mob/wings.dmi'
color_src = WINGCOLOR
relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
/datum/sprite_accessory/insect_wings/none
name = "None"
icon_state = "none"
relevant_layers = null
/datum/sprite_accessory/insect_wings/bat
name = "Bat"
@@ -231,10 +240,12 @@
/datum/sprite_accessory/insect_markings // Extra markings for insects ported from tg.
icon = 'icons/mob/insect_markings.dmi'
color_src = null
relevant_layers = list(BODY_ADJ_LAYER)
/datum/sprite_accessory/insect_markings/none
name = "None"
icon_state = "none"
relevant_layers = null
/datum/sprite_accessory/insect_markings/reddish
name = "Reddish"
@@ -290,4 +301,4 @@
/datum/sprite_accessory/insect_markings/witchwing
name = "Witch Wing"
icon_state = "witchwing"
icon_state = "witchwing"
@@ -937,3 +937,20 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
spawners_menu = new(src)
spawners_menu.ui_interact(src)
/mob/dead/observer/verb/game_info()
set name = "Game info"
set desc = "Shows various info relating to the game mode, antagonists etc."
set category = "Ghost"
if(!started_as_observer && can_reenter_corpse)
to_chat(src, "You cannot see this info unless you are an observer or you've chosen Do Not Resuscitate!")
return
var/list/stuff = list("[SSticker.mode.name]")
stuff += "Antagonists:\n"
for(var/datum/antagonist/A in GLOB.antagonists)
if(A.owner)
stuff += "[A.owner] the [A.name]"
var/ghost_info = SSticker.mode.ghost_info()
if(ghost_info)
stuff += ghost_info
to_chat(src,stuff.Join("\n"))
+3
View File
@@ -33,6 +33,9 @@
else
to_follow = V.source
var/link = FOLLOW_LINK(src, to_follow)
// Create map text prior to modifying message for goonchat
if (client?.prefs.chat_on_map && (client.prefs.see_chat_non_mob || ismob(speaker)))
create_chat_message(speaker, message_language, raw_message, spans, message_mode)
// Recompose the message, because it's scrambled by default
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source)
to_chat(src, "[link] [message]")
+10 -16
View File
@@ -245,23 +245,17 @@
. = adjusted_amount
*/
/obj/item/organ/brain/on_life()
if(damage >= BRAIN_DAMAGE_DEATH) //rip
to_chat(owner, "<span class='userdanger'>The last spark of life in your brain fizzles out...</span>")
owner.death()
brain_death = TRUE
return
..()
/obj/item/organ/brain/on_death()
if(damage <= BRAIN_DAMAGE_DEATH) //rip
brain_death = FALSE
..()
/obj/item/organ/brain/applyOrganDamage(var/d, var/maximum = maxHealth)
..()
. = ..()
if(!. || !owner)
return
if(damage >= BRAIN_DAMAGE_DEATH) //rip
if(owner.stat != DEAD)
to_chat(owner, "<span class='userdanger'>The last spark of life in your brain fizzles out...</span>")
owner.death()
brain_death = TRUE
else
brain_death = FALSE
/obj/item/organ/brain/check_damage_thresholds(mob/M)
. = ..()
@@ -12,6 +12,13 @@
bubble_icon = "alien"
type_of_meat = /obj/item/reagent_containers/food/snacks/meat/slab/xeno
/// How much brute damage without armor piercing they do against mobs in melee
var/meleeSlashHumanPower = 20
/// How much power they have for DefaultCombatKnockdown when attacking humans
var/meleeKnockdownPower = 100
/// How much brute damage they do to simple animals
var/meleeSlashSAPower = 35
var/obj/item/card/id/wear_id = null // Fix for station bounced radios -- Skie
var/has_fine_manipulation = 0
var/move_delay_add = 0 // movement delay to add
@@ -4,6 +4,7 @@
maxHealth = 125
health = 125
icon_state = "aliend"
meleeKnockdownPower = 80
/mob/living/carbon/alien/humanoid/drone/Initialize()
AddAbility(new/obj/effect/proc_holder/alien/evolve(null))
@@ -1,9 +1,12 @@
/mob/living/carbon/alien/humanoid/hunter
name = "alien hunter"
caste = "h"
maxHealth = 125
health = 125
maxHealth = 170
health = 170
icon_state = "alienh"
meleeKnockdownPower = 75
meleeSlashHumanPower = 20
meleeSlashSAPower = 45
var/obj/screen/leap_icon = null
/mob/living/carbon/alien/humanoid/hunter/create_internal_organs()
@@ -68,6 +71,7 @@
else
L.visible_message("<span class ='danger'>[src] pounces on [L]!</span>", "<span class ='userdanger'>[src] pounces on you!</span>")
L.DefaultCombatKnockdown(100)
L.Stagger(4 SECONDS)
sleep(2)//Runtime prevention (infinite bump() calls on hulks)
step_towards(src,L)
@@ -1,9 +1,10 @@
/mob/living/carbon/alien/humanoid/sentinel
name = "alien sentinel"
caste = "s"
maxHealth = 150
health = 150
maxHealth = 140
health = 140
icon_state = "aliens"
meleeSlashHumanPower = 15
/mob/living/carbon/alien/humanoid/sentinel/Initialize()
AddAbility(new /obj/effect/proc_holder/alien/sneak)
@@ -112,7 +112,6 @@
return A
return FALSE
/mob/living/carbon/alien/humanoid/check_breath(datum/gas_mixture/breath)
if(breath && breath.total_moles() > 0 && !sneaking)
playsound(get_turf(src), pick('sound/voice/lowHiss2.ogg', 'sound/voice/lowHiss3.ogg', 'sound/voice/lowHiss4.ogg'), 50, 0, -5)
@@ -1,4 +1,3 @@
/mob/living/carbon/alien/humanoid/grabbedby(mob/living/carbon/user, supress_message = 0)
if(user == src && pulling && grab_state >= GRAB_AGGRESSIVE && !pulling.anchored && iscarbon(pulling))
devour_mob(pulling, devour_time = 60)
@@ -1,5 +1,3 @@
/mob/living/carbon/alien/humanoid/proc/adjust_body_temperature(current, loc_temp, boost)
var/temperature = current
var/difference = abs(current-loc_temp) //get difference
@@ -11,6 +11,10 @@
pressure_resistance = 200 //Because big, stompy xenos should not be blown around like paper.
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/xeno = 20, /obj/item/stack/sheet/animalhide/xeno = 3)
meleeKnockdownPower = 125
meleeSlashHumanPower = 30
meleeSlashSAPower = 60
var/alt_inhands_file = 'icons/mob/alienqueen.dmi'
/mob/living/carbon/alien/humanoid/royal/can_inject(mob/user, error_msg, target_zone, penetrate_thick = FALSE, bypass_immunity = FALSE)
@@ -6,6 +6,7 @@
mob_size = MOB_SIZE_SMALL
density = FALSE
hud_type = /datum/hud/larva
mouse_opacity = MOUSE_OPACITY_OPAQUE
maxHealth = 25
health = 25
@@ -77,6 +77,9 @@
alien_powers = list(/obj/effect/proc_holder/alien/transfer)
/obj/item/organ/alien/plasmavessel/on_life()
. = ..()
if(!.)
return
//If there are alien weeds on the ground then heal if needed or give some plasma
if(locate(/obj/structure/alien/weeds) in owner.loc)
if(owner.health >= owner.maxHealth)
@@ -23,6 +23,8 @@
/obj/item/organ/body_egg/alien_embryo/on_life()
. = ..()
if(!owner)
return
switch(stage)
if(2, 3)
if(prob(2))
+12 -4
View File
@@ -7,6 +7,7 @@
update_body_parts() //to update the carbon's new bodyparts appearance
GLOB.carbon_list += src
blood_volume = (BLOOD_VOLUME_NORMAL * blood_ratio)
add_movespeed_modifier(/datum/movespeed_modifier/carbon_crawling)
/mob/living/carbon/Destroy()
//This must be done first, so the mob ghosts correctly before DNA etc is nulled
@@ -539,10 +540,16 @@
return 1
/mob/living/carbon/proc/spew_organ(power = 5, amt = 1)
var/list/spillable_organs = list()
for(var/A in internal_organs)
var/obj/item/organ/O = A
if(!(O.organ_flags & ORGAN_NO_DISMEMBERMENT))
spillable_organs += O
for(var/i in 1 to amt)
if(!internal_organs.len)
if(!spillable_organs.len)
break //Guess we're out of organs!
var/obj/item/organ/guts = pick(internal_organs)
var/obj/item/organ/guts = pick(spillable_organs)
spillable_organs -= guts
var/turf/T = get_turf(src)
guts.Remove()
guts.forceMove(T)
@@ -550,6 +557,7 @@
guts.throw_at(throw_target, power, 4, src)
/mob/living/carbon/fully_replace_character_name(oldname,newname)
..()
if(dna)
@@ -574,9 +582,9 @@
become_husk("burn")
med_hud_set_health()
if(stat == SOFT_CRIT)
add_movespeed_modifier(MOVESPEED_ID_CARBON_SOFTCRIT, TRUE, multiplicative_slowdown = SOFTCRIT_ADD_SLOWDOWN)
add_movespeed_modifier(/datum/movespeed_modifier/carbon_softcrit)
else
remove_movespeed_modifier(MOVESPEED_ID_CARBON_SOFTCRIT, TRUE)
remove_movespeed_modifier(/datum/movespeed_modifier/carbon_softcrit)
/mob/living/carbon/update_stamina()
var/stam = getStaminaLoss()
@@ -38,7 +38,7 @@
adjustCloneLoss(damage_amount, forced = forced)
if(STAMINA)
if(BP)
if(damage > 0 ? BP.receive_damage(0, 0, damage_amount) : BP.heal_damage(0, 0, abs(damage_amount)))
if(damage > 0 ? BP.receive_damage(0, 0, damage_amount) : BP.heal_damage(0, 0, abs(damage_amount), FALSE, FALSE))
update_damage_overlays()
else
adjustStaminaLoss(damage_amount, forced = forced)
+2 -6
View File
@@ -41,18 +41,14 @@
if(no_brain && istype(O, /obj/item/organ/brain))
qdel(O) //so the brain isn't transfered to the head when the head drops.
continue
var/org_zone = check_zone(O.zone) //both groin and chest organs.
if(org_zone == BODY_ZONE_CHEST)
if(!(O.organ_flags & ORGAN_NO_DISMEMBERMENT) && check_zone(O.zone) == BODY_ZONE_CHEST)
O.Remove()
O.forceMove(Tsec)
O.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),5)
else
for(var/X in internal_organs)
var/obj/item/organ/I = X
if(no_brain && istype(I, /obj/item/organ/brain))
qdel(I)
continue
if(no_organs && !istype(I, /obj/item/organ/brain))
if(I.organ_flags & ORGAN_NO_DISMEMBERMENT || (no_brain && istype(I, /obj/item/organ/brain)) || (no_organs && !istype(I, /obj/item/organ/brain)))
qdel(I)
continue
I.Remove()
+11 -10
View File
@@ -1041,7 +1041,7 @@
return FALSE
/mob/living/carbon/human/proc/clear_shove_slowdown()
remove_movespeed_modifier(MOVESPEED_ID_SHOVE)
remove_movespeed_modifier(/datum/movespeed_modifier/shove)
var/active_item = get_active_held_item()
if(is_type_in_typecache(active_item, GLOB.shove_disarming_types))
visible_message("<span class='warning'>[src.name] regains their grip on \the [active_item]!</span>", "<span class='warning'>You regain your grip on \the [active_item]</span>", null, COMBAT_MESSAGE_RANGE)
@@ -1049,18 +1049,19 @@
/mob/living/carbon/human/updatehealth()
. = ..()
if(HAS_TRAIT(src, TRAIT_IGNORESLOWDOWN))
remove_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN)
remove_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN_FLYING)
if(HAS_TRAIT(src, TRAIT_IGNORESLOWDOWN)) //if we want to ignore slowdown from damage and equipment
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying)
return
var/stambufferinfluence = (bufferedstam*(100/stambuffer))*0.2 //CIT CHANGE - makes stamina buffer influence movedelay
var/health_deficiency = ((100 + stambufferinfluence) - health + (getStaminaLoss()*0.75))//CIT CHANGE - reduces the impact of staminaloss and makes stamina buffer influence it
if(health_deficiency >= 40)
add_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN, override = TRUE, multiplicative_slowdown = ((health_deficiency-39) / 75), blacklisted_movetypes = FLOATING|FLYING)
add_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN_FLYING, override = TRUE, multiplicative_slowdown = ((health_deficiency-39) / 25), movetypes = FLYING, blacklisted_movetypes = FLOATING)
if(!HAS_TRAIT(src, TRAIT_IGNOREDAMAGESLOWDOWN)) //if we want to ignore slowdown from damage, but not from equipment
var/health_deficiency = ((maxHealth + stambufferinfluence) - health + (getStaminaLoss()*0.75))//CIT CHANGE - reduces the impact of staminaloss and makes stamina buffer influence it
if(health_deficiency >= 40)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown, TRUE, (health_deficiency-39) / 75)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying, TRUE, (health_deficiency-39) / 25)
else
remove_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN)
remove_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN_FLYING)
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying)
/mob/living/carbon/human/do_after_coefficent()
. = ..()
@@ -155,7 +155,7 @@
if(M.a_intent == INTENT_HARM)
if (w_uniform)
w_uniform.add_fingerprint(M)
var/damage = prob(90) ? 20 : 0
var/damage = prob(90) ? M.meleeSlashHumanPower : 0
if(!damage)
playsound(loc, 'sound/weapons/slashmiss.ogg', 50, 1, -1)
visible_message("<span class='danger'>[M] has lunged at [src]!</span>", \
@@ -182,10 +182,7 @@
"<span class='userdanger'>[M] disarmed [src]!</span>")
else
playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
if(!lying) //CITADEL EDIT
DefaultCombatKnockdown(100, TRUE, FALSE, 30, 25)
else
DefaultCombatKnockdown(100)
DefaultCombatKnockdown(M.meleeKnockdownPower)
log_combat(M, src, "tackled")
visible_message("<span class='danger'>[M] has tackled down [src]!</span>", \
"<span class='userdanger'>[M] has tackled down [src]!</span>")
@@ -1,11 +1,13 @@
/mob/living/carbon/human/get_movespeed_modifiers()
var/list/considering = ..()
. = considering
if(HAS_TRAIT(src, TRAIT_IGNORESLOWDOWN))
for(var/id in .)
var/list/data = .[id]
if(data[MOVESPEED_DATA_INDEX_FLAGS] & IGNORE_NOSLOW)
.[id] = data
. = list()
for(var/id in considering)
var/datum/movespeed_modifier/M = considering[id]
if(M.flags & IGNORE_NOSLOW || M.multiplicative_slowdown < 0)
.[id] = M
return
return considering
/mob/living/carbon/human/movement_delay()
. = ..()
@@ -22,13 +24,18 @@
/mob/living/carbon/human/slip(knockdown_amount, obj/O, lube)
if(HAS_TRAIT(src, TRAIT_NOSLIPALL))
return 0
if (!(lube&GALOSHES_DONT_HELP))
if (!(lube & GALOSHES_DONT_HELP))
if(HAS_TRAIT(src, TRAIT_NOSLIPWATER))
return 0
if(shoes && istype(shoes, /obj/item/clothing))
var/obj/item/clothing/CS = shoes
if (CS.clothing_flags & NOSLIP)
return 0
if (lube & SLIDE_ICE)
if(shoes && istype(shoes, /obj/item/clothing))
var/obj/item/clothing/CS = shoes
if (CS.clothing_flags & NOSLIP_ICE)
return FALSE
return ..()
/mob/living/carbon/human/experience_pressure_difference()
+126 -166
View File
@@ -334,7 +334,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(mutant_bodyparts["meat_type"]) //I can't believe it's come to the meat
H.type_of_meat = GLOB.meat_types[H.dna.features["meat_type"]]
C.add_movespeed_modifier(MOVESPEED_ID_SPECIES, TRUE, 100, override=TRUE, multiplicative_slowdown=speedmod, movetypes=(~FLYING))
C.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/species, TRUE, multiplicative_slowdown = speedmod)
SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species)
@@ -352,7 +352,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
for(var/X in inherent_traits)
REMOVE_TRAIT(C, X, SPECIES_TRAIT)
C.remove_movespeed_modifier(MOVESPEED_ID_SPECIES)
C.remove_movespeed_modifier(/datum/movespeed_modifier/species)
if(mutant_bodyparts["meat_type"])
C.type_of_meat = GLOB.meat_types[C.dna.features["meat_type"]]
@@ -551,8 +551,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
//Underwear, Undershirts & Socks
if(!(NO_UNDERWEAR in species_traits))
if(H.socks && !H.hidden_socks && H.get_num_legs(FALSE) >= 2)
var/datum/sprite_accessory/taur/TA
if(mutant_bodyparts["taur"] && H.dna.features["taur"])
TA = GLOB.taur_list[H.dna.features["taur"]]
if(!(TA?.hide_legs) && H.socks && !H.hidden_socks && H.get_num_legs(FALSE) >= 2)
if(H.saved_socks)
H.socks = H.saved_socks
H.saved_socks = ""
@@ -585,7 +587,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/state = "[T.icon_state][((DIGITIGRADE in species_traits) && T.has_digitigrade) ? "_d" : ""]"
var/mutable_appearance/MA
if(H.dna.species.sexes && H.dna.features["body_model"] == FEMALE)
MA = wear_female_version(state, T.icon, BODY_LAYER)
MA = wear_alpha_masked_version(state, T.icon, BODY_LAYER, FEMALE_UNIFORM_TOP)
else
MA = mutable_appearance(T.icon, state, -BODY_LAYER)
if(T.has_color)
@@ -600,21 +602,17 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
/datum/species/proc/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour)
var/list/bodyparts_to_add = mutant_bodyparts.Copy()
var/list/relevent_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER, BODY_TAUR_LAYER)
var/list/standing = list()
H.remove_overlay(BODY_BEHIND_LAYER)
H.remove_overlay(BODY_ADJ_LAYER)
H.remove_overlay(BODY_ADJ_UPPER_LAYER)
H.remove_overlay(BODY_FRONT_LAYER)
//CITADEL EDIT - Do not forget to add this to relevent_layers list just above too!
H.remove_overlay(BODY_TAUR_LAYER)
//END EDIT
if(!mutant_bodyparts)
return
var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD)
var/tauric = H.dna.features["taur"] && H.dna.features["taur"] != "None"
var/tauric = mutant_bodyparts["taur"] && H.dna.features["taur"] && H.dna.features["taur"] != "None"
if(mutant_bodyparts["tail_lizard"])
if((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric)
@@ -745,95 +743,105 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(!bodyparts_to_add)
return
var/list/relevant_layers = list()
var/list/dna_feature_as_text_string = list()
for(var/bodypart in bodyparts_to_add)
var/datum/sprite_accessory/S
switch(bodypart)
if("tail_lizard")
S = GLOB.tails_list_lizard[H.dna.features["tail_lizard"]]
if("waggingtail_lizard")
S = GLOB.animated_tails_list_lizard[H.dna.features["tail_lizard"]]
if("tail_human")
S = GLOB.tails_list_human[H.dna.features["tail_human"]]
if("waggingtail_human")
S = GLOB.animated_tails_list_human[H.dna.features["tail_human"]]
if("spines")
S = GLOB.spines_list[H.dna.features["spines"]]
if("waggingspines")
S = GLOB.animated_spines_list[H.dna.features["spines"]]
if("snout")
S = GLOB.snouts_list[H.dna.features["snout"]]
if("frills")
S = GLOB.frills_list[H.dna.features["frills"]]
if("horns")
S = GLOB.horns_list[H.dna.features["horns"]]
if("ears")
S = GLOB.ears_list[H.dna.features["ears"]]
if("body_markings")
S = GLOB.body_markings_list[H.dna.features["body_markings"]]
if("wings")
S = GLOB.wings_list[H.dna.features["wings"]]
if("wingsopen")
S = GLOB.wings_open_list[H.dna.features["wings"]]
if("deco_wings")
S = GLOB.deco_wings_list[H.dna.features["deco_wings"]]
if("legs")
S = GLOB.legs_list[H.dna.features["legs"]]
if("insect_wings")
S = GLOB.insect_wings_list[H.dna.features["insect_wings"]]
if("insect_fluff")
S = GLOB.insect_fluffs_list[H.dna.features["insect_fluff"]]
if("insect_markings")
S = GLOB.insect_markings_list[H.dna.features["insect_markings"]]
if("caps")
S = GLOB.caps_list[H.dna.features["caps"]]
if("ipc_screen")
S = GLOB.ipc_screens_list[H.dna.features["ipc_screen"]]
if("ipc_antenna")
S = GLOB.ipc_antennas_list[H.dna.features["ipc_antenna"]]
if("mam_tail")
S = GLOB.mam_tails_list[H.dna.features["mam_tail"]]
if("mam_waggingtail")
S = GLOB.mam_tails_animated_list[H.dna.features["mam_tail"]]
if("mam_body_markings")
S = GLOB.mam_body_markings_list[H.dna.features["mam_body_markings"]]
if("mam_ears")
S = GLOB.mam_ears_list[H.dna.features["mam_ears"]]
if("mam_snouts")
S = GLOB.mam_snouts_list[H.dna.features["mam_snouts"]]
if("taur")
S = GLOB.taur_list[H.dna.features["taur"]]
if("xenodorsal")
S = GLOB.xeno_dorsal_list[H.dna.features["xenodorsal"]]
if("xenohead")
S = GLOB.xeno_head_list[H.dna.features["xenohead"]]
if("xenotail")
S = GLOB.xeno_tail_list[H.dna.features["xenotail"]]
if(!S || S.icon_state == "none")
continue
for(var/L in S.relevant_layers)
LAZYADD(relevant_layers["[L]"], S)
if(!S.mutant_part_string)
dna_feature_as_text_string[S] = bodypart
var/static/list/layer_text = list("[BODY_BEHIND_LAYER]" = "BEHIND", "[BODY_ADJ_LAYER]" = "ADJ", \
"[BODY_ADJ_UPPER_LAYER]" = "ADJUP", "[BODY_FRONT_LAYER]" = "FRONT")
var/g = (H.dna.features["body_model"] == FEMALE) ? "f" : "m"
var/list/colorlist = list()
var/husk = HAS_TRAIT(H, TRAIT_HUSK)
colorlist += husk ? ReadRGB("#a3a3a3") :ReadRGB("[H.dna.features["mcolor"]]0")
colorlist += husk ? ReadRGB("#a3a3a3") :ReadRGB("[H.dna.features["mcolor2"]]0")
colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features["mcolor3"]]0")
colorlist += list(0,0,0, hair_alpha)
for(var/index in 1 to colorlist.len)
colorlist[index] /= 255
for(var/layer in relevent_layers)
var/layertext = mutant_bodyparts_layertext(layer)
for(var/bodypart in bodyparts_to_add)
var/datum/sprite_accessory/S
switch(bodypart)
if("tail_lizard")
S = GLOB.tails_list_lizard[H.dna.features["tail_lizard"]]
if("waggingtail_lizard")
S = GLOB.animated_tails_list_lizard[H.dna.features["tail_lizard"]]
if("tail_human")
S = GLOB.tails_list_human[H.dna.features["tail_human"]]
if("waggingtail_human")
S = GLOB.animated_tails_list_human[H.dna.features["tail_human"]]
if("spines")
S = GLOB.spines_list[H.dna.features["spines"]]
if("waggingspines")
S = GLOB.animated_spines_list[H.dna.features["spines"]]
if("snout")
S = GLOB.snouts_list[H.dna.features["snout"]]
if("frills")
S = GLOB.frills_list[H.dna.features["frills"]]
if("horns")
S = GLOB.horns_list[H.dna.features["horns"]]
if("ears")
S = GLOB.ears_list[H.dna.features["ears"]]
if("body_markings")
S = GLOB.body_markings_list[H.dna.features["body_markings"]]
if("wings")
S = GLOB.wings_list[H.dna.features["wings"]]
if("wingsopen")
S = GLOB.wings_open_list[H.dna.features["wings"]]
if("deco_wings")
S = GLOB.deco_wings_list[H.dna.features["deco_wings"]]
if("legs")
S = GLOB.legs_list[H.dna.features["legs"]]
if("insect_wings")
S = GLOB.insect_wings_list[H.dna.features["insect_wings"]]
if("insect_fluff")
S = GLOB.insect_fluffs_list[H.dna.features["insect_fluff"]]
if("insect_markings")
S = GLOB.insect_markings_list[H.dna.features["insect_markings"]]
if("caps")
S = GLOB.caps_list[H.dna.features["caps"]]
if("ipc_screen")
S = GLOB.ipc_screens_list[H.dna.features["ipc_screen"]]
if("ipc_antenna")
S = GLOB.ipc_antennas_list[H.dna.features["ipc_antenna"]]
if("mam_tail")
S = GLOB.mam_tails_list[H.dna.features["mam_tail"]]
if("mam_waggingtail")
S = GLOB.mam_tails_animated_list[H.dna.features["mam_tail"]]
if("mam_body_markings")
S = GLOB.mam_body_markings_list[H.dna.features["mam_body_markings"]]
if("mam_ears")
S = GLOB.mam_ears_list[H.dna.features["mam_ears"]]
if("mam_snouts")
S = GLOB.mam_snouts_list[H.dna.features["mam_snouts"]]
if("taur")
S = GLOB.taur_list[H.dna.features["taur"]]
if("xenodorsal")
S = GLOB.xeno_dorsal_list[H.dna.features["xenodorsal"]]
if("xenohead")
S = GLOB.xeno_head_list[H.dna.features["xenohead"]]
if("xenotail")
S = GLOB.xeno_tail_list[H.dna.features["xenotail"]]
if(!S || S.icon_state == "none")
continue
var/mutable_appearance/accessory_overlay = mutable_appearance(S.icon, layer = -layer)
accessory_overlay.color = null //just because. reee.
//A little rename so we don't have to use tail_lizard or tail_human when naming the sprites.
if(bodypart == "tail_lizard" || bodypart == "tail_human" || bodypart == "mam_tail" || bodypart == "xenotail")
bodypart = "tail"
if(bodypart == "mam_waggingtail" || bodypart == "waggingtail_human" || bodypart == "waggingtail_lizard")
bodypart = "tailwag"
if(bodypart == "mam_ears" || bodypart == "ears")
bodypart = "ears"
if(bodypart == "mam_snouts" || bodypart == "snout")
bodypart = "snout"
if(bodypart == "xenohead")
bodypart = "xhead"
if(bodypart == "insect_wings" || bodypart == "deco_wings")
bodypart = "insect_wings"
for(var/layer in relevant_layers)
var/list/standing = list()
var/layertext = layer_text[layer]
if(!layertext) //shouldn't happen
stack_trace("invalid layer '[layer]' found in the list of relevant layers on species.handle_mutant_bodyparts().")
continue
var/layernum = text2num(layer)
for(var/bodypart in relevant_layers[layer])
var/datum/sprite_accessory/S = bodypart
var/mutable_appearance/accessory_overlay = mutable_appearance(S.icon, layer = -layernum)
bodypart = S.mutant_part_string || dna_feature_as_text_string[S]
if(S.gender_specific)
accessory_overlay.icon_state = "[g]_[bodypart]_[S.icon_state]_[layertext]"
@@ -843,16 +851,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(S.center)
accessory_overlay = center_image(accessory_overlay, S.dimension_x, S.dimension_y)
var/list/colorlist = list()
colorlist.Cut()
colorlist += ReadRGB("[H.dna.features["mcolor"]]0")
colorlist += ReadRGB("[H.dna.features["mcolor2"]]0")
colorlist += ReadRGB("[H.dna.features["mcolor3"]]0")
colorlist += list(0,0,0, hair_alpha)
for(var/index=1, index<=colorlist.len, index++)
colorlist[index] = colorlist[index]/255
if(!HAS_TRAIT(H, TRAIT_HUSK))
if(!husk)
if(!forced_colour)
switch(S.color_src)
if(SKINTONE)
@@ -897,14 +896,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(bodypart == "tail")
accessory_overlay.icon_state = "m_tail_husk_[layertext]"
if(S.color_src == MATRIXED)
var/list/husklist = list()
husklist += ReadRGB("#a3a3a3")
husklist += ReadRGB("#a3a3a3")
husklist += ReadRGB("#a3a3a3")
husklist += list(0,0,0, hair_alpha)
for(var/index=1, index<=husklist.len, index++)
husklist[index] = husklist[index]/255
accessory_overlay.color = husklist
accessory_overlay.color = colorlist
if(OFFSET_MUTPARTS in H.dna.species.offset_features)
accessory_overlay.pixel_x += H.dna.species.offset_features[OFFSET_MUTPARTS][1]
@@ -912,24 +904,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
standing += accessory_overlay
if(S.hasinner)
var/mutable_appearance/inner_accessory_overlay = mutable_appearance(S.icon, layer = -layer)
if(S.gender_specific)
inner_accessory_overlay.icon_state = "[g]_[bodypart]inner_[S.icon_state]_[layertext]"
else
inner_accessory_overlay.icon_state = "m_[bodypart]inner_[S.icon_state]_[layertext]"
if(S.center)
inner_accessory_overlay = center_image(inner_accessory_overlay, S.dimension_x, S.dimension_y)
if(OFFSET_MUTPARTS in H.dna.species.offset_features)
inner_accessory_overlay.pixel_x += H.dna.species.offset_features[OFFSET_MUTPARTS][1]
inner_accessory_overlay.pixel_y += H.dna.species.offset_features[OFFSET_MUTPARTS][2]
standing += inner_accessory_overlay
if(S.extra) //apply the extra overlay, if there is one
var/mutable_appearance/extra_accessory_overlay = mutable_appearance(S.icon, layer = -layer)
var/mutable_appearance/extra_accessory_overlay = mutable_appearance(S.icon, layer = -layernum)
if(S.gender_specific)
extra_accessory_overlay.icon_state = "[g]_[bodypart]_extra_[S.icon_state]_[layertext]"
else
@@ -976,7 +952,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
standing += extra_accessory_overlay
if(S.extra2) //apply the extra overlay, if there is one
var/mutable_appearance/extra2_accessory_overlay = mutable_appearance(S.icon, layer = -layer)
var/mutable_appearance/extra2_accessory_overlay = mutable_appearance(S.icon, layer = -layernum)
if(S.gender_specific)
extra2_accessory_overlay.icon_state = "[g]_[bodypart]_extra2_[S.icon_state]_[layertext]"
else
@@ -1017,13 +993,12 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
standing += extra2_accessory_overlay
H.overlays_standing[layer] = standing.Copy()
standing = list()
H.overlays_standing[layernum] = standing
H.apply_overlay(BODY_BEHIND_LAYER)
H.apply_overlay(BODY_ADJ_LAYER)
H.apply_overlay(BODY_ADJ_UPPER_LAYER)
H.apply_overlay(BODY_FRONT_LAYER)
H.apply_overlay(BODY_TAUR_LAYER) // CITADEL EDIT
/*
@@ -1035,21 +1010,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
outfit_important_for_life= new()
outfit_important_for_life.equip(human_to_equip)
//This exists so sprite accessories can still be per-layer without having to include that layer's
//number in their sprite name, which causes issues when those numbers change.
/datum/species/proc/mutant_bodyparts_layertext(layer)
switch(layer)
if(BODY_BEHIND_LAYER)
return "BEHIND"
if(BODY_ADJ_LAYER)
return "ADJ"
if(BODY_FRONT_LAYER)
return "FRONT"
//CITADEL EDIT
if(BODY_TAUR_LAYER)
return "TAUR"
//END EDIT
/* TODO: Snowflake trail marks
// Impliments different trails for species depending on if they're wearing shoes.
/datum/species/proc/get_move_trail(var/mob/living/carbon/human/H)
@@ -1302,14 +1262,14 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(H.overeatduration < 100)
to_chat(H, "<span class='notice'>You feel fit again!</span>")
REMOVE_TRAIT(H, TRAIT_FAT, OBESITY)
H.remove_movespeed_modifier(MOVESPEED_ID_FAT)
H.remove_movespeed_modifier(/datum/movespeed_modifier/obesity)
H.update_inv_w_uniform()
H.update_inv_wear_suit()
else
if(H.overeatduration >= 100)
to_chat(H, "<span class='danger'>You suddenly feel blubbery!</span>")
ADD_TRAIT(H, TRAIT_FAT, OBESITY)
H.add_movespeed_modifier(MOVESPEED_ID_FAT, multiplicative_slowdown = 1.5)
H.add_movespeed_modifier(/datum/movespeed_modifier/obesity)
H.update_inv_w_uniform()
H.update_inv_wear_suit()
@@ -1365,9 +1325,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(!HAS_TRAIT(H, TRAIT_NOHUNGER))
var/hungry = (500 - H.nutrition) / 5 //So overeat would be 100 and default level would be 80
if(hungry >= 70)
H.add_movespeed_modifier(MOVESPEED_ID_HUNGRY, override = TRUE, multiplicative_slowdown = (hungry / 50))
H.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/hunger, multiplicative_slowdown = (hungry / 50))
else
H.remove_movespeed_modifier(MOVESPEED_ID_HUNGRY)
H.remove_movespeed_modifier(/datum/movespeed_modifier/hunger)
switch(H.nutrition)
if(NUTRITION_LEVEL_FULL to INFINITY)
@@ -1618,7 +1578,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
"You hear a slap."
)
return FALSE
else
user.do_attack_animation(target, ATTACK_EFFECT_DISARM)
@@ -1626,10 +1586,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
user.adjustStaminaLossBuffered(1)
else
user.adjustStaminaLossBuffered(3)
if(attacker_style && attacker_style.disarm_act(user,target))
return TRUE
if(target.w_uniform)
target.w_uniform.add_fingerprint(user)
//var/randomized_zone = ran_zone(user.zone_selected) CIT CHANGE - comments out to prevent compiling errors
@@ -1662,7 +1622,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
randn -= 25 //if you are a pugilist, you're slapping that item from them pretty reliably
if(HAS_TRAIT(target, TRAIT_PUGILIST))
randn += 25 //meanwhile, pugilists are less likely to get disarmed
if(randn <= 35)//CIT CHANGE - changes this back to a 35% chance to accomodate for the above being commented out in favor of right-click pushing
var/obj/item/I = null
if(target.pulling)
@@ -1935,8 +1895,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/obj/item/target_held_item = target.get_active_held_item()
if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types))
target_held_item = null
if(!target.has_movespeed_modifier(MOVESPEED_ID_SHOVE))
target.add_movespeed_modifier(MOVESPEED_ID_SHOVE, multiplicative_slowdown = SHOVE_SLOWDOWN_STRENGTH)
if(!target.has_movespeed_modifier(/datum/movespeed_modifier/shove))
target.add_movespeed_modifier(/datum/movespeed_modifier/shove)
if(target_held_item)
if(!HAS_TRAIT(target_held_item, TRAIT_NODROP))
target.visible_message("<span class='danger'>[target.name]'s grip on \the [target_held_item] loosens!</span>",
@@ -2087,7 +2047,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "cold")
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "hot", /datum/mood_event/hot)
H.remove_movespeed_modifier(MOVESPEED_ID_COLD)
H.remove_movespeed_modifier(/datum/movespeed_modifier/cold)
var/burn_damage
var/firemodifier = H.fire_stacks / 50
@@ -2104,8 +2064,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
else if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT && !HAS_TRAIT(H, TRAIT_RESISTCOLD))
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "hot")
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "cold", /datum/mood_event/cold)
//Sorry for the nasty oneline but I don't want to assign a variable on something run pretty frequently
H.add_movespeed_modifier(MOVESPEED_ID_COLD, override = TRUE, multiplicative_slowdown = ((BODYTEMP_COLD_DAMAGE_LIMIT - H.bodytemperature) / COLD_SLOWDOWN_FACTOR), blacklisted_movetypes = FLOATING)
//Apply cold slowdown
H.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/cold, multiplicative_slowdown = ((BODYTEMP_COLD_DAMAGE_LIMIT - H.bodytemperature) / COLD_SLOWDOWN_FACTOR))
switch(H.bodytemperature)
if(200 to BODYTEMP_COLD_DAMAGE_LIMIT)
H.apply_damage(COLD_DAMAGE_LEVEL_1*coldmod*H.physiology.cold_mod, BURN)
@@ -2115,7 +2075,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.apply_damage(COLD_DAMAGE_LEVEL_3*coldmod*H.physiology.cold_mod, BURN)
else
H.remove_movespeed_modifier(MOVESPEED_ID_COLD)
H.remove_movespeed_modifier(/datum/movespeed_modifier/cold)
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "cold")
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "hot")
@@ -101,12 +101,11 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
/obj/item/organ/dwarfgland/on_life() //Primary loop to hook into to start delayed loops for other loops..
. = ..()
dwarf_cycle_ticker()
if(owner && owner.stat != DEAD)
dwarf_cycle_ticker()
//Handles the delayed tick cycle by just adding on increments per each on_life() tick
/obj/item/organ/dwarfgland/proc/dwarf_cycle_ticker()
if(owner.stat == DEAD)
return //We make sure they are not dead, so they don't increment any tickers.
dwarf_eth_ticker++
dwarf_filth_ticker++
@@ -91,4 +91,9 @@
if((C.dna.features["spines"] != "None" ) && (C.dna.features["tail_lizard"] == "None")) //tbh, it's kinda ugly for them not to have a tail yet have floating spines
C.dna.features["tail_lizard"] = "Smooth"
C.update_body()
if(C.dna.features["legs"] != "digitigrade")
C.dna.features["legs"] = "digitigrade"
for(var/obj/item/bodypart/leggie in C.bodyparts)
if(leggie.body_zone == BODY_ZONE_L_LEG || leggie.body_zone == BODY_ZONE_R_LEG)
leggie.update_limb(FALSE, C)
return ..()
@@ -129,16 +129,18 @@ There are several things that need to be remembered:
alt_worn = U.anthro_mob_worn_overlay || 'icons/mob/clothing/uniform_digi.dmi'
variant_flag |= STYLE_DIGITIGRADE
var/mask
if(dna.species.mutant_bodyparts["taur"])
var/datum/sprite_accessory/taur/T = GLOB.taur_list[dna.features["taur"]]
var/clip_flag = U.mutantrace_variation & T?.hide_legs
if(clip_flag)
variant_flag |= clip_flag
mask = T.alpha_mask_state
var/mutable_appearance/uniform_overlay
if(dna && dna.species.sexes)
var/G = (dna.features["body_model"] == FEMALE) ? "f" : "m"
if(G == "f" && U.fitted != NO_FEMALE_UNIFORM)
uniform_overlay = U.build_worn_icon(UNIFORM_LAYER, alt_worn, FALSE, U.fitted, target_overlay, variant_flag, FALSE)
if(!uniform_overlay)
uniform_overlay = U.build_worn_icon( UNIFORM_LAYER, alt_worn, FALSE, NO_FEMALE_UNIFORM, target_overlay, variant_flag, FALSE)
var/gendered = (dna?.species.sexes && dna.features["body_model"] == FEMALE) ? U.fitted : NO_FEMALE_UNIFORM
uniform_overlay = U.build_worn_icon( UNIFORM_LAYER, alt_worn, FALSE, gendered, target_overlay, variant_flag, FALSE, mask)
if(OFFSET_UNIFORM in dna.species.offset_features)
uniform_overlay.pixel_x += dna.species.offset_features[OFFSET_UNIFORM][1]
@@ -269,6 +271,11 @@ There are several things that need to be remembered:
var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_SHOES]
inv.update_icon()
if(dna.species.mutant_bodyparts["taur"])
var/datum/sprite_accessory/taur/T = GLOB.taur_list[dna.features["taur"]]
if(T?.hide_legs) //If only they actually made shoes unwearable. Please don't making cosmetics, guys.
return
if(shoes)
var/obj/item/clothing/shoes/S = shoes
shoes.screen_loc = ui_shoes //move the item to the appropriate screen loc
@@ -514,12 +521,17 @@ There are several things that need to be remembered:
overlays_standing[BACK_LAYER] = back_overlay
apply_overlay(BACK_LAYER)
/proc/wear_female_version(t_color, icon, layer, type)
var/index = "[t_color]-[icon]"
var/icon/female_clothing_icon = GLOB.female_clothing_icons[index]
if(!female_clothing_icon) //Create standing/laying icons if they don't exist
generate_female_clothing(index,t_color,icon,type)
return mutable_appearance(GLOB.female_clothing_icons[index], layer = -layer)
/proc/wear_alpha_masked_version(state, icon, layer, female, alpha_mask)
var/mask = "-[alpha_mask]"
if(islist(alpha_mask))
mask = "-"
for(var/t in alpha_mask)
mask += t
var/index = "[state]-[icon]-[female][mask]"
. = GLOB.alpha_masked_worn_icons[index]
if(!.) //Create standing/laying icons if they don't exist
. = generate_alpha_masked_clothing(index,state,icon,female,alpha_mask)
return mutable_appearance(., layer = -layer)
/mob/living/carbon/human/proc/get_overlays_copy(list/unwantedLayers)
var/list/out = new
@@ -574,10 +586,12 @@ generate/load female uniform sprites matching all previously decided variables
style_flags: mutant race appearance flags, mostly used for worn_overlays()
alpha_mask: a text string or list of text, the actual icons are stored in a global list and associated with said text string(s).
use_mob_overlay_icon: if FALSE, it will always use the default_icon_file even if mob_overlay_icon is present.
*/
/obj/item/proc/build_worn_icon(default_layer = 0, default_icon_file = null, isinhands = FALSE, femaleuniform = NO_FEMALE_UNIFORM, override_state, style_flags = NONE, use_mob_overlay_icon = TRUE)
/obj/item/proc/build_worn_icon(default_layer = 0, default_icon_file = null, isinhands = FALSE, femaleuniform = NO_FEMALE_UNIFORM, override_state, style_flags = NONE, use_mob_overlay_icon = TRUE, alpha_mask)
var/t_state
t_state = override_state || item_state || icon_state
@@ -597,8 +611,8 @@ use_mob_overlay_icon: if FALSE, it will always use the default_icon_file even if
layer2use = default_layer
var/mutable_appearance/standing
if(femaleuniform)
standing = wear_female_version(t_state,file2use,layer2use,femaleuniform)
if(femaleuniform || alpha_mask)
standing = wear_alpha_masked_version(t_state, file2use, layer2use, femaleuniform, alpha_mask)
if(!standing)
standing = mutable_appearance(file2use, t_state, -layer2use)
@@ -661,19 +675,17 @@ use_mob_overlay_icon: if FALSE, it will always use the default_icon_file even if
. += "-[dna.features["body_model"]]"
var/is_taur = FALSE
if(dna.species.mutant_bodyparts["taur"] && dna.features["taur"] != "None")
is_taur = TRUE
if(dna.species.mutant_bodyparts["taur"])
var/datum/sprite_accessory/taur/T = GLOB.taur_list[dna.features["taur"]]
if(T?.hide_legs)
is_taur = TRUE
var/static/list/leg_day = typecacheof(list(/obj/item/bodypart/r_leg, /obj/item/bodypart/l_leg))
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
if(istype(BP, /obj/item/bodypart/r_leg) || istype(BP, /obj/item/bodypart/l_leg))
if(is_taur)
continue
if(is_taur && leg_day[BP.type])
continue
. += "-[BP.body_zone]"
if(BP.status == BODYPART_ORGANIC)
@@ -111,7 +111,7 @@
if(pickupTarget)
if(restrained() || blacklistItems[pickupTarget] || HAS_TRAIT(pickupTarget, TRAIT_NODROP))
pickupTarget = null
else
else if(!isobj(loc) || istype(loc, /obj/item/clothing/head/mob_holder))
pickupTimer++
if(pickupTimer >= 4)
blacklistItems[pickupTarget] ++
@@ -126,10 +126,8 @@
pickupTarget = null
pickupTimer = 0
else if(ismob(pickupTarget.loc)) // in someones hand
if(istype(pickupTarget, /obj/item/clothing/head/mob_holder/))
var/obj/item/clothing/head/mob_holder/h = pickupTarget
if(h && h.held_mob==src)
return//dont let them pickpocket themselves
if(istype(pickupTarget, /obj/item/clothing/head/mob_holder))
return//dont let them pickpocket themselves or hold other monkys.
var/mob/M = pickupTarget.loc
if(!pickpocketing)
pickpocketing = TRUE
@@ -65,20 +65,20 @@
/mob/living/carbon/monkey/on_reagent_change()
. = ..()
remove_movespeed_modifier(MOVESPEED_ID_MONKEY_REAGENT_SPEEDMOD, TRUE)
var/amount
if(reagents.has_reagent(/datum/reagent/medicine/morphine))
amount = -1
if(amount)
add_movespeed_modifier(MOVESPEED_ID_MONKEY_REAGENT_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = amount)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/monkey_reagent_speedmod, TRUE, amount)
/mob/living/carbon/monkey/updatehealth()
. = ..()
var/slow = 0
var/health_deficiency = (100 - health)
if(health_deficiency >= 45)
slow += (health_deficiency / 25)
add_movespeed_modifier(MOVESPEED_ID_MONKEY_HEALTH_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = slow)
if(!HAS_TRAIT(src, TRAIT_IGNOREDAMAGESLOWDOWN))
var/health_deficiency = (maxHealth - health)
if(health_deficiency >= 45)
slow += (health_deficiency / 25)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/monkey_health_speedmod, TRUE, slow)
/mob/living/carbon/monkey/adjust_bodytemperature(amount)
. = ..()
@@ -87,7 +87,7 @@
slow += (283.222 - bodytemperature) / 10 * 1.75
if(slow <= 0)
return
add_movespeed_modifier(MOVESPEED_ID_MONKEY_TEMPERATURE_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = amount)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/monkey_temperature_speedmod, TRUE, slow)
/mob/living/carbon/monkey/Stat()
..()
@@ -99,7 +99,6 @@
if(changeling)
stat("Chemical Storage", "[changeling.chem_charges]/[changeling.chem_storage]")
stat("Absorbed DNA", changeling.absorbedcount)
return
/mob/living/carbon/monkey/verb/removeinternal()
@@ -203,6 +203,12 @@
remove_overlay(BODYPARTS_LAYER)
var/is_taur = FALSE
if(dna?.species.mutant_bodyparts["taur"])
var/datum/sprite_accessory/taur/T = GLOB.taur_list[dna.features["taur"]]
if(T?.hide_legs)
is_taur = TRUE
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
BP.update_limb()
@@ -213,9 +219,12 @@
return
//GENERATE NEW LIMBS
var/static/list/leg_day = typecacheof(list(/obj/item/bodypart/r_leg, /obj/item/bodypart/l_leg))
var/list/new_limbs = list()
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
if(is_taur && leg_day[BP.type])
continue
new_limbs += BP.get_limb_icon()
if(new_limbs.len)
overlays_standing[BODYPARTS_LAYER] = new_limbs
+9 -1
View File
@@ -502,8 +502,16 @@
var/obj/effect/proc_holder/spell/spell = S
spell.updateButtonIcon()
//proc used to remove all immobilisation effects + reset stamina
/mob/living/proc/remove_CC(should_update_mobility = TRUE)
SetAllImmobility(0, FALSE)
setStaminaLoss(0)
SetUnconscious(0, FALSE)
if(should_update_mobility)
update_mobility()
//proc used to completely heal a mob.
/mob/living/proc/fully_heal(admin_revive = 0)
/mob/living/proc/fully_heal(admin_revive = FALSE)
restore_blood()
setToxLoss(0, 0) //zero as second argument not automatically call updatehealth().
setOxyLoss(0, 0)
+4 -2
View File
@@ -94,11 +94,13 @@
if(should_be_lying)
mobility_flags &= ~MOBILITY_STAND
setMovetype(movement_type | CRAWLING)
if(!lying) //force them on the ground
lying = pick(90, 270)
if(has_gravity() && !buckled)
playsound(src, "bodyfall", 20, 1)
else
setMovetype(movement_type & ~CRAWLING)
mobility_flags |= MOBILITY_STAND
lying = 0
@@ -161,8 +163,8 @@
if(!has_legs && has_arms < 2)
limbless_slowdown += 6 - (has_arms * 3)
if(limbless_slowdown)
add_movespeed_modifier(MOVESPEED_ID_LIVING_LIMBLESS, update=TRUE, priority=100, override=TRUE, multiplicative_slowdown=limbless_slowdown, blacklisted_movetypes = FLYING|FLOATING)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/limbless, multiplicative_slowdown = limbless_slowdown)
else
remove_movespeed_modifier(MOVESPEED_ID_LIVING_LIMBLESS, update=TRUE)
remove_movespeed_modifier(/datum/movespeed_modifier/limbless)
return mobility_flags
+6 -18
View File
@@ -38,38 +38,26 @@
sprint_stamina_cost = CONFIG_GET(number/movedelay/sprint_stamina_cost)
return ..()
/mob/living/movement_delay(ignorewalk = 0)
. = ..()
if(!CHECK_MOBILITY(src, MOBILITY_STAND))
. += 6
/// whether or not we can slide under another living mob. defaults to if we're not dense. CanPass should check "overriding circumstances" like buckled mobs/having PASSMOB flag, etc.
/mob/living/proc/can_move_under_living(mob/living/other)
return !density
/mob/living/proc/update_move_intent_slowdown()
var/mod = 0
if(m_intent == MOVE_INTENT_WALK)
mod = CONFIG_GET(number/movedelay/walk_delay)
else
mod = CONFIG_GET(number/movedelay/run_delay)
if(!isnum(mod))
mod = 1
add_movespeed_modifier(MOVESPEED_ID_MOB_WALK_RUN_CONFIG_SPEED, TRUE, 100, override = TRUE, multiplicative_slowdown = mod)
add_movespeed_modifier((m_intent == MOVE_INTENT_WALK)? /datum/movespeed_modifier/config_walk_run/walk : /datum/movespeed_modifier/config_walk_run/run)
/mob/living/proc/update_turf_movespeed(turf/open/T)
if(isopenturf(T) && !is_flying())
add_movespeed_modifier(MOVESPEED_ID_LIVING_TURF_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = T.slowdown)
if(isopenturf(T))
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/turf_slowdown, multiplicative_slowdown = T.slowdown)
else
remove_movespeed_modifier(MOVESPEED_ID_LIVING_TURF_SPEEDMOD)
remove_movespeed_modifier(/datum/movespeed_modifier/turf_slowdown)
/mob/living/proc/update_pull_movespeed()
if(pulling && isliving(pulling))
var/mob/living/L = pulling
if(drag_slowdown && L.lying && !L.buckled && grab_state < GRAB_AGGRESSIVE)
add_movespeed_modifier(MOVESPEED_ID_PRONE_DRAGGING, multiplicative_slowdown = PULL_PRONE_SLOWDOWN)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/bulky_drag, multiplicative_slowdown = PULL_PRONE_SLOWDOWN)
return
remove_movespeed_modifier(MOVESPEED_ID_PRONE_DRAGGING)
remove_movespeed_modifier(/datum/movespeed_modifier/bulky_drag)
/mob/living/canZMove(dir, turf/target)
return can_zTravel(target, dir) && (movement_type & FLYING)
+5 -1
View File
@@ -237,6 +237,10 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
deaf_message = "<span class='notice'>You can't hear yourself!</span>"
deaf_type = 2 // Since you should be able to hear yourself without looking
// Create map text prior to modifying message for goonchat
if (client?.prefs.chat_on_map && stat != UNCONSCIOUS && (client.prefs.see_chat_non_mob || ismob(speaker)) && can_hear())
create_chat_message(speaker, message_language, raw_message, spans, message_mode)
// Recompose message for AI hrefs, language incomprehension.
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source)
@@ -289,7 +293,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
//speech bubble
var/list/speech_bubble_recipients = list()
for(var/mob/M in listening)
if(M.client)
if(M.client && !M.client.prefs.chat_on_map)
speech_bubble_recipients.Add(M.client)
var/image/I = image('icons/mob/talk.dmi', src, "[bubble_type][say_test(message)]", FLY_LAYER)
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
+5 -5
View File
@@ -822,21 +822,21 @@
return get_dist(src, A) <= max(viewscale[1]*0.5,viewscale[2]*0.5)
/mob/living/silicon/ai/proc/relay_speech(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
raw_message = lang_treat(speaker, message_language, raw_message, spans, message_mode)
var/treated_message = lang_treat(speaker, message_language, raw_message, spans, message_mode)
var/start = "Relayed Speech: "
var/namepart = "[speaker.GetVoice()][speaker.get_alt_name()]"
var/hrefpart = "<a href='?src=[REF(src)];track=[html_encode(namepart)]'>"
var/jobpart
var/jobpart = "Unknown"
if (iscarbon(speaker))
var/mob/living/carbon/S = speaker
if(S.job)
jobpart = "[S.job]"
else
jobpart = "Unknown"
var/rendered = "<i><span class='game say'>[start]<span class='name'>[hrefpart][namepart] ([jobpart])</a> </span><span class='message'>[raw_message]</span></span></i>"
var/rendered = "<i><span class='game say'>[start]<span class='name'>[hrefpart][namepart] ([jobpart])</a> </span><span class='message'>[treated_message]</span></span></i>"
if (client?.prefs.chat_on_map && (client.prefs.see_chat_non_mob || ismob(speaker)))
create_chat_message(speaker, message_language, raw_message, spans, message_mode)
show_message(rendered, MSG_AUDIBLE)
/mob/living/silicon/ai/fully_replace_character_name(oldname,newname)
+2 -2
View File
@@ -273,9 +273,9 @@
/mob/living/silicon/pai/Process_Spacemove(movement_dir = 0)
. = ..()
if(!.)
add_movespeed_modifier(MOVESPEED_ID_PAI_SPACEWALK_SPEEDMOD, TRUE, 100, multiplicative_slowdown = 2)
add_movespeed_modifier(/datum/movespeed_modifier/pai_spacewalk)
return TRUE
remove_movespeed_modifier(MOVESPEED_ID_PAI_SPACEWALK_SPEEDMOD, TRUE)
remove_movespeed_modifier(/datum/movespeed_modifier/pai_spacewalk)
return TRUE
/mob/living/silicon/pai/examine(mob/user)
@@ -237,7 +237,7 @@
return
if(!CONFIG_GET(flag/disable_secborg) && GLOB.security_level < CONFIG_GET(number/minimum_secborg_alert))
to_chat(src, "<span class='notice'>NOTICE: Due to local station regulations, the security cyborg module and its variants are only available during [num2seclevel(CONFIG_GET(number/minimum_secborg_alert))] alert and greater.</span>")
to_chat(src, "<span class='notice'>NOTICE: Due to local station regulations, the security cyborg module and its variants are only available during [NUM2SECLEVEL(CONFIG_GET(number/minimum_secborg_alert))] alert and greater.</span>")
var/list/modulelist = list("Standard" = /obj/item/robot_module/standard, \
"Engineering" = /obj/item/robot_module/engineering, \
@@ -1,3 +1,5 @@
/mob/living/silicon/KnockToFloor(disarm_items = FALSE, silent = TRUE, updating = TRUE)
return
/mob/living/silicon/grippedby(mob/living/user, instant = FALSE)
return //can't upgrade a simple pull into a more aggressive grab.
@@ -61,11 +61,10 @@
"<span class='userdanger'>[M] [response_disarm] [name]!</span>", null, COMBAT_MESSAGE_RANGE)
log_combat(M, src, "disarmed")
else
var/damage = rand(15, 30)
visible_message("<span class='danger'>[M] has slashed at [src]!</span>", \
"<span class='userdanger'>[M] has slashed at [src]!</span>", null, COMBAT_MESSAGE_RANGE)
playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
attack_threshold_check(damage)
attack_threshold_check(M.meleeSlashSAPower)
log_combat(M, src, "attacked")
/mob/living/simple_animal/attack_larva(mob/living/carbon/alien/larva/L)
@@ -19,6 +19,11 @@
path_image_color = "#993299"
weather_immunities = list("lava","ash")
var/clean_time = 50 //How long do we take to clean?
var/broom = FALSE //Do we have an speed buff from a broom?
var/adv_mop = FALSE //Do we have a cleaning buff from a better mop?
var/blood = 1
var/trash = 0
var/pests = 0
@@ -75,6 +80,26 @@
to_chat(user, "<span class='warning'>Please close the access panel before locking it.</span>")
else
to_chat(user, "<span class='notice'>\The [src] doesn't seem to respect your authority.</span>")
if(istype(W, /obj/item/mop/advanced))
if(bot_core.allowed(user) && open && adv_mop == TRUE)
to_chat(user, "<span class='notice'>You replace \the [src] old mop with a new better one!</span>")
adv_mop = TRUE
clean_time = 20 //2.5 the speed!
window_name = "Automatic Station Cleaner v2.1 BETA" //New!
qdel(W)
else
to_chat(user, "<span class='notice'>\the [src] already has this mop!</span>")
if(istype(W, /obj/item/twohanded/broom))
if(bot_core.allowed(user) && open && broom == TRUE)
to_chat(user, "<span class='notice'>You add to \the [src] a broom speeding it up!</span>")
broom = TRUE
base_speed = 1 //2x faster!
qdel(W)
else
to_chat(user, "<span class='notice'>\the [src] already has a broom!</span>")
else
return ..()
@@ -221,7 +246,7 @@
icon_state = "cleanbot-c"
visible_message("<span class='notice'>[src] begins to clean up [A].</span>")
mode = BOT_CLEANING
spawn(50)
spawn(clean_time)
if(mode == BOT_CLEANING)
if(A && isturf(A.loc))
var/atom/movable/AM = A
@@ -264,6 +264,9 @@
if((last_newpatient_speak + 300) < world.time) //Don't spam these messages!
var/list/messagevoice = list("Hey, [H.name]! Hold on, I'm coming." = 'sound/voice/medbot/coming.ogg',"Wait [H.name]! I want to help!" = 'sound/voice/medbot/help.ogg',"[H.name], you appear to be injured!" = 'sound/voice/medbot/injured.ogg')
var/message = pick(messagevoice)
if(prob(1) && ISINRANGE_EX(H.getFireLoss(), 0, 20))
message = "Notices your minor burns*OwO what's this?"
messagevoice[message] = 'sound/voice/medbot/owo.ogg'
speak(message)
playsound(loc, messagevoice[message], 50, 0)
last_newpatient_speak = world.time
@@ -97,6 +97,8 @@
body_color = "brown"
icon_state = "mouse_brown"
GLOBAL_VAR(tom_existed)
//TOM IS ALIVE! SQUEEEEEEEE~K :)
/mob/living/simple_animal/mouse/brown/Tom
name = "Tom"
@@ -106,6 +108,10 @@
response_harm = "splats"
gold_core_spawnable = NO_SPAWN
/mob/living/simple_animal/mouse/brown/Tom/Initialize()
. = ..()
GLOB.tom_existed = TRUE
/obj/item/reagent_containers/food/snacks/deadmouse
name = "dead mouse"
desc = "It looks like somebody dropped the bass on it. A lizard's favorite meal."
@@ -7,7 +7,7 @@
icon_living = "carp"
icon_dead = "carp_dead"
icon_gib = "carp_gib"
threat = 0.2
threat = 0.1
mob_biotypes = MOB_ORGANIC|MOB_BEAST
speak_chance = 0
turns_per_move = 5
@@ -186,10 +186,10 @@
. = ..()
if(slowed_by_webs)
if(!(locate(/obj/structure/spider/stickyweb) in loc))
remove_movespeed_modifier(MOVESPEED_ID_TARANTULA_WEB)
remove_movespeed_modifier(/datum/movespeed_modifier/tarantula_web)
slowed_by_webs = FALSE
else if(locate(/obj/structure/spider/stickyweb) in loc)
add_movespeed_modifier(MOVESPEED_ID_TARANTULA_WEB, priority=100, multiplicative_slowdown=3)
add_movespeed_modifier(/datum/movespeed_modifier/tarantula_web)
slowed_by_webs = TRUE
//midwives are the queen of the spiders, can send messages to all them and web faster. That rare round where you get a queen spider and turn your 'for honor' players into 'r6siege' players will be a fun one.
@@ -265,4 +265,12 @@ Difficulty: Medium
desc = "The sweet blood, oh, it sings to me."
invisibility = 100
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/doom
name = "hostile-environment miner"
desc = "A miner destined to hop across dimensions for all eternity, hunting anomalous creatures."
speed = 8
move_to_delay = 8
ranged_cooldown_time = 8
dash_cooldown = 8
#undef MINER_DASH_RANGE
@@ -0,0 +1,361 @@
/*
Difficulty: Extremely Hard
*/
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner
name = "demonic-frost miner"
desc = "An extremely geared miner, driven crazy or possessed by the demonic forces here, either way a terrifying enemy."
health = 1500
maxHealth = 1500
icon_state = "demonic_miner"
icon_living = "demonic_miner"
icon = 'icons/mob/icemoon/icemoon_monsters.dmi'
attacktext = "pummels"
attack_sound = 'sound/weapons/sonic_jackhammer.ogg'
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
light_color = "#E4C7C5"
movement_type = GROUND
weather_immunities = list("snow")
speak_emote = list("roars")
armour_penetration = 100
melee_damage_lower = 10
melee_damage_upper = 10
aggro_vision_range = 18 // large vision range so combat doesn't abruptly end when someone runs a bit away
rapid_melee = 4
speed = 20
move_to_delay = 20
ranged = TRUE
crusher_loot = list(/obj/effect/decal/remains/plasma, /obj/item/crusher_trophy/ice_block_talisman)
loot = list(/obj/effect/decal/remains/plasma)
wander = FALSE
del_on_death = TRUE
blood_volume = BLOOD_VOLUME_NORMAL
deathmessage = "falls to the ground, decaying into plasma particles."
deathsound = "bodyfall"
attack_action_types = list(/datum/action/innate/megafauna_attack/frost_orbs,
/datum/action/innate/megafauna_attack/snowball_machine_gun,
/datum/action/innate/megafauna_attack/ice_shotgun)
/// Modifies the speed of the projectiles the demonic frost miner shoots out
var/projectile_speed_multiplier = 1
/// If the demonic frost miner is in its enraged state
var/enraged = FALSE
/// If the demonic frost miner is currently transforming to its enraged state
var/enraging = FALSE
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/Initialize()
. = ..()
AddComponent(/datum/component/knockback, 7, FALSE, TRUE)
AddComponent(/datum/component/lifesteal, 50)
/datum/action/innate/megafauna_attack/frost_orbs
name = "Fire Frost Orbs"
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
chosen_message = "<span class='colossus'>You are now sending out frost orbs to track in on a target.</span>"
chosen_attack_num = 1
/datum/action/innate/megafauna_attack/snowball_machine_gun
name = "Fire Snowball Machine Gun"
icon_icon = 'icons/obj/guns/energy.dmi'
button_icon_state = "kineticgun"
chosen_message = "<span class='colossus'>You are now firing a snowball machine gun at a target.</span>"
chosen_attack_num = 2
/datum/action/innate/megafauna_attack/ice_shotgun
name = "Fire Ice Shotgun"
icon_icon = 'icons/obj/guns/projectile.dmi'
button_icon_state = "shotgun"
chosen_message = "<span class='colossus'>You are now firing shotgun ice blasts.</span>"
chosen_attack_num = 3
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/OpenFire()
check_enraged()
projectile_speed_multiplier = 1 - enraged * 0.25
SetRecoveryTime(100, 100)
if(client)
switch(chosen_attack)
if(1)
frost_orbs()
if(2)
snowball_machine_gun()
if(3)
ice_shotgun()
return
var/easy_attack = prob(80 - enraged * 40)
chosen_attack = rand(1, 3)
switch(chosen_attack)
if(1)
if(easy_attack)
frost_orbs(10, 8)
else
frost_orbs(5, 16)
if(2)
if(easy_attack)
snowball_machine_gun()
else
INVOKE_ASYNC(src, .proc/ice_shotgun, 5, list(list(-180, -140, -100, -60, -20, 20, 60, 100, 140), list(-160, -120, -80, -40, 0, 40, 80, 120, 160)))
snowball_machine_gun(5 * 8, 5)
if(3)
if(easy_attack)
ice_shotgun()
else
ice_shotgun(5, list(list(0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330), list(-30, -15, 0, 15, 30)))
/obj/item/projectile/frost_orb
name = "frost orb"
icon_state = "ice_1"
damage = 20
armour_penetration = 100
speed = 10
homing_turn_speed = 30
damage_type = BURN
/obj/item/projectile/frost_orb/on_hit(atom/target, blocked = FALSE)
. = ..()
if(isturf(target) || isobj(target))
target.ex_act(EXPLODE_HEAVY)
/obj/item/projectile/snowball
name = "machine-gun snowball"
icon_state = "nuclear_particle"
damage = 5
armour_penetration = 100
speed = 4
damage_type = BRUTE
/obj/item/projectile/ice_blast
name = "ice blast"
icon_state = "ice_2"
damage = 15
armour_penetration = 100
speed = 4
damage_type = BRUTE
/obj/item/projectile/ice_blast/on_hit(atom/target, blocked = FALSE)
. = ..()
if(isturf(target) || isobj(target))
target.ex_act(EXPLODE_HEAVY)
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/ex_act(severity, target)
adjustBruteLoss(30 * severity - 120)
visible_message("<span class='danger'>[src] absorbs the explosion!</span>", "<span class='userdanger'>You absorb the explosion!</span>")
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/Goto(target, delay, minimum_distance)
if(enraging)
return
return ..()
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/MoveToTarget(list/possible_targets)
if(enraging)
return
return ..()
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/Move()
if(enraging)
return
return ..()
/// Shoots out homing frost orbs that explode into ice blast projectiles after a couple seconds
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/proc/frost_orbs(added_delay = 10, shoot_times = 8)
for(var/i in 1 to shoot_times)
var/turf/startloc = get_turf(src)
var/turf/endloc = get_turf(target)
if(!endloc)
break
var/obj/item/projectile/frost_orb/P = new(startloc)
P.preparePixelProjectile(endloc, startloc)
P.firer = src
if(target)
P.original = target
P.set_homing_target(target)
P.fire(rand(0, 360))
addtimer(CALLBACK(P, /obj/item/projectile/frost_orb/proc/orb_explosion, projectile_speed_multiplier), 20) // make the orbs home in after a second
SLEEP_CHECK_DEATH(added_delay)
SetRecoveryTime(40, 60)
/// Called when the orb is exploding, shoots out projectiles
/obj/item/projectile/frost_orb/proc/orb_explosion(projectile_speed_multiplier)
for(var/i in 0 to 5)
var/angle = i * 60
var/turf/startloc = get_turf(src)
var/turf/endloc = get_turf(original)
if(!startloc || !endloc)
break
var/obj/item/projectile/ice_blast/P = new(startloc)
P.speed *= projectile_speed_multiplier
P.preparePixelProjectile(endloc, startloc, null, angle + rand(-10, 10))
P.firer = firer
if(original)
P.original = original
P.fire()
qdel(src)
/// Shoots out snowballs with a random spread
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/proc/snowball_machine_gun(shots = 60, spread = 45)
for(var/i in 1 to shots)
var/turf/startloc = get_turf(src)
var/turf/endloc = get_turf(target)
if(!endloc)
break
var/obj/item/projectile/P = new /obj/item/projectile/snowball(startloc)
P.speed *= projectile_speed_multiplier
P.preparePixelProjectile(endloc, startloc, null, rand(-spread, spread))
P.firer = src
if(target)
P.original = target
P.fire()
SLEEP_CHECK_DEATH(1)
SetRecoveryTime(15, 15)
/// Shoots out ice blasts in a shotgun like pattern
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/proc/ice_shotgun(shots = 5, list/patterns = list(list(-40, -20, 0, 20, 40), list(-30, -10, 10, 30)))
for(var/i in 1 to shots)
var/list/pattern = patterns[i % length(patterns) + 1] // alternating patterns
for(var/spread in pattern)
var/turf/startloc = get_turf(src)
var/turf/endloc = get_turf(target)
if(!endloc)
break
var/obj/item/projectile/P = new /obj/item/projectile/ice_blast(startloc)
P.speed *= projectile_speed_multiplier
P.preparePixelProjectile(endloc, startloc, null, spread)
P.firer = src
if(target)
P.original = target
P.fire()
SLEEP_CHECK_DEATH(8)
SetRecoveryTime(15, 20)
/// Checks if the demonic frost miner is ready to be enraged
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/proc/check_enraged()
if(enraged)
return
if(health > maxHealth*0.25)
return
SetRecoveryTime(80, 80)
adjustHealth(-maxHealth)
enraged = TRUE
enraging = TRUE
animate(src, pixel_y = pixel_y + 96, time = 100, easing = ELASTIC_EASING)
spin(100, 10)
SLEEP_CHECK_DEATH(60)
playsound(src, 'sound/effects/explosion3.ogg', 100, TRUE)
icon_state = "demonic_miner_phase2"
animate(src, pixel_y = pixel_y - 96, time = 8, flags = ANIMATION_END_NOW)
spin(8, 2)
SLEEP_CHECK_DEATH(8)
for(var/mob/living/L in viewers(src))
shake_camera(L, 3, 2)
playsound(src, 'sound/effects/meteorimpact.ogg', 100, TRUE)
setMovetype(movement_type | FLYING)
enraging = FALSE
adjustHealth(-maxHealth)
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/death(gibbed, list/force_grant)
if(health > 0)
return
var/turf/T = get_turf(src)
var/loot = rand(1, 3)
switch(loot)
if(1)
new /obj/item/resurrection_crystal(T)
if(2)
new /obj/item/clothing/shoes/winterboots/ice_boots/speedy(T)
if(3)
new /obj/item/pickaxe/drill/jackhammer/demonic(T)
return ..()
/obj/item/resurrection_crystal
name = "resurrection crystal"
desc = "When used by anything holding it, this crystal gives them a second chance at life if they die."
icon = 'icons/obj/objects.dmi'
icon_state = "demonic_crystal"
/obj/item/resurrection_crystal/attack_self(mob/living/user)
if(!iscarbon(user))
to_chat(user, "<span class='notice'>A dark presence stops you from absorbing the crystal.</span>")
return
forceMove(user)
to_chat(user, "<span class='notice'>You feel a bit safer... but a demonic presence lurks in the back of your head...</span>")
RegisterSignal(user, COMSIG_MOB_DEATH, .proc/resurrect)
/// Resurrects the target when they die by cloning them into a new duplicate body and transferring their mind to the clone on a safe station turf
/obj/item/resurrection_crystal/proc/resurrect(mob/living/carbon/user, gibbed)
user.visible_message("<span class='notice'>You see [user]'s soul dragged out of their body!</span>", "<span class='notice'>You feel your soul dragged away to a fresh body!</span>")
var/typepath = user.type
var/turf/T = find_safe_turf()
var/mob/living/carbon/clone = new typepath(T)
clone.real_name = user.real_name
user.dna.transfer_identity(clone)
clone.updateappearance(mutcolor_update=1)
user.mind.transfer_to(clone) // second life
to_chat(clone, "<span class='notice'>You blink and find yourself in [get_area_name(T)].</span>")
user.gib()
qdel(src)
/obj/item/clothing/shoes/winterboots/ice_boots/speedy
name = "cursed ice hiking boots"
desc = "A pair of winter boots contractually made by a devil, they cannot be taken off once put on."
slowdown = SHOES_SPEED_SLIGHT
/obj/item/clothing/shoes/winterboots/ice_boots/speedy/Initialize()
. = ..()
ADD_TRAIT(src, TRAIT_NODROP, CURSED_ITEM_TRAIT)
/obj/item/pickaxe/drill/jackhammer/demonic
name = "demonic jackhammer"
desc = "Cracks rocks at an inhuman speed, as well as being enhanced for combat purposes."
toolspeed = 0
/obj/item/pickaxe/drill/jackhammer/demonic/Initialize()
. = ..()
AddComponent(/datum/component/knockback, 4, FALSE, TRUE)
AddComponent(/datum/component/lifesteal, 5)
/obj/item/crusher_trophy/ice_block_talisman
name = "ice block talisman"
desc = "A glowing trinket that a demonic miner had on him, it seems he couldn't utilize it for whatever reason."
icon_state = "ice_trap_talisman"
denied_type = /obj/item/crusher_trophy/ice_block_talisman
/obj/item/crusher_trophy/ice_block_talisman/effect_desc()
return "mark detonation to freeze a creature in a block of ice for a period, preventing them from moving"
/obj/item/crusher_trophy/ice_block_talisman/on_mark_detonation(mob/living/target, mob/living/user)
target.apply_status_effect(/datum/status_effect/ice_block_talisman)
/datum/status_effect/ice_block_talisman
id = "ice_block_talisman"
duration = 25
status_type = STATUS_EFFECT_REFRESH
alert_type = /obj/screen/alert/status_effect/ice_block_talisman
/// Stored icon overlay for the hit mob, removed when effect is removed
var/icon/cube
/obj/screen/alert/status_effect/ice_block_talisman
name = "Frozen Solid"
desc = "You're frozen inside an ice cube, and cannot move!"
icon_state = "frozen"
/datum/status_effect/ice_block_talisman/on_apply()
RegisterSignal(owner, COMSIG_MOVABLE_PRE_MOVE, .proc/owner_moved)
if(!owner.stat)
to_chat(owner, "<span class='userdanger'>You become frozen in a cube!</span>")
cube = icon('icons/effects/freeze.dmi', "ice_cube")
var/icon/size_check = icon(owner.icon, owner.icon_state)
cube.Scale(size_check.Width(), size_check.Height())
owner.add_overlay(cube)
return ..()
/// Blocks movement from the status effect owner
/datum/status_effect/ice_block_talisman/proc/owner_moved()
return COMPONENT_MOVABLE_BLOCK_PRE_MOVE
/datum/status_effect/ice_block_talisman/on_remove()
. = ..()
if(!owner.stat)
to_chat(owner, "<span class='notice'>The cube melts!</span>")
owner.cut_overlay(cube)
UnregisterSignal(owner, COMSIG_MOVABLE_PRE_MOVE)
@@ -394,3 +394,26 @@ Difficulty: Medium
/mob/living/simple_animal/hostile/megafauna/dragon/lesser/grant_achievement(medaltype,scoretype)
return
//fire line keeps going even if dragon is deleted
/proc/dragon_fire_line(source, list/turfs)
var/list/hit_list = list()
for(var/turf/T in turfs)
if(istype(T, /turf/closed))
break
new /obj/effect/hotspot(T)
T.hotspot_expose(700,50,1)
for(var/mob/living/L in T.contents)
if(L in hit_list || L == source)
continue
hit_list += L
L.adjustFireLoss(20)
to_chat(L, "<span class='userdanger'>You're hit by [source]'s fire breath!</span>")
// deals damage to mechs
for(var/obj/mecha/M in T.contents)
if(M in hit_list)
continue
hit_list += M
M.take_damage(45, BRUTE, "melee", 1)
sleep(1.5)
@@ -27,23 +27,51 @@
mob_size = MOB_SIZE_LARGE
layer = LARGE_MOB_LAYER //Looks weird with them slipping under mineral walls and cameras and shit otherwise
flags_1 = PREVENT_CONTENTS_EXPLOSION_1 | HEAR_1
/// Crusher loot dropped when fauna killed with a crusher
var/list/crusher_loot
var/medal_type
/// Score given to players when the fauna is killed
var/score_type = BOSS_SCORE
/// If the megafauna is actually killed (vs entering another phase)
var/elimination = 0
/// Modifies attacks when at lower health
var/anger_modifier = 0
/// Internal tracking GPS inside fauna
var/obj/item/gps/internal
/// Next time fauna can use a melee attack
var/recovery_time = 0
var/true_spawn = TRUE // if this is a megafauna that should grant achievements, or have a gps signal
var/nest_range = 10
var/chosen_attack = 1 // chosen attack num
var/list/attack_action_types = list()
var/small_sprite_type
/mob/living/simple_animal/hostile/megafauna/Initialize(mapload)
. = ..()
apply_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
ADD_TRAIT(src, TRAIT_NO_TELEPORT, MEGAFAUNA_TRAIT)
for(var/action_type in attack_action_types)
var/datum/action/innate/megafauna_attack/attack_action = new action_type()
attack_action.Grant(src)
if(small_sprite_type)
var/datum/action/small_sprite/small_action = new small_sprite_type()
small_action.Grant(src)
/mob/living/simple_animal/hostile/megafauna/Destroy()
QDEL_NULL(internal)
. = ..()
/mob/living/simple_animal/hostile/megafauna/Moved()
if(nest && nest.parent && get_dist(nest.parent, src) > nest_range)
var/turf/closest = get_turf(nest.parent)
for(var/i = 1 to nest_range)
closest = get_step(closest, get_dir(closest, src))
forceMove(closest) // someone teleported out probably and the megafauna kept chasing them
target = null
return
return ..()
/mob/living/simple_animal/hostile/megafauna/death(gibbed)
if(health > 0)
return
@@ -134,3 +162,21 @@
SSmedals.SetScore(BOSS_SCORE, C, 1)
SSmedals.SetScore(score_type, C, 1)
return TRUE
/datum/action/innate/megafauna_attack
name = "Megafauna Attack"
icon_icon = 'icons/mob/actions/actions_animal.dmi'
button_icon_state = ""
var/mob/living/simple_animal/hostile/megafauna/M
var/chosen_message
var/chosen_attack_num = 0
/datum/action/innate/megafauna_attack/Grant(mob/living/L)
if(istype(L, /mob/living/simple_animal/hostile/megafauna))
M = L
return ..()
return FALSE
/datum/action/innate/megafauna_attack/Activate()
M.chosen_attack = chosen_attack_num
to_chat(M, chosen_message)
@@ -0,0 +1,201 @@
/*
Difficulty: Hard
*/
/mob/living/simple_animal/hostile/megafauna/wendigo
name = "wendigo"
desc = "A mythological man-eating legendary creature, you probably aren't going to survive this."
health = 2500
maxHealth = 2500
icon_state = "wendigo"
icon_living = "wendigo"
icon_dead = "wendigo_dead"
icon = 'icons/mob/icemoon/64x64megafauna.dmi'
attacktext = "claws"
attack_sound = 'sound/magic/demon_attack1.ogg'
weather_immunities = list("snow")
speak_emote = list("roars")
armour_penetration = 40
melee_damage_lower = 40
melee_damage_upper = 40
vision_range = 9
aggro_vision_range = 18 // man-eating for a reason
speed = 8
move_to_delay = 8
rapid_melee = 16 // every 1/8 second
melee_queue_distance = 20 // as far as possible really, need this because of charging and teleports
ranged = TRUE
pixel_x = -16
loot = list(/obj/item/wendigo_blood)
crusher_loot = list(/obj/item/wendigo_blood, /obj/item/crusher_trophy/demon_claws)
wander = FALSE
del_on_death = TRUE
blood_volume = BLOOD_VOLUME_NORMAL
deathmessage = "falls, shaking the ground around it"
deathsound = 'sound/effects/gravhit.ogg'
attack_action_types = list(/datum/action/innate/megafauna_attack/heavy_stomp,
/datum/action/innate/megafauna_attack/teleport,
/datum/action/innate/megafauna_attack/disorienting_scream)
/// Saves the turf the megafauna was created at (spawns exit portal here)
var/turf/starting
/// Range for wendigo stomping when it moves
var/stomp_range = 1
/// Stores directions the mob is moving, then calls that a move has fully ended when these directions are removed in moved
var/stored_move_dirs = 0
/// If the wendigo is allowed to move
var/can_move = TRUE
/datum/action/innate/megafauna_attack/heavy_stomp
name = "Heavy Stomp"
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
chosen_message = "<span class='colossus'>You are now stomping the ground around you.</span>"
chosen_attack_num = 1
/datum/action/innate/megafauna_attack/teleport
name = "Teleport"
icon_icon = 'icons/effects/bubblegum.dmi'
button_icon_state = "smack ya one"
chosen_message = "<span class='colossus'>You are now teleporting at the target you click on.</span>"
chosen_attack_num = 2
/datum/action/innate/megafauna_attack/disorienting_scream
name = "Disorienting Scream"
icon_icon = 'icons/turf/walls/wall.dmi'
button_icon_state = "wall"
chosen_message = "<span class='colossus'>You are now screeching, disorienting targets around you.</span>"
chosen_attack_num = 3
/mob/living/simple_animal/hostile/megafauna/wendigo/Initialize()
. = ..()
starting = get_turf(src)
/mob/living/simple_animal/hostile/megafauna/wendigo/OpenFire()
SetRecoveryTime(0, 100)
if(health <= maxHealth*0.5)
stomp_range = 2
speed = 6
move_to_delay = 6
else
stomp_range = initial(stomp_range)
speed = initial(speed)
move_to_delay = initial(move_to_delay)
if(client)
switch(chosen_attack)
if(1)
heavy_stomp()
if(2)
teleport()
if(3)
disorienting_scream()
return
chosen_attack = rand(1, 3)
switch(chosen_attack)
if(1)
heavy_stomp()
if(2)
teleport()
if(3)
disorienting_scream()
/mob/living/simple_animal/hostile/megafauna/wendigo/Move(atom/newloc, direct)
if(!can_move)
return
stored_move_dirs |= direct
return ..()
/mob/living/simple_animal/hostile/megafauna/wendigo/Moved(atom/oldloc, direct)
. = ..()
stored_move_dirs &= ~direct
if(!stored_move_dirs)
INVOKE_ASYNC(src, .proc/ground_slam, stomp_range, 1)
/// Slams the ground around the wendigo throwing back enemies caught nearby
/mob/living/simple_animal/hostile/megafauna/wendigo/proc/ground_slam(range, delay)
var/turf/orgin = get_turf(src)
var/list/all_turfs = RANGE_TURFS(range, orgin)
for(var/i = 0 to range)
for(var/turf/T in all_turfs)
if(get_dist(orgin, T) > i)
continue
playsound(T,'sound/effects/bamf.ogg', 600, TRUE, 10)
new /obj/effect/temp_visual/small_smoke/halfsecond(T)
for(var/mob/living/L in T)
if(L == src || L.throwing)
continue
to_chat(L, "<span class='userdanger'>[src]'s ground slam shockwave sends you flying!</span>")
var/turf/thrownat = get_ranged_target_turf_direct(src, L, 8, rand(-10, 10))
L.throw_at(thrownat, 8, 2, src, TRUE) //, force = MOVE_FORCE_OVERPOWERING, gentle = TRUE)
L.apply_damage(20, BRUTE)
shake_camera(L, 2, 1)
all_turfs -= T
sleep(delay)
/// Larger but slower ground stomp
/mob/living/simple_animal/hostile/megafauna/wendigo/proc/heavy_stomp()
can_move = FALSE
ground_slam(5, 2)
SetRecoveryTime(0, 0)
can_move = TRUE
/// Teleports to a location 4 turfs away from the enemy in view
/mob/living/simple_animal/hostile/megafauna/wendigo/proc/teleport()
var/list/possible_ends = list()
for(var/turf/T in view(4, target.loc) - view(3, target.loc))
if(isclosedturf(T))
continue
possible_ends |= T
var/turf/end = pick(possible_ends)
do_teleport(src, end, 0, channel=TELEPORT_CHANNEL_BLUESPACE, forced = TRUE)
SetRecoveryTime(20, 0)
/// Shakes all nearby enemies screens and animates the wendigo shaking up and down
/mob/living/simple_animal/hostile/megafauna/wendigo/proc/disorienting_scream()
can_move = FALSE
playsound(src, 'sound/magic/demon_dies.ogg', 600, FALSE, 10)
animate(src, pixel_z = rand(5, 15), time = 1, loop = 6)
animate(pixel_z = 0, time = 1)
for(var/mob/living/L in get_hearers_in_view(7, src) - src)
shake_camera(L, 30, 1)
to_chat(L, "<span class='danger'>The wendigo screams loudly!</span>")
SetRecoveryTime(30, 0)
SLEEP_CHECK_DEATH(12)
can_move = TRUE
return
/mob/living/simple_animal/hostile/megafauna/wendigo/death(gibbed, list/force_grant)
if(health > 0)
return
var/obj/effect/portal/permanent/one_way/exit = new /obj/effect/portal/permanent/one_way(starting)
exit.id = "wendigo arena exit"
exit.add_atom_colour(COLOR_RED_LIGHT, ADMIN_COLOUR_PRIORITY)
exit.set_light(20, 1, LIGHT_COLOR_RED)
return ..()
/obj/item/wendigo_blood
name = "bottle of wendigo blood"
desc = "You're not actually going to drink this, are you?"
icon = 'icons/obj/wizard.dmi'
icon_state = "vial"
/obj/item/wendigo_blood/attack_self(mob/living/user)
if(!ishuman(user))
return
var/mob/living/carbon/human/H = user
if(!H.mind)
return
to_chat(H, "<span class='danger'>Power courses through you! You can now shift your form at will.</span>")
var/obj/effect/proc_holder/spell/targeted/shapeshift/polar_bear/P = new
H.mind.AddSpell(P)
playsound(H.loc,'sound/items/drink.ogg', rand(10,50), TRUE)
qdel(src)
/obj/effect/proc_holder/spell/targeted/shapeshift/polar_bear
name = "Polar Bear Form"
desc = "Take on the shape of a polar bear."
invocation = "RAAAAAAAAWR!"
convert_damage = FALSE
shapeshift_type = /mob/living/simple_animal/hostile/asteroid/polarbear
@@ -424,3 +424,29 @@
l_pocket = /obj/item/reagent_containers/food/drinks/soda_cans/buzz_fuzz
mask = /obj/item/clothing/mask/rat/bee
. = ..()
// Snow Legion
/mob/living/simple_animal/hostile/asteroid/hivelord/legion/snow
name = "snow legion"
desc = "You can still see what was once a human under the shifting snowy mass, clearly decorated by a clown."
icon = 'icons/mob/icemoon/icemoon_monsters.dmi'
icon_state = "snowlegion"
icon_living = "snowlegion"
icon_aggro = "snowlegion_alive"
icon_dead = "snowlegion"
crusher_loot = /obj/item/crusher_trophy/legion_skull
loot = list(/obj/item/organ/regenerative_core/legion)
brood_type = /mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/snow
/mob/living/simple_animal/hostile/asteroid/hivelord/legion/snow/tendril
fromtendril = TRUE
// Snow Legion skull
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/snow
name = "snow legion"
desc = "One of many."
icon = 'icons/mob/icemoon/icemoon_monsters.dmi'
icon_state = "snowlegion_head"
icon_living = "snowlegion_head"
icon_aggro = "snowlegion_head"
icon_dead = "snowlegion_head"
@@ -0,0 +1,76 @@
/mob/living/simple_animal/hostile/asteroid/ice_demon
name = "demonic watcher"
desc = "A creature formed entirely out of ice, bluespace energy emanates from inside of it."
icon = 'icons/mob/icemoon/icemoon_monsters.dmi'
icon_state = "ice_demon"
icon_living = "ice_demon"
icon_dead = "ice_demon_dead"
icon_gib = "syndicate_gib"
mob_biotypes = MOB_ORGANIC|MOB_BEAST
mouse_opacity = MOUSE_OPACITY_ICON
speak_emote = list("telepathically cries")
speed = 2
move_to_delay = 2
projectiletype = /obj/item/projectile/temp/basilisk/ice
projectilesound = 'sound/weapons/pierce.ogg'
ranged = TRUE
ranged_message = "manifests ice"
ranged_cooldown_time = 30
minimum_distance = 3
retreat_distance = 3
maxHealth = 150
health = 150
obj_damage = 40
melee_damage_lower = 15
melee_damage_upper = 15
attacktext = "slices"
attack_sound = 'sound/weapons/bladeslice.ogg'
vision_range = 9
aggro_vision_range = 9
move_force = MOVE_FORCE_VERY_STRONG
move_resist = MOVE_FORCE_VERY_STRONG
pull_force = MOVE_FORCE_VERY_STRONG
del_on_death = TRUE
loot = list(/obj/item/stack/ore/bluespace_crystal = 3)
crusher_loot = /obj/item/crusher_trophy/watcher_wing/ice_wing
deathmessage = "fades as the energies that tied it to this world dissipate."
deathsound = 'sound/magic/demon_dies.ogg'
stat_attack = UNCONSCIOUS
movement_type = FLYING
robust_searching = TRUE
/// Distance the demon will teleport from the target
var/teleport_distance = 3
/obj/item/projectile/temp/basilisk/ice
name = "ice blast"
damage = 5
nodamage = FALSE
temperature = -75
/mob/living/simple_animal/hostile/asteroid/ice_demon/OpenFire()
if(teleport_distance <= 0)
return ..()
var/list/possible_ends = list()
for(var/turf/T in view(teleport_distance, target.loc) - view(teleport_distance - 1, target.loc))
if(isclosedturf(T))
continue
possible_ends |= T
var/turf/end = pick(possible_ends)
do_teleport(src, end, 0, channel=TELEPORT_CHANNEL_BLUESPACE, forced = TRUE)
SLEEP_CHECK_DEATH(8)
return ..()
/mob/living/simple_animal/hostile/asteroid/ice_demon/Life()
. = ..()
if(!. || target)
return
adjustHealth(-maxHealth*0.025)
/mob/living/simple_animal/hostile/asteroid/ice_demon/death(gibbed)
move_force = MOVE_FORCE_DEFAULT
move_resist = MOVE_RESIST_DEFAULT
pull_force = PULL_FORCE_DEFAULT
var/turf/T = get_turf(src)
if(T && prob(5))
new /obj/item/assembly/signaler/anomaly/bluespace(T)
return ..()
@@ -0,0 +1,54 @@
/mob/living/simple_animal/hostile/asteroid/ice_whelp
name = "ice whelp"
desc = "The offspring of an ice drake, weak in comparison but still terrifying."
icon = 'icons/mob/icemoon/icemoon_monsters.dmi'
icon_state = "ice_whelp"
icon_living = "ice_whelp"
icon_dead = "ice_whelp_dead"
mob_biotypes = MOB_ORGANIC|MOB_BEAST
mouse_opacity = MOUSE_OPACITY_ICON
friendly = "stares down"
speak_emote = list("roars")
speed = 30
move_to_delay = 30
ranged = TRUE
ranged_cooldown_time = 40
maxHealth = 350
health = 350
obj_damage = 40
armour_penetration = 20
melee_damage_lower = 20
melee_damage_upper = 20
attacktext = "chomps"
attack_sound = 'sound/magic/demon_attack1.ogg'
vision_range = 9
aggro_vision_range = 9
move_force = MOVE_FORCE_VERY_STRONG
move_resist = MOVE_FORCE_VERY_STRONG
pull_force = MOVE_FORCE_VERY_STRONG
butcher_results = list(/obj/item/stack/ore/diamond = 3, /obj/item/stack/sheet/sinew = 2, /obj/item/stack/sheet/bone = 10, /obj/item/stack/sheet/animalhide/ashdrake = 1)
loot = list()
crusher_loot = /obj/item/crusher_trophy/tail_spike
deathmessage = "collapses on it's side."
deathsound = 'sound/magic/demon_dies.ogg'
stat_attack = UNCONSCIOUS
robust_searching = TRUE
/// How far the whelps fire can go
var/fire_range = 4
/mob/living/simple_animal/hostile/asteroid/ice_whelp/OpenFire()
var/turf/T = get_ranged_target_turf_direct(src, target, fire_range)
var/list/burn_turfs = getline(src, T) - get_turf(src)
dragon_fire_line(src, burn_turfs)
/mob/living/simple_animal/hostile/asteroid/ice_whelp/Life()
. = ..()
if(!. || target)
return
adjustHealth(-maxHealth*0.025)
/mob/living/simple_animal/hostile/asteroid/ice_whelp/death(gibbed)
move_force = MOVE_FORCE_DEFAULT
move_resist = MOVE_RESIST_DEFAULT
pull_force = PULL_FORCE_DEFAULT
return ..()
@@ -28,7 +28,7 @@
/mob/living/simple_animal/hostile/asteroid/Aggro()
..()
if(vision_range != aggro_vision_range)
if(vision_range == aggro_vision_range && icon_aggro)
icon_state = icon_aggro
/mob/living/simple_animal/hostile/asteroid/LoseAggro()
@@ -0,0 +1,56 @@
/mob/living/simple_animal/hostile/asteroid/polarbear
name = "polar bear"
desc = "An aggressive animal that defends it's territory with incredible power. These beasts don't run from their enemies."
icon = 'icons/mob/icemoon/icemoon_monsters.dmi'
icon_state = "polarbear"
icon_living = "polarbear"
icon_dead = "polarbear_dead"
mob_biotypes = MOB_ORGANIC|MOB_BEAST
mouse_opacity = MOUSE_OPACITY_ICON
friendly = "growls at"
speak_emote = list("growls")
speed = 12
move_to_delay = 12
maxHealth = 300
health = 300
obj_damage = 40
melee_damage_lower = 25
melee_damage_upper = 25
attacktext = "claws"
attack_sound = 'sound/weapons/bladeslice.ogg'
vision_range = 2 // don't aggro unless you basically antagonize it, though they will kill you worse than a goliath will
aggro_vision_range = 9
move_force = MOVE_FORCE_VERY_STRONG
move_resist = MOVE_FORCE_VERY_STRONG
pull_force = MOVE_FORCE_VERY_STRONG
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/bear = 3, /obj/item/stack/sheet/bone = 2)
guaranteed_butcher_results = list(/obj/item/stack/sheet/animalhide/goliath_hide/polar_bear_hide = 1)
loot = list()
crusher_loot = /obj/item/crusher_trophy/goliath_tentacle
stat_attack = UNCONSCIOUS
robust_searching = TRUE
/// Message for when the polar bear starts to attack faster
var/aggressive_message_said = FALSE
/mob/living/simple_animal/hostile/asteroid/polarbear/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
. = ..()
if(health > maxHealth*0.5)
rapid_melee = initial(rapid_melee)
return
if(!aggressive_message_said && target)
visible_message("<span class='danger'>The [name] gets an enraged look at [target]!</span>")
aggressive_message_said = TRUE
rapid_melee = 2
/mob/living/simple_animal/hostile/asteroid/polarbear/Life()
. = ..()
if(!. || target)
return
adjustHealth(-maxHealth*0.025)
aggressive_message_said = FALSE
/mob/living/simple_animal/hostile/asteroid/polarbear/death(gibbed)
move_force = MOVE_FORCE_DEFAULT
move_resist = MOVE_RESIST_DEFAULT
pull_force = PULL_FORCE_DEFAULT
return ..()
@@ -0,0 +1,57 @@
/mob/living/simple_animal/hostile/asteroid/wolf
name = "white wolf"
desc = "A beast that survives by feasting on weaker opponents, they're much stronger with numbers."
icon = 'icons/mob/icemoon/icemoon_monsters.dmi'
icon_state = "whitewolf"
icon_living = "whitewolf"
icon_dead = "whitewolf_dead"
mob_biotypes = MOB_ORGANIC|MOB_BEAST
mouse_opacity = MOUSE_OPACITY_ICON
friendly = "howls at"
speak_emote = list("howls")
speed = 5
move_to_delay = 5
maxHealth = 130
health = 130
obj_damage = 15
melee_damage_lower = 7.5
melee_damage_upper = 7.5
rapid_melee = 2 // every second attack
dodging = TRUE
dodge_prob = 50
attacktext = "bites"
attack_sound = 'sound/weapons/bite.ogg'
vision_range = 7
aggro_vision_range = 7
move_force = MOVE_FORCE_WEAK
move_resist = MOVE_FORCE_WEAK
pull_force = MOVE_FORCE_WEAK
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 2, /obj/item/stack/sheet/sinew/wolf = 2, /obj/item/stack/sheet/bone = 2)
loot = list()
crusher_loot = /obj/item/crusher_trophy/watcher_wing
stat_attack = UNCONSCIOUS
robust_searching = TRUE
/// Message for when the wolf decides to start running away
var/retreat_message_said = FALSE
/mob/living/simple_animal/hostile/asteroid/wolf/Move(atom/newloc)
if(newloc && newloc.z == z && (islava(newloc) || ischasm(newloc)))
return FALSE
return ..()
/mob/living/simple_animal/hostile/asteroid/wolf/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
. = ..()
if(stat == DEAD || health > maxHealth*0.1)
retreat_distance = initial(retreat_distance)
return
if(!retreat_message_said && target)
visible_message("<span class='danger'>The [name] tries to flee from [target]!</span>")
retreat_message_said = TRUE
retreat_distance = 30
/mob/living/simple_animal/hostile/asteroid/wolf/Life()
. = ..()
if(!. || target)
return
adjustHealth(-maxHealth*0.025)
retreat_message_said = FALSE
@@ -1,14 +1,13 @@
/mob/living/simple_animal/hostile/retaliate/clown
name = "Clown"
desc = "A denizen of clown planet."
icon = 'icons/mob/simple_human.dmi'
icon = 'icons/mob/clown_mobs.dmi'
icon_state = "clown"
icon_living = "clown"
icon_dead = "clown_dead"
icon_gib = "clown_gib"
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
turns_per_move = 5
response_help = "pokes"
response_disarm = "gently pushes aside"
response_harm = "robusts"
speak = list("HONK", "Honk!", "Welcome to clown planet!")
@@ -21,7 +20,6 @@
harm_intent_damage = 8
melee_damage_lower = 10
melee_damage_upper = 10
attacktext = "attacks"
attack_sound = 'sound/items/bikehorn.ogg'
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
@@ -32,15 +30,245 @@
minbodytemp = 270
maxbodytemp = 370
unsuitable_atmos_damage = 10
do_footstep = TRUE
var/banana_time = 0 // If there's no time set it won't spawn.
var/banana_type = /obj/item/grown/bananapeel
var/attack_reagent
/mob/living/simple_animal/hostile/retaliate/clown/handle_temperature_damage()
if(bodytemperature < minbodytemp)
adjustBruteLoss(10)
throw_alert("temp", /obj/screen/alert/cold, 2)
else if(bodytemperature > maxbodytemp)
adjustBruteLoss(15)
throw_alert("temp", /obj/screen/alert/hot, 3)
else
clear_alert("temp")
/mob/living/simple_animal/hostile/retaliate/clown/attack_hand(mob/living/carbon/human/M)
..()
playsound(src.loc, 'sound/items/bikehorn.ogg', 50, 1)
playsound(src.loc, 'sound/items/bikehorn.ogg', 50, TRUE)
/mob/living/simple_animal/hostile/retaliate/clown/Life()
. = ..()
if(banana_time && banana_time < world.time)
var/turf/T = get_turf(src)
var/list/adjacent = T.GetAtmosAdjacentTurfs(1)
new banana_type(pick(adjacent))
banana_time = world.time + rand(30,60)
/mob/living/simple_animal/hostile/retaliate/clown/AttackingTarget()
. = ..()
if(attack_reagent && . && isliving(target))
var/mob/living/L = target
if(L.reagents)
L.reagents.add_reagent(attack_reagent, rand(1,5))
/mob/living/simple_animal/hostile/retaliate/clown/lube
name = "Living Lube"
desc = "A puddle of lube brought to life by the honkmother."
icon_state = "lube"
icon_living = "lube"
turns_per_move = 1
response_help = "dips a finger into"
response_disarm = "gently scoops and pours aside"
emote_see = list("bubbles", "oozes")
loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/particle_effect/foam)
/mob/living/simple_animal/hostile/retaliate/clown/lube/Initialize()
. = ..()
AddElement(/datum/element/snailcrawl)
/mob/living/simple_animal/hostile/retaliate/clown/banana
name = "Clownana"
desc = "A fusion of clown and banana DNA birthed from a botany experiment gone wrong."
icon_state = "banana tree"
icon_living = "banana tree"
response_disarm = "peels"
response_harm = "peels"
turns_per_move = 1
speak = list("HONK", "Honk!", "YA-HONK!!!")
emote_see = list("honks", "bites into the banana", "plucks a banana off its head", "photosynthesizes")
maxHealth = 120
health = 120
speed = -10
loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap, /obj/item/seeds/banana)
banana_time = 20
/mob/living/simple_animal/hostile/retaliate/clown/honkling
name = "Honkling"
desc = "A divine being sent by the Honkmother to spread joy. It's not dangerous, but it's a bit of a nuisance."
icon_state = "honkling"
icon_living = "honkling"
turns_per_move = 1
speed = -10
harm_intent_damage = 1
melee_damage_lower = 1
melee_damage_upper = 1
attacktext = "cheers up"
loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap, /obj/item/seeds/banana/bluespace)
banana_type = /obj/item/grown/bananapeel
attack_reagent = /datum/reagent/consumable/laughter
/mob/living/simple_animal/hostile/retaliate/clown/fleshclown
name = "Fleshclown"
desc = "A being forged out of the pure essence of pranking, cursed into existence by a cruel maker."
icon_state = "fleshclown"
icon_living = "fleshclown"
response_help = "reluctantly pokes"
response_disarm = "sinks his hands into the spongy flesh of"
response_harm = "cleanses the world of"
speak = list("HONK", "Honk!", "I didn't ask for this", "I feel constant and horrible pain", "YA-HONK!!!", "this body is a merciless and unforgiving prison", "I was born out of mirthful pranking but I live in suffering")
emote_see = list("honks", "sweats", "jiggles", "contemplates its existence")
speak_chance = 5
dextrous = TRUE
ventcrawler = VENTCRAWLER_ALWAYS
maxHealth = 140
health = 140
speed = -5
melee_damage_upper = 15
attacktext = "limply slaps"
obj_damage = 5
loot = list(/obj/item/clothing/suit/hooded/bloated_human, /obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap)
/mob/living/simple_animal/hostile/retaliate/clown/longface
name = "Longface"
desc = "Often found walking into the bar."
icon_state = "long face"
icon_living = "long face"
move_resist = INFINITY
turns_per_move = 10
response_help = "tries to awkwardly hug"
response_disarm = "pushes the unwieldy frame of"
response_harm = "tries to shut up"
speak = list("YA-HONK!!!")
emote_see = list("honks", "squeaks")
speak_chance = 60
maxHealth = 150
health = 150
pixel_x = -16
speed = 10
harm_intent_damage = 5
melee_damage_lower = 5
attacktext = "YA-HONKs"
loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap)
/mob/living/simple_animal/hostile/retaliate/clown/clownhulk
name = "Honk Hulk"
desc = "A cruel and fearsome clown. Don't make him angry."
icon_state = "honkhulk"
icon_living = "honkhulk"
move_resist = INFINITY
response_help = "tries desperately to appease"
response_disarm = "foolishly pushes"
response_harm = "angers"
speak = list("HONK", "Honk!", "HAUAUANK!!!", "GUUURRRRAAAHHH!!!")
emote_see = list("honks", "sweats", "grunts")
speak_chance = 5
maxHealth = 400
health = 400
pixel_x = -16
speed = 2
harm_intent_damage = 15
melee_damage_lower = 15
melee_damage_upper = 20
attacktext = "pummels"
obj_damage = 30
environment_smash = ENVIRONMENT_SMASH_WALLS
loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap)
/mob/living/simple_animal/hostile/retaliate/clown/clownhulk/chlown
name = "Chlown"
desc = "A real lunkhead who somehow gets all the girls."
icon_state = "chlown"
icon_living = "chlown"
response_help = "submits to"
response_disarm = "tries to assert dominance over"
response_harm = "makes a weak beta attack at"
speak = list("HONK", "Honk!", "Bruh", "cheeaaaahhh?")
emote_see = list("asserts his dominance", "emasculates everyone implicitly")
maxHealth = 500
health = 500
speed = -2
armour_penetration = 20
attacktext = "steals the girlfriend of"
attack_sound = 'sound/items/airhorn2.ogg'
loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/effect/particle_effect/foam, /obj/item/soap)
/mob/living/simple_animal/hostile/retaliate/clown/clownhulk/honcmunculus
name = "Honkmunculus"
desc = "A slender wiry figure of alchemical origin."
icon_state = "honkmunculus"
icon_living = "honkmunculus"
response_help = "skeptically pokes"
response_disarm = "pushes the unwieldy frame of"
speak = list("honk")
emote_see = list("squirms", "writhes")
speak_chance = 1
maxHealth = 200
health = 200
speed = -5
harm_intent_damage = 5
melee_damage_lower = 5
melee_damage_upper = 10
attacktext = "ferociously mauls"
environment_smash = ENVIRONMENT_SMASH_NONE
loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/effect/particle_effect/foam, /obj/item/soap)
attack_reagent = /datum/reagent/peaceborg_confuse
/mob/living/simple_animal/hostile/retaliate/clown/clownhulk/destroyer
name = "The Destroyer"
desc = "An ancient being born of arcane honking."
icon_state = "destroyer"
icon_living = "destroyer"
response_disarm = "bounces off of"
response_harm = "bounces off of"
speak = list("HONK!!!", "The Honkmother is merciful, so I must act out her wrath.", "parce mihi ad beatus honkmother placet mihi ut peccata committere,", "DIE!!!")
maxHealth = 400
health = 400
speed = 5
harm_intent_damage = 30
melee_damage_lower = 20
melee_damage_upper = 40
armour_penetration = 30
stat_attack = UNCONSCIOUS
attacktext = "acts out divine vengeance on"
obj_damage = 50
environment_smash = ENVIRONMENT_SMASH_RWALLS
loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/effect/particle_effect/foam, /obj/item/soap)
/mob/living/simple_animal/hostile/retaliate/clown/mutant
name = "Unknown"
desc = "Kill it for its own sake."
icon_state = "mutant"
icon_living = "mutant"
move_resist = INFINITY
turns_per_move = 10
response_help = "reluctantly sinks a finger into"
response_disarm = "squishes into"
response_harm = "squishes into"
speak = list("aaaaaahhhhuuhhhuhhhaaaaa", "AAAaaauuuaaAAAaauuhhh", "huuuuuh... hhhhuuuooooonnnnkk", "HuaUAAAnKKKK")
emote_see = list("squirms", "writhes", "pulsates", "froths", "oozes")
speak_chance = 10
maxHealth = 130
health = 130
pixel_x = -16
speed = -5
harm_intent_damage = 10
melee_damage_lower = 10
melee_damage_upper = 20
attacktext = "awkwardly flails at"
loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/item/soap, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/generic/animal, /obj/effect/gibspawner/human/bodypartless, /obj/effect/gibspawner/human)
/mob/living/simple_animal/hostile/retaliate/clown/mutant/blob
name = "Something that was once a clown"
desc = "A grotesque bulging figure far mutated from it's original state."
icon_state = "blob"
icon_living = "blob"
speak = list("hey, buddy", "HONK!!!", "H-h-h-H-HOOOOONK!!!!", "HONKHONKHONK!!!", "HEY, BUCKO, GET BACK HERE!!!", "HOOOOOOOONK!!!")
emote_see = list("jiggles", "wobbles")
health = 130
mob_size = MOB_SIZE_LARGE
speed = 20
attacktext = "bounces off of"
loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/effect/particle_effect/foam, /obj/item/soap, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/generic/animal, /obj/effect/gibspawner/human/bodypartless, /obj/effect/gibspawner/human)
attack_reagent = /datum/reagent/toxin/mindbreaker
@@ -1,5 +1,13 @@
/**
* Kudzu Flower Bud
*
* A flower created by flowering kudzu which spawns a venus human trap after a certain amount of time has passed.
*
* A flower created by kudzu with the flowering mutation. Spawns a venus human trap after 2 minutes under normal circumstances.
* Also spawns 4 vines going out in diagonal directions from the bud. Any living creature not aligned with plants is damaged by these vines.
* Once it grows a venus human trap, the bud itself will destroy itself.
*
*/
/obj/structure/alien/resin/flower_bud_enemy //inheriting basic attack/damage stuff from alien structures
name = "flower bud"
desc = "A large pulsating plant..."
@@ -9,9 +17,9 @@
opacity = 0
canSmoothWith = list()
smooth = SMOOTH_FALSE
/// The amount of time it takes to create a venus human trap, in deciseconds
var/growth_time = 1200
/obj/structure/alien/resin/flower_bud_enemy/Initialize()
. = ..()
var/list/anchors = list()
@@ -25,36 +33,49 @@
B.sleep_time = 10 //these shouldn't move, so let's slow down updates to 1 second (any slower and the deletion of the vines would be too slow)
addtimer(CALLBACK(src, .proc/bear_fruit), growth_time)
/**
* Spawns a venus human trap, then qdels itself.
*
* Displays a message, spawns a human venus trap, then qdels itself.
*/
/obj/structure/alien/resin/flower_bud_enemy/proc/bear_fruit()
visible_message("<span class='danger'>the plant has borne fruit!</span>")
visible_message("<span class='danger'>The plant has borne fruit!</span>")
new /mob/living/simple_animal/hostile/venus_human_trap(get_turf(src))
qdel(src)
/obj/effect/ebeam/vine
name = "thick vine"
mouse_opacity = MOUSE_OPACITY_ICON
desc = "A thick vine, painful to the touch."
/obj/effect/ebeam/vine/Crossed(atom/movable/AM)
. = ..()
if(isliving(AM))
var/mob/living/L = AM
if(!("vines" in L.faction))
if(!isvineimmune(L))
L.adjustBruteLoss(5)
to_chat(L, "<span class='alert'>You cut yourself on the thorny vines.</span>")
/**
* Venus Human Trap
*
* The result of a kudzu flower bud, these enemies use vines to drag prey close to them for attack.
*
* A carnivorious plant which uses vines to catch and ensnare prey. Spawns from kudzu flower buds.
* Each one has a maximum of four vines, which can be attached to a variety of things. Carbons are stunned when a vine is attached to them, and movable entities are pulled closer over time.
* Attempting to attach a vine to something with a vine already attached to it will pull all movable targets closer on command.
* Once the prey is in melee range, melee attacks from the venus human trap heals itself for 10% of its max health, assuming the target is alive.
* Akin to certain spiders, venus human traps can also be possessed and controlled by ghosts.
*
*/
/mob/living/simple_animal/hostile/venus_human_trap
name = "venus human trap"
desc = "Now you know how the fly feels."
icon_state = "venus_human_trap"
threat = 1
layer = SPACEVINE_MOB_LAYER
health = 50
maxHealth = 50
ranged = 1
ranged = TRUE
harm_intent_damage = 5
obj_damage = 60
melee_damage_lower = 25
@@ -63,65 +84,110 @@
attack_sound = 'sound/weapons/bladeslice.ogg'
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)
unsuitable_atmos_damage = 0
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
faction = list("hostile","vines","plants")
var/list/grasping = list()
var/max_grasps = 4
var/grasp_chance = 20
var/grasp_pull_chance = 85
var/grasp_range = 4
del_on_death = 1
initial_language_holder = /datum/language_holder/venus
del_on_death = TRUE
/// A list of all the plant's vines
var/list/vines = list()
/// The maximum amount of vines a plant can have at one time
var/max_vines = 4
/// How far away a plant can attach a vine to something
var/vine_grab_distance = 5
/// Whether or not this plant is ghost possessable
var/playable_plant = FALSE //Normal plants can **not** have players.
/mob/living/simple_animal/hostile/venus_human_trap/Destroy()
for(var/L in grasping)
var/datum/beam/B = grasping[L]
if(B)
qdel(B)
grasping = null
return ..()
/mob/living/simple_animal/hostile/venus_human_trap/ghost_playable
playable_plant = TRUE //For admins that want to buss some harmless plants
/mob/living/simple_animal/hostile/venus_human_trap/handle_automated_action()
if(..())
for(var/mob/living/L in grasping)
if(L.stat == DEAD)
var/datum/beam/B = grasping[L]
if(B)
B.End()
grasping -= L
//Can attack+pull multiple times per cycle
if(L.Adjacent(src))
L.attack_animal(src)
else
if(prob(grasp_pull_chance))
setDir(get_dir(src,L) )//staaaare
step(L,get_dir(L,src)) //reel them in
L.DefaultCombatKnockdown(60) //you can't get away now~
if(grasping.len < max_grasps)
grasping:
for(var/mob/living/L in view(grasp_range, src))
if(L == src || faction_check_mob(L) || (L in grasping) || L == target)
continue
for(var/t in getline(src,L))
for(var/a in t)
var/atom/A = a
if(A.density && A != L)
continue grasping
if(prob(grasp_chance))
to_chat(L, "<span class='userdanger'>\The [src] has you entangled!</span>")
grasping[L] = Beam(L, "vine", time=INFINITY, maxdistance=5, beam_type=/obj/effect/ebeam/vine)
break //only take 1 new victim per cycle
/mob/living/simple_animal/hostile/venus_human_trap/Life()
. = ..()
pull_vines()
/mob/living/simple_animal/hostile/venus_human_trap/AttackingTarget()
. = ..()
if(isliving(target))
var/mob/living/L = target
if(L.stat != DEAD)
adjustHealth(-maxHealth * 0.1)
/mob/living/simple_animal/hostile/venus_human_trap/OpenFire(atom/the_target)
var/dist = get_dist(src,the_target)
Beam(the_target, "vine", time=dist*2, maxdistance=dist+2, beam_type=/obj/effect/ebeam/vine)
the_target.attack_animal(src)
for(var/datum/beam/B in vines)
if(B.target == the_target)
pull_vines()
ranged_cooldown = world.time + (ranged_cooldown_time * 0.5)
return
if(get_dist(src,the_target) > vine_grab_distance || vines.len == max_vines)
return
for(var/turf/T in getline(src,target))
if (T.density)
return
for(var/obj/O in T)
if(O.density)
return
var/datum/beam/newVine = Beam(the_target, "vine", time=INFINITY, maxdistance = vine_grab_distance, beam_type=/obj/effect/ebeam/vine)
RegisterSignal(newVine, COMSIG_PARENT_QDELETING, .proc/remove_vine, newVine)
vines += newVine
if(isliving(the_target))
var/mob/living/L = the_target
L.Paralyze(20)
ranged_cooldown = world.time + ranged_cooldown_time
/mob/living/simple_animal/hostile/venus_human_trap/CanAttack(atom/the_target)
/mob/living/simple_animal/hostile/venus_human_trap/Login()
. = ..()
to_chat(src, "<span class='boldwarning'>You a venus human trap! Protect the kudzu at all costs, and feast on those who oppose you!</span>")
/mob/living/simple_animal/hostile/venus_human_trap/attack_ghost(mob/user)
. = ..()
if(.)
if(the_target in grasping)
return 0
return
humanize_plant(user)
/**
* Sets a ghost to control the plant if the plant is eligible
*
* Asks the interacting ghost if they would like to control the plant.
* If they answer yes, and another ghost hasn't taken control, sets the ghost to control the plant.
* Arguments:
* * mob/user - The ghost to possibly control the plant
*/
/mob/living/simple_animal/hostile/venus_human_trap/proc/humanize_plant(mob/user)
if(key || !playable_plant || stat)
return
var/plant_ask = alert("Become a venus human trap?", "Are you reverse vegan?", "Yes", "No")
if(plant_ask == "No" || QDELETED(src))
return
if(key)
to_chat(user, "<span class='warning'>Someone else already took this plant!</span>")
return
key = user.key
log_game("[key_name(src)] took control of [name].")
/**
* Manages how the vines should affect the things they're attached to.
*
* Pulls all movable targets of the vines closer to the plant
* If the target is on the same tile as the plant, destroy the vine
* Removes any QDELETED vines from the vines list.
*/
/mob/living/simple_animal/hostile/venus_human_trap/proc/pull_vines()
for(var/datum/beam/B in vines)
if(istype(B.target, /atom/movable))
var/atom/movable/AM = B.target
if(!AM.anchored)
step(AM,get_dir(AM,src))
if(get_dist(src,B.target) == 0)
B.End()
/**
* Removes a vine from the list.
*
* Removes the vine from our list.
* Called specifically when the vine is about to be destroyed, so we don't have any null references.
* Arguments:
* * datum/beam/vine - The vine to be removed from the list.
*/
mob/living/simple_animal/hostile/venus_human_trap/proc/remove_vine(datum/beam/vine, force)
vines -= vine
@@ -292,8 +292,8 @@
/mob/living/simple_animal/proc/update_simplemob_varspeed()
if(speed == 0)
remove_movespeed_modifier(MOVESPEED_ID_SIMPLEMOB_VARSPEED, TRUE)
add_movespeed_modifier(MOVESPEED_ID_SIMPLEMOB_VARSPEED, TRUE, 100, multiplicative_slowdown = speed, override = TRUE)
remove_movespeed_modifier(/datum/movespeed_modifier/simplemob_varspeed)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/simplemob_varspeed, multiplicative_slowdown = speed)
/mob/living/simple_animal/Stat()
..()
@@ -147,25 +147,26 @@
/mob/living/simple_animal/slime/on_reagent_change()
. = ..()
remove_movespeed_modifier(MOVESPEED_ID_SLIME_REAGENTMOD, TRUE)
remove_movespeed_modifier(/datum/movespeed_modifier/slime_reagentmod)
var/amount = 0
if(reagents.has_reagent(/datum/reagent/medicine/morphine)) // morphine slows slimes down
amount = 2
if(reagents.has_reagent(/datum/reagent/consumable/frostoil)) // Frostoil also makes them move VEEERRYYYYY slow
amount = 5
if(amount)
add_movespeed_modifier(MOVESPEED_ID_SLIME_REAGENTMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = amount)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/slime_reagentmod, multiplicative_slowdown = amount)
/mob/living/simple_animal/slime/updatehealth()
. = ..()
remove_movespeed_modifier(MOVESPEED_ID_SLIME_HEALTHMOD, FALSE)
var/health_deficiency = (100 - health)
remove_movespeed_modifier(/datum/movespeed_modifier/slime_healthmod)
var/mod = 0
if(health_deficiency >= 45)
mod += (health_deficiency / 25)
if(health <= 0)
mod += 2
add_movespeed_modifier(MOVESPEED_ID_SLIME_HEALTHMOD, TRUE, 100, multiplicative_slowdown = mod)
if(!HAS_TRAIT(src, TRAIT_IGNOREDAMAGESLOWDOWN))
var/health_deficiency = (maxHealth - health)
if(health_deficiency >= 45)
mod += (health_deficiency / 25)
if(health <= 0)
mod += 2
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/slime_healthmod, multiplicative_slowdown = mod)
/mob/living/simple_animal/slime/adjust_bodytemperature()
. = ..()
@@ -173,9 +174,8 @@
if(bodytemperature >= 330.23) // 135 F or 57.08 C
mod = -1 // slimes become supercharged at high temperatures
else if(bodytemperature < 183.222)
mod = (283.222 - bodytemperature) / 10 * 1.75
if(mod)
add_movespeed_modifier(MOVESPEED_ID_SLIME_TEMPMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = mod)
mod = min(15, (283.222 - bodytemperature) / 10 * 1.75)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/slime_tempmod, multiplicative_slowdown = mod)
/mob/living/simple_animal/slime/ObjBump(obj/O)
if(!client && powerlevel > 0)
+32 -2
View File
@@ -622,10 +622,40 @@
tod = STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)
update_stat()
///Unignores all slowdowns that lack the IGNORE_NOSLOW flag.
/mob/living/proc/unignore_slowdown(source)
REMOVE_TRAIT(src, TRAIT_IGNORESLOWDOWN, source)
update_movespeed(FALSE)
update_movespeed()
///Ignores all slowdowns that lack the IGNORE_NOSLOW flag.
/mob/living/proc/ignore_slowdown(source)
ADD_TRAIT(src, TRAIT_IGNORESLOWDOWN, source)
update_movespeed(FALSE)
update_movespeed()
///Ignores specific slowdowns. Accepts a list of slowdowns.
/mob/living/proc/add_movespeed_mod_immunities(source, slowdown_type, update = TRUE)
if(islist(slowdown_type))
for(var/listed_type in slowdown_type)
if(ispath(listed_type))
listed_type = "[listed_type]" //Path2String
LAZYADDASSOC(movespeed_mod_immunities, listed_type, source)
else
if(ispath(slowdown_type))
slowdown_type = "[slowdown_type]" //Path2String
LAZYADDASSOC(movespeed_mod_immunities, slowdown_type, source)
if(update)
update_movespeed()
///Unignores specific slowdowns. Accepts a list of slowdowns.
/mob/living/proc/remove_movespeed_mod_immunities(source, slowdown_type, update = TRUE)
if(islist(slowdown_type))
for(var/listed_type in slowdown_type)
if(ispath(listed_type))
listed_type = "[listed_type]" //Path2String
LAZYREMOVEASSOC(movespeed_mod_immunities, listed_type, source)
else
if(ispath(slowdown_type))
slowdown_type = "[slowdown_type]" //Path2String
LAZYREMOVEASSOC(movespeed_mod_immunities, slowdown_type, source)
if(update)
update_movespeed()
+11 -6
View File
@@ -1033,17 +1033,22 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0)
/// Updates the grab state of the mob and updates movespeed
/mob/setGrabState(newstate)
. = ..()
if(grab_state == GRAB_PASSIVE)
remove_movespeed_modifier(MOVESPEED_ID_MOB_GRAB_STATE, update=TRUE)
else
add_movespeed_modifier(MOVESPEED_ID_MOB_GRAB_STATE, update=TRUE, priority=100, override=TRUE, multiplicative_slowdown=grab_state*3, blacklisted_movetypes=FLOATING)
switch(grab_state)
if(GRAB_PASSIVE)
remove_movespeed_modifier(MOVESPEED_ID_MOB_GRAB_STATE)
if(GRAB_AGGRESSIVE)
add_movespeed_modifier(/datum/movespeed_modifier/grab_slowdown/aggressive)
if(GRAB_NECK)
add_movespeed_modifier(/datum/movespeed_modifier/grab_slowdown/neck)
if(GRAB_KILL)
add_movespeed_modifier(/datum/movespeed_modifier/grab_slowdown/kill)
/mob/proc/update_equipment_speed_mods()
var/speedies = equipped_speed_mods()
if(!speedies)
remove_movespeed_modifier(MOVESPEED_ID_MOB_EQUIPMENT, update=TRUE)
remove_movespeed_modifier(/datum/movespeed_modifier/equipment_speedmod, update=TRUE)
else
add_movespeed_modifier(MOVESPEED_ID_MOB_EQUIPMENT, update=TRUE, priority=100, override=TRUE, multiplicative_slowdown=speedies, blacklisted_movetypes=FLOATING)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/equipment_speedmod, multiplicative_slowdown = speedies)
/// Gets the combined speed modification of all worn items
/// Except base mob type doesnt really wear items
+6 -1
View File
@@ -10,6 +10,8 @@
throwforce = 10
blocks_emissive = EMISSIVE_BLOCK_GENERIC
vis_flags = VIS_INHERIT_PLANE //when this be added to vis_contents of something it inherit something.plane, important for visualisation of mob in openspace.
var/lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
var/datum/mind/mind
var/list/datum/action/actions = list()
@@ -42,8 +44,11 @@
var/lying_prev = 0
var/is_shifted = FALSE
//MOVEMENT SPEED
/// List of movement speed modifiers applying to this mob
var/list/movespeed_modification //Lazy list, see mob_movespeed.dm
/// List of movement speed modifiers ignored by this mob. List -> List (id) -> List (sources)
var/list/movespeed_mod_immunities //Lazy list, see mob_movespeed.dm
/// The calculated mob speed slowdown based on the modifiers list
var/cached_multiplicative_slowdown
/////////////////
+6 -6
View File
@@ -80,12 +80,12 @@
var/oldloc = mob.loc
if(L.confused)
var/newdir = 0
if(L.confused > 40)
var/newdir = NONE
if((L.confused > 50) && prob(min(L.confused * 0.5, 50)))
newdir = pick(GLOB.alldirs)
else if(prob(L.confused * 1.5))
else if(prob(L.confused))
newdir = angle2dir(dir2angle(direction) + pick(90, -90))
else if(prob(L.confused * 3))
else if(prob(L.confused * 2))
newdir = angle2dir(dir2angle(direction) + pick(45, -45))
if(newdir)
direction = newdir
@@ -251,9 +251,9 @@
/mob/proc/update_gravity(has_gravity, override=FALSE)
var/speed_change = max(0, has_gravity - STANDARD_GRAVITY)
if(!speed_change)
remove_movespeed_modifier(MOVESPEED_ID_MOB_GRAVITY, update=TRUE)
remove_movespeed_modifier(/datum/movespeed_modifier/gravity)
else
add_movespeed_modifier(MOVESPEED_ID_MOB_GRAVITY, update=TRUE, priority=100, override=TRUE, multiplicative_slowdown=speed_change, blacklisted_movetypes=FLOATING)
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/gravity, multiplicative_slowdown = speed_change)
//bodypart selection - Cyberboss
//8 toggles through head - eyes - mouth
-126
View File
@@ -1,126 +0,0 @@
/*Current movespeed modification list format: list(id = list(
priority,
flags,
legacy slowdown/speedup amount,
movetype_flags,
blacklisted_movetypes,
conflict
))
*/
//ANY ADD/REMOVE DONE IN UPDATE_MOVESPEED MUST HAVE THE UPDATE ARGUMENT SET AS FALSE!
/mob/proc/add_movespeed_modifier(id, update=TRUE, priority=0, flags=NONE, override=FALSE, multiplicative_slowdown=0, movetypes=ALL, blacklisted_movetypes=NONE, conflict=FALSE)
var/list/temp = list(priority, flags, multiplicative_slowdown, movetypes, blacklisted_movetypes, conflict) //build the modification list
var/resort = TRUE
if(LAZYACCESS(movespeed_modification, id))
var/list/existing_data = movespeed_modification[id]
if(movespeed_modifier_identical_check(existing_data, temp))
return FALSE
if(!override)
return FALSE
if(priority == existing_data[MOVESPEED_DATA_INDEX_PRIORITY])
resort = FALSE // We don't need to re-sort if we're replacing something already there and it's the same priority
LAZYSET(movespeed_modification, id, temp)
if(update)
update_movespeed(resort)
return TRUE
/mob/proc/remove_movespeed_modifier(id, update = TRUE)
if(!LAZYACCESS(movespeed_modification, id))
return FALSE
LAZYREMOVE(movespeed_modification, id)
UNSETEMPTY(movespeed_modification)
if(update)
update_movespeed(FALSE)
return TRUE
/mob/vv_edit_var(var_name, var_value)
var/slowdown_edit = (var_name == NAMEOF(src, cached_multiplicative_slowdown))
var/diff
if(slowdown_edit && isnum(cached_multiplicative_slowdown) && isnum(var_value))
remove_movespeed_modifier(MOVESPEED_ID_ADMIN_VAREDIT)
diff = var_value - cached_multiplicative_slowdown
. = ..()
if(. && slowdown_edit && isnum(diff))
add_movespeed_modifier(MOVESPEED_ID_ADMIN_VAREDIT, TRUE, 100, override = TRUE, multiplicative_slowdown = diff)
/mob/proc/has_movespeed_modifier(id)
return LAZYACCESS(movespeed_modification, id)
/mob/proc/update_config_movespeed()
add_movespeed_modifier(MOVESPEED_ID_CONFIG_SPEEDMOD, FALSE, 100, override = TRUE, multiplicative_slowdown = get_config_multiplicative_speed())
/mob/proc/get_config_multiplicative_speed()
if(!islist(GLOB.mob_config_movespeed_type_lookup) || !GLOB.mob_config_movespeed_type_lookup[type])
return 0
else
return GLOB.mob_config_movespeed_type_lookup[type]
/mob/proc/update_movespeed(resort = TRUE)
if(resort)
sort_movespeed_modlist()
. = 0
var/list/conflict_tracker = list()
for(var/id in get_movespeed_modifiers())
var/list/data = movespeed_modification[id]
if(!(data[MOVESPEED_DATA_INDEX_MOVETYPE] & movement_type)) // We don't affect any of these move types, skip
continue
if(data[MOVESPEED_DATA_INDEX_BL_MOVETYPE] & movement_type) // There's a movetype here that disables this modifier, skip
continue
var/conflict = data[MOVESPEED_DATA_INDEX_CONFLICT]
var/amt = data[MOVESPEED_DATA_INDEX_MULTIPLICATIVE_SLOWDOWN]
if(conflict)
// Conflicting modifiers prioritize the larger slowdown or the larger speedup
// We purposefuly don't handle mixing speedups and slowdowns on the same id
if(abs(conflict_tracker[conflict]) < abs(amt))
conflict_tracker[conflict] = amt
else
continue
. += amt
cached_multiplicative_slowdown = .
/mob/proc/get_movespeed_modifiers()
return movespeed_modification
/mob/proc/movespeed_modifier_identical_check(list/mod1, list/mod2)
if(!islist(mod1) || !islist(mod2) || mod1.len < MOVESPEED_DATA_INDEX_MAX || mod2.len < MOVESPEED_DATA_INDEX_MAX)
return FALSE
for(var/i in 1 to MOVESPEED_DATA_INDEX_MAX)
if(mod1[i] != mod2[i])
return FALSE
return TRUE
/mob/proc/total_multiplicative_slowdown()
. = 0
for(var/id in get_movespeed_modifiers())
var/list/data = movespeed_modification[id]
. += data[MOVESPEED_DATA_INDEX_MULTIPLICATIVE_SLOWDOWN]
/proc/movespeed_data_null_check(list/data) //Determines if a data list is not meaningful and should be discarded.
. = TRUE
if(data[MOVESPEED_DATA_INDEX_MULTIPLICATIVE_SLOWDOWN])
. = FALSE
/mob/proc/sort_movespeed_modlist() //Verifies it too. Sorts highest priority (first applied) to lowest priority (last applied)
if(!movespeed_modification)
return
var/list/assembled = list()
for(var/our_id in movespeed_modification)
var/list/our_data = movespeed_modification[our_id]
if(!islist(our_data) || (our_data.len < MOVESPEED_DATA_INDEX_PRIORITY) || movespeed_data_null_check(our_data))
movespeed_modification -= our_id
continue
var/our_priority = our_data[MOVESPEED_DATA_INDEX_PRIORITY]
var/resolved = FALSE
for(var/their_id in assembled)
var/list/their_data = assembled[their_id]
if(their_data[MOVESPEED_DATA_INDEX_PRIORITY] < our_priority)
assembled.Insert(assembled.Find(their_id), our_id)
assembled[our_id] = our_data
resolved = TRUE
break
if(!resolved)
assembled[our_id] = our_data
movespeed_modification = assembled
UNSETEMPTY(movespeed_modification)