Merge branch 'master' into the-fuck-am-i-doing
This commit is contained in:
@@ -27,7 +27,7 @@
|
||||
age = rand(AGE_MIN,AGE_MAX)
|
||||
|
||||
/datum/preferences/proc/update_preview_icon(current_tab)
|
||||
var/equip_job = (current_tab != 2)
|
||||
var/equip_job = (current_tab != APPEARANCE_TAB)
|
||||
// Determine what job is marked as 'High' priority, and dress them up as such.
|
||||
var/datum/job/previewJob = get_highest_job()
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
mannequin.add_overlay(mutable_appearance('modular_citadel/icons/ui/backgrounds.dmi', bgstate, layer = SPACE_LAYER))
|
||||
copy_to(mannequin, initial_spawn = TRUE)
|
||||
|
||||
if(current_tab == 3)
|
||||
if(current_tab == LOADOUT_TAB)
|
||||
//give it its loadout if not on the appearance tab
|
||||
SSjob.equip_loadout(parent.mob, mannequin, FALSE, bypass_prereqs = TRUE, can_drop = FALSE)
|
||||
else
|
||||
|
||||
@@ -514,6 +514,20 @@
|
||||
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
|
||||
matrixed_sections = MATRIX_RED_GREEN
|
||||
|
||||
/datum/sprite_accessory/tails/human/triple_kitsune
|
||||
name = "Triple Kitsune Tails"
|
||||
icon_state = "3sune"
|
||||
color_src = MATRIXED
|
||||
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
|
||||
matrixed_sections = MATRIX_RED_GREEN
|
||||
|
||||
/datum/sprite_accessory/tails_animated/human/triple_kitsune
|
||||
name = "Triple Kitsune Tails"
|
||||
icon_state = "3sune"
|
||||
color_src = MATRIXED
|
||||
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
|
||||
matrixed_sections = MATRIX_RED_GREEN
|
||||
|
||||
/datum/sprite_accessory/tails/human/tentacle
|
||||
name = "Tentacle"
|
||||
icon_state = "tentacle"
|
||||
@@ -965,6 +979,16 @@
|
||||
icon_state = "9sune"
|
||||
matrixed_sections = MATRIX_RED_GREEN
|
||||
|
||||
/datum/sprite_accessory/tails/mam_tails/triple_kitsune
|
||||
name = "Triple Kitsune Tails"
|
||||
icon_state = "3sune"
|
||||
matrixed_sections = MATRIX_RED_GREEN
|
||||
|
||||
/datum/sprite_accessory/tails_animated/mam_tails_animated/triple_kitsune
|
||||
name = "Triple Kitsune Tails"
|
||||
icon_state = "3sune"
|
||||
matrixed_sections = MATRIX_RED_GREEN
|
||||
|
||||
/datum/sprite_accessory/tails/mam_tails/tentacle
|
||||
name = "Tentacle"
|
||||
icon_state = "tentacle"
|
||||
|
||||
@@ -905,6 +905,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
mob_eye.observers |= src
|
||||
mob_eye.hud_used.show_hud(mob_eye.hud_used.hud_version, src)
|
||||
observetarget = mob_eye
|
||||
mob_eye.investigate_log("was observed by [src] as a ghost.", INVESTIGATE_GHOST)
|
||||
|
||||
/mob/dead/observer/verb/register_pai_candidate()
|
||||
set category = "Ghost"
|
||||
|
||||
@@ -297,6 +297,11 @@
|
||||
icon = 'icons/obj/surgery.dmi'
|
||||
icon_state = "posibrain-ipc"
|
||||
|
||||
/obj/item/organ/brain/slime
|
||||
name = "slime nucleus"
|
||||
desc = "A slimey membranous mass from a slimeperson."
|
||||
icon_state = "brain-s"
|
||||
|
||||
|
||||
////////////////////////////////////TRAUMAS////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -1237,7 +1237,7 @@
|
||||
if(user.incapacitated() || !user.Adjacent(src))
|
||||
return FALSE
|
||||
if(W && user.a_intent == INTENT_HELP && W.can_give())
|
||||
user.give()
|
||||
user.give(src)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/verb/give_verb()
|
||||
@@ -1253,4 +1253,4 @@
|
||||
var/obj/item/I = usr.get_active_held_item()
|
||||
var/mob/living/carbon/C = usr
|
||||
if(I.can_give())
|
||||
C.give()
|
||||
C.give(src)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
|
||||
/mob/living/carbon/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = SHARP_NONE)
|
||||
SEND_SIGNAL(src, COMSIG_MOB_APPLY_DAMGE, damage, damagetype, def_zone)
|
||||
SEND_SIGNAL(src, COMSIG_MOB_APPLY_DAMAGE, damage, damagetype, def_zone)
|
||||
var/hit_percent = (100-blocked)/100
|
||||
if(!forced && hit_percent <= 0)
|
||||
return 0
|
||||
|
||||
@@ -24,7 +24,12 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
|
||||
/mob/living/carbon/human/dummy/proc/wipe_state()
|
||||
delete_equipment()
|
||||
icon_render_key = null
|
||||
cut_overlays()
|
||||
cut_overlays(TRUE)
|
||||
|
||||
/mob/living/carbon/human/dummy/setup_human_dna()
|
||||
create_dna(src)
|
||||
randomize_human(src)
|
||||
dna.initialize_dna(skip_index = TRUE) //Skip stuff that requires full round init.
|
||||
|
||||
//Inefficient pooling/caching way.
|
||||
GLOBAL_LIST_EMPTY(human_dummy_list)
|
||||
@@ -42,13 +47,48 @@ GLOBAL_LIST_EMPTY(dummy_mob_list)
|
||||
D = new
|
||||
GLOB.human_dummy_list[slotkey] = D
|
||||
GLOB.dummy_mob_list += D
|
||||
else
|
||||
D.regenerate_icons() //they were cut in wipe_state()
|
||||
D.in_use = TRUE
|
||||
return D
|
||||
|
||||
/proc/unset_busy_human_dummy(slotnumber)
|
||||
if(!slotnumber)
|
||||
/proc/generate_dummy_lookalike(slotkey, mob/target)
|
||||
if(!istype(target))
|
||||
return generate_or_wait_for_human_dummy(slotkey)
|
||||
|
||||
var/mob/living/carbon/human/dummy/copycat = generate_or_wait_for_human_dummy(slotkey)
|
||||
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/carbon_target = target
|
||||
carbon_target.dna.transfer_identity(copycat, transfer_SE = TRUE)
|
||||
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/human_target = target
|
||||
human_target.copy_clothing_prefs(copycat)
|
||||
|
||||
copycat.updateappearance(icon_update=TRUE, mutcolor_update=TRUE, mutations_overlay_update=TRUE)
|
||||
else
|
||||
//even if target isn't a carbon, if they have a client we can make the
|
||||
//dummy look like what their human would look like based on their prefs
|
||||
target?.client?.prefs?.copy_to(copycat, icon_updates=TRUE, roundstart_checks=FALSE)
|
||||
|
||||
return copycat
|
||||
|
||||
/proc/unset_busy_human_dummy(slotkey)
|
||||
if(!slotkey)
|
||||
return
|
||||
var/mob/living/carbon/human/dummy/D = GLOB.human_dummy_list[slotnumber]
|
||||
var/mob/living/carbon/human/dummy/D = GLOB.human_dummy_list[slotkey]
|
||||
if(istype(D))
|
||||
D.wipe_state()
|
||||
D.in_use = FALSE
|
||||
|
||||
/proc/clear_human_dummy(slotkey)
|
||||
if(!slotkey)
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/dummy/dummy = GLOB.human_dummy_list[slotkey]
|
||||
|
||||
GLOB.human_dummy_list -= slotkey
|
||||
if(istype(dummy))
|
||||
GLOB.dummy_mob_list -= dummy
|
||||
qdel(dummy)
|
||||
|
||||
@@ -41,10 +41,10 @@
|
||||
|
||||
. += "[t_He] [t_is] wearing [w_uniform.get_examine_string(user)][accessory_msg]."
|
||||
//head
|
||||
if(head)
|
||||
if(head && !(head.item_flags & EXAMINE_SKIP))
|
||||
. += "[t_He] [t_is] wearing [head.get_examine_string(user)] on [t_his] head."
|
||||
//suit/armor
|
||||
if(wear_suit)
|
||||
if(wear_suit && !(wear_suit.item_flags & EXAMINE_SKIP))
|
||||
. += "[t_He] [t_is] wearing [wear_suit.get_examine_string(user)]."
|
||||
//suit/armor storage
|
||||
if(s_store && !(SLOT_S_STORE in obscured))
|
||||
|
||||
@@ -14,10 +14,7 @@
|
||||
//initialize limbs first
|
||||
create_bodyparts()
|
||||
|
||||
//initialize dna. for spawned humans; overwritten by other code
|
||||
create_dna(src)
|
||||
randomize_human(src)
|
||||
dna.initialize_dna()
|
||||
setup_human_dna()
|
||||
|
||||
if(dna.species)
|
||||
set_species(dna.species.type)
|
||||
@@ -36,6 +33,11 @@
|
||||
RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /atom.proc/clean_blood)
|
||||
GLOB.human_list += src
|
||||
|
||||
/mob/living/carbon/human/proc/setup_human_dna()
|
||||
//initialize dna. for spawned humans; overwritten by other code
|
||||
create_dna(src)
|
||||
randomize_human(src)
|
||||
dna.initialize_dna()
|
||||
|
||||
/mob/living/carbon/human/ComponentInitialize()
|
||||
. = ..()
|
||||
|
||||
@@ -115,13 +115,13 @@
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(HAS_TRAIT(src, TRAIT_NOGUNS))
|
||||
to_chat(src, "<span class='warning'>You can't bring yourself to use a ranged weapon!</span>")
|
||||
return FALSE
|
||||
if(G.trigger_guard == TRIGGER_GUARD_NORMAL)
|
||||
if(HAS_TRAIT(src, TRAIT_CHUNKYFINGERS))
|
||||
to_chat(src, "<span class='warning'>Your meaty finger is much too large for the trigger guard!</span>")
|
||||
return FALSE
|
||||
if(HAS_TRAIT(src, TRAIT_NOGUNS))
|
||||
to_chat(src, "<span class='warning'>Your fingers don't fit in the trigger guard!</span>")
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/human/proc/get_bank_account()
|
||||
RETURN_TYPE(/datum/bank_account)
|
||||
@@ -176,3 +176,9 @@
|
||||
|
||||
/mob/living/carbon/human/get_biological_state()
|
||||
return dna.species.get_biological_state()
|
||||
|
||||
///copies over clothing preferences like underwear to another human
|
||||
/mob/living/carbon/human/proc/copy_clothing_prefs(mob/living/carbon/human/destination)
|
||||
destination.underwear = underwear
|
||||
destination.undershirt = undershirt
|
||||
destination.socks = socks
|
||||
|
||||
@@ -37,16 +37,17 @@
|
||||
to_chat(owner, "There's something stuck to your hand, stopping you from transforming!")
|
||||
return
|
||||
if(IsAvailable())
|
||||
transforming = TRUE
|
||||
UpdateButtonIcon()
|
||||
var/mutcolor = owner.get_ability_property(INNATE_ABILITY_SLIME_BLOBFORM, PROPERTY_BLOBFORM_COLOR) || ("#" + H.dna.features["mcolor"])
|
||||
if(!is_puddle)
|
||||
if(CHECK_MOBILITY(H, MOBILITY_USE)) //if we can use items, we can turn into a puddle
|
||||
transforming = TRUE
|
||||
is_puddle = TRUE //so we know which transformation to use when its used
|
||||
ADD_TRAIT(H, TRAIT_HUMAN_NO_RENDER, SLIMEPUDDLE_TRAIT)
|
||||
owner.cut_overlays() //we dont show our normal sprite, we show a puddle sprite
|
||||
var/obj/effect/puddle_effect = new puddle_into_effect(get_turf(owner), owner.dir)
|
||||
puddle_effect.color = mutcolor
|
||||
puddle_effect.transform = H.transform //copy mob size for consistent meltdown appearance
|
||||
H.Stun(in_transformation_duration, ignore_canstun = TRUE) //cant move while transforming
|
||||
|
||||
//series of traits that make up the puddle behaviour
|
||||
@@ -75,6 +76,7 @@
|
||||
puddle_overlay.color = mutcolor
|
||||
tracked_overlay = puddle_overlay
|
||||
owner.add_overlay(puddle_overlay)
|
||||
owner.update_antag_overlays()
|
||||
|
||||
transforming = FALSE
|
||||
UpdateButtonIcon()
|
||||
@@ -89,6 +91,7 @@
|
||||
H.cut_overlay(tracked_overlay)
|
||||
var/obj/effect/puddle_effect = new puddle_from_effect(get_turf(owner), owner.dir)
|
||||
puddle_effect.color = tracked_overlay.color
|
||||
puddle_effect.transform = H.transform //copy mob size for consistent transform size
|
||||
H.Stun(out_transformation_duration, ignore_canstun = TRUE)
|
||||
sleep(out_transformation_duration)
|
||||
REMOVE_TRAIT(H, TRAIT_PARALYSIS_L_ARM, SLIMEPUDDLE_TRAIT)
|
||||
@@ -106,5 +109,6 @@
|
||||
is_puddle = FALSE
|
||||
if(squeak)
|
||||
squeak.RemoveComponent()
|
||||
H.regenerate_icons()
|
||||
transforming = FALSE
|
||||
UpdateButtonIcon()
|
||||
|
||||
@@ -1620,8 +1620,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
"<span class='userdanger'>[user] [atk_verb]ed you!</span>", null, COMBAT_MESSAGE_RANGE, null, \
|
||||
user, "<span class='danger'>You [atk_verb]ed [target]!</span>")
|
||||
|
||||
target.lastattacker = user.real_name
|
||||
target.lastattackerckey = user.ckey
|
||||
target.set_last_attacker(user)
|
||||
user.dna.species.spec_unarmedattacked(user, target)
|
||||
|
||||
if(user.limb_destroyer)
|
||||
@@ -2039,8 +2038,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
user, "<span class='danger'>You shove [target.name]!</span>")
|
||||
target.Stagger(SHOVE_STAGGER_DURATION)
|
||||
var/obj/item/target_held_item = target.get_active_held_item()
|
||||
if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types))
|
||||
target_held_item = null
|
||||
if(!target.has_status_effect(STATUS_EFFECT_OFF_BALANCE))
|
||||
if(target_held_item)
|
||||
if(!HAS_TRAIT(target_held_item, TRAIT_NODROP))
|
||||
@@ -2058,7 +2055,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
log_combat(user, target, "shoved", append_message)
|
||||
|
||||
/datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = SHARP_NONE)
|
||||
SEND_SIGNAL(H, COMSIG_MOB_APPLY_DAMGE, damage, damagetype, def_zone, wound_bonus, bare_wound_bonus, sharpness) // make sure putting wound_bonus here doesn't screw up other signals or uses for this signal
|
||||
SEND_SIGNAL(H, COMSIG_MOB_APPLY_DAMAGE, damage, damagetype, def_zone, wound_bonus, bare_wound_bonus, sharpness) // make sure putting wound_bonus here doesn't screw up other signals or uses for this signal
|
||||
var/hit_percent = (100-(blocked+armor))/100
|
||||
hit_percent = (hit_percent * (100-H.physiology.damage_resistance))/100
|
||||
if(!forced && hit_percent <= 0)
|
||||
|
||||
@@ -625,7 +625,7 @@
|
||||
say_mod = "clicks"
|
||||
limbs_id = "clockgolem"
|
||||
info_text = "<span class='bold alloy'>As a </span><span class='bold brass'>Clockwork Golem</span><span class='bold alloy'>, you are faster than other types of golems, and are capable of using guns. On death, you will break down into scrap.</span>"
|
||||
species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYES,NOGENITALS,NOAROUSAL)
|
||||
species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYES,NOGENITALS,NOAROUSAL,ROBOTIC_LIMBS)
|
||||
inherent_biotypes = MOB_ROBOTIC|MOB_HUMANOID
|
||||
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOFIRE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER)
|
||||
inherent_biotypes = MOB_ROBOTIC|MOB_HUMANOID
|
||||
@@ -667,6 +667,10 @@
|
||||
|
||||
/datum/species/golem/clockwork/no_scrap //These golems are created through the herald's beacon and leave normal corpses on death.
|
||||
id = "clockwork golem servant"
|
||||
species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYES,NOSTOMACH,NOLIVER,NOGENITALS,NOAROUSAL,NOTRANSSTING,ROBOTIC_LIMBS,HAS_BONE)
|
||||
inherent_biotypes = MOB_ROBOTIC|MOB_HUMANOID
|
||||
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_NOHUNGER,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOFIRE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER)
|
||||
inherent_biotypes = MOB_ROBOTIC|MOB_HUMANOID
|
||||
armor = 15 //Balance reasons make this armor weak
|
||||
no_equip = list()
|
||||
nojumpsuit = FALSE
|
||||
@@ -675,6 +679,8 @@
|
||||
dangerous_existence = TRUE
|
||||
random_eligible = FALSE
|
||||
info_text = "<span class='bold alloy'>As a </span><span class='bold brass'>Clockwork Golem Servant</span><span class='bold alloy'>, you are faster than other types of golems, and are capable of using guns.</span>" //warcult golems leave a corpse
|
||||
gib_types = list(/obj/effect/gibspawner/ipc, /obj/effect/gibspawner/ipc/bodypartless)
|
||||
|
||||
|
||||
/datum/species/golem/cloth
|
||||
name = "Cloth Golem"
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,WINGCOLOR,HAS_FLESH)
|
||||
mutantlungs = /obj/item/organ/lungs/slime
|
||||
mutant_heart = /obj/item/organ/heart/slime
|
||||
mutantstomach = /obj/item/organ/stomach/slime
|
||||
mutantliver = /obj/item/organ/liver/slime
|
||||
mutant_brain = /obj/item/organ/brain/slime
|
||||
mutant_bodyparts = list("mcolor" = "FFFFFF", "mam_tail" = "None", "mam_ears" = "None", "mam_snouts" = "None", "taur" = "None", "deco_wings" = "None", "legs" = "Plantigrade")
|
||||
inherent_traits = list(TRAIT_TOXINLOVER)
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/slime
|
||||
@@ -22,18 +25,12 @@
|
||||
heatmod = 0.5 // = 1/4x heat damage
|
||||
burnmod = 0.5 // = 1/2x generic burn damage
|
||||
species_language_holder = /datum/language_holder/jelly
|
||||
mutant_brain = /obj/item/organ/brain/jelly
|
||||
|
||||
tail_type = "mam_tail"
|
||||
wagging_type = "mam_waggingtail"
|
||||
species_category = SPECIES_CATEGORY_JELLY
|
||||
ass_image = 'icons/ass/assslime.png'
|
||||
|
||||
/obj/item/organ/brain/jelly
|
||||
name = "slime nucleus"
|
||||
desc = "A slimey membranous mass from a slime person"
|
||||
icon_state = "brain-slime"
|
||||
|
||||
/datum/species/jelly/on_species_loss(mob/living/carbon/C)
|
||||
C.faction -= "slime"
|
||||
if(ishuman(C))
|
||||
|
||||
@@ -62,9 +62,12 @@
|
||||
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"
|
||||
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)
|
||||
if(C.dna.features["mam_snouts"] != "Sharp")
|
||||
C.dna.features["mam_snouts"] = "Sharp"
|
||||
C.update_body()
|
||||
return ..()
|
||||
|
||||
@@ -181,6 +181,10 @@
|
||||
if(T.light_range && !isspaceturf(T)) //no fairy grass or light tile can escape the fury of the darkness.
|
||||
to_chat(user, "<span class='notice'>You scrape away [T] with your [name] and snuff out its lights.</span>")
|
||||
T.ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
|
||||
else if(is_cleanable(AM))
|
||||
var/obj/effect/E = AM
|
||||
if(E.light_range && E.light_power)
|
||||
disintegrate(E)
|
||||
else if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
if(isethereal(AM))
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
id = SPECIES_VAMPIRE
|
||||
default_color = "FFFFFF"
|
||||
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,DRINKSBLOOD,HAS_FLESH,HAS_BONE)
|
||||
inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH)
|
||||
inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH,TRAIT_NOMARROW)
|
||||
inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID
|
||||
mutant_bodyparts = list("mcolor" = "FFFFFF", "tail_human" = "None", "ears" = "None", "deco_wings" = "None")
|
||||
exotic_bloodtype = "U"
|
||||
@@ -53,12 +53,13 @@
|
||||
C.adjustOxyLoss(-4)
|
||||
C.adjustCloneLoss(-4)
|
||||
return
|
||||
C.blood_volume -= 0.75 //Will take roughly 19.5 minutes to die from standard blood volume, roughly 83 minutes to die from max blood volume.
|
||||
if(C.blood_volume <= (BLOOD_VOLUME_SURVIVE*C.blood_ratio))
|
||||
to_chat(C, "<span class='danger'>You ran out of blood!</span>")
|
||||
C.dust()
|
||||
if(C.blood_volume > 0.5)
|
||||
C.blood_volume -= 0.5 //Will take roughly 19.5 minutes to die from standard blood volume, roughly 83 minutes to die from max blood volume.
|
||||
else
|
||||
C.dust(FALSE, TRUE)
|
||||
|
||||
var/area/A = get_area(C)
|
||||
if(istype(A, /area/chapel) && C.mind?.assigned_role != "Chaplain")
|
||||
if(istype(A, /area/service/chapel) && C.mind?.assigned_role != "Chaplain")
|
||||
to_chat(C, "<span class='danger'>You don't belong here!</span>")
|
||||
C.adjustFireLoss(5)
|
||||
C.adjust_fire_stacks(6)
|
||||
@@ -125,7 +126,7 @@
|
||||
. = ..()
|
||||
var/obj/item/organ/heart/vampire/darkheart = getorgan(/obj/item/organ/heart/vampire)
|
||||
if(darkheart)
|
||||
. += "<span class='notice'>Current blood level: [blood_volume]/[BLOOD_VOLUME_MAXIMUM].</span>"
|
||||
. += "Current blood level: [blood_volume]/[BLOOD_VOLUME_MAXIMUM]."
|
||||
|
||||
|
||||
/obj/item/organ/heart/vampire
|
||||
|
||||
@@ -100,10 +100,29 @@ There are several things that need to be remembered:
|
||||
update_mutations_overlay()
|
||||
//damage overlays
|
||||
update_damage_overlays()
|
||||
//antagonism
|
||||
update_antag_overlays()
|
||||
|
||||
/* --------------------------------------- */
|
||||
//vvvvvv UPDATE_INV PROCS vvvvvv
|
||||
|
||||
|
||||
/mob/living/carbon/human/update_antag_overlays()
|
||||
remove_overlay(ANTAG_LAYER)
|
||||
var/datum/antagonist/cult/D = src?.mind?.has_antag_datum(/datum/antagonist/cult) //check for cultism
|
||||
if(D && D.cult_team?.cult_ascendent == TRUE)
|
||||
var/istate = pick("halo1","halo2","halo3","halo4","halo5","halo6")
|
||||
var/mutable_appearance/new_cult_overlay = mutable_appearance('icons/effects/32x64.dmi', istate, -ANTAG_LAYER)
|
||||
overlays_standing[ANTAG_LAYER] = new_cult_overlay
|
||||
var/datum/antagonist/clockcult/C = src?.mind?.has_antag_datum(/datum/antagonist/clockcult) //check for clockcultism - surely one can't be both cult and clockie, right?
|
||||
if(C)
|
||||
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
|
||||
if(G && G.active && ishuman(src))
|
||||
var/mutable_appearance/new_cult_overlay = mutable_appearance('icons/effects/genetics.dmi', "servitude", -ANTAG_LAYER)
|
||||
overlays_standing[ANTAG_LAYER] = new_cult_overlay
|
||||
apply_overlay(ANTAG_LAYER)
|
||||
|
||||
|
||||
/mob/living/carbon/human/update_inv_w_uniform()
|
||||
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
|
||||
remove_overlay(UNIFORM_LAYER)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/**
|
||||
* Applies damage to this mob
|
||||
*
|
||||
* Sends [COMSIG_MOB_APPLY_DAMGE]
|
||||
* Sends [COMSIG_MOB_APPLY_DAMAGE]
|
||||
*
|
||||
* Arguuments:
|
||||
* * damage - amount of damage
|
||||
|
||||
@@ -55,6 +55,8 @@
|
||||
|
||||
|
||||
/mob/living/death(gibbed)
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_PREDEATH, gibbed)
|
||||
|
||||
stat = DEAD
|
||||
unset_machine()
|
||||
timeofdeath = world.time
|
||||
@@ -87,7 +89,7 @@
|
||||
addtimer(CALLBACK(src, .proc/med_hud_set_status), (DEFIB_TIME_LIMIT * 10) + 1)
|
||||
stop_pulling()
|
||||
|
||||
var/signal = SEND_SIGNAL(src, COMSIG_MOB_DEATH, gibbed)
|
||||
var/signal = SEND_SIGNAL(src, COMSIG_MOB_DEATH, gibbed) | SEND_GLOBAL_SIGNAL(COMSIG_GLOB_MOB_DEATH, src, gibbed)
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
if(mind && mind.name && mind.active && !istype(T.loc, /area/ctf) && !(signal & COMPONENT_BLOCK_DEATH_BROADCAST))
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Splits off into PhysicalLife() and BiologicalLife(). Override those instead of this.
|
||||
*/
|
||||
/mob/living/proc/Life(seconds, times_fired)
|
||||
//SHOULD_NOT_SLEEP(TRUE)
|
||||
SHOULD_NOT_SLEEP(TRUE)
|
||||
if(mob_transforming)
|
||||
return
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
break
|
||||
var/msg = "[key_name_admin(src)] [ADMIN_JMP(src)] was found to have no .loc with an attached client, if the cause is unknown it would be wise to ask how this was accomplished."
|
||||
message_admins(msg)
|
||||
send2tgs_adminless_only("Mob", msg, R_ADMIN)
|
||||
INVOKE_ASYNC(GLOBAL_PROC, .proc/send2tgs_adminless_only, "Mob", msg, R_ADMIN)
|
||||
log_game("[key_name(src)] was found to have no .loc with an attached client.")
|
||||
|
||||
// This is a temporary error tracker to make sure we've caught everything
|
||||
|
||||
@@ -274,7 +274,7 @@
|
||||
|
||||
/mob/living/on_attack_hand(mob/user, act_intent = user.a_intent, attackchain_flags)
|
||||
..() //Ignoring parent return value here.
|
||||
SEND_SIGNAL(src, COMSIG_MOB_ATTACK_HAND, user)
|
||||
SEND_SIGNAL(src, COMSIG_MOB_ATTACK_HAND, user, act_intent)
|
||||
if((user != src) && act_intent != INTENT_HELP && (mob_run_block(user, 0, user.name, ATTACK_TYPE_UNARMED | ATTACK_TYPE_MELEE | ((attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE), null, user, check_zone(user.zone_selected), null) & BLOCK_SUCCESS))
|
||||
log_combat(user, src, "attempted to touch")
|
||||
visible_message("<span class='warning'>[user] attempted to touch [src]!</span>",
|
||||
@@ -514,10 +514,21 @@
|
||||
/mob/living/ratvar_act()
|
||||
if(status_flags & GODMODE)
|
||||
return
|
||||
if(stat != DEAD && !is_servant_of_ratvar(src))
|
||||
if(stat == DEAD || is_servant_of_ratvar(src))
|
||||
return
|
||||
if(is_eligible_servant(src))
|
||||
add_servant_of_ratvar(src)
|
||||
to_chat(src, "<span class='heavy_brass'>Ratvar's influence invades your mind, praise the Justiciar!</span>")
|
||||
else
|
||||
to_chat(src, "<span class='userdanger'>A blinding light boils you alive! <i>Run!</i></span>")
|
||||
adjust_fire_stacks(20)
|
||||
adjustFireLoss(35)
|
||||
IgniteMob()
|
||||
if(iscultist(src))
|
||||
to_chat(src, "<span class='userdanger'>You resist Ratvar's influence... but not all of it! <i>Run!</i></span>")
|
||||
adjustFireLoss(35)
|
||||
if(src && reagents)
|
||||
reagents.add_reagent(/datum/reagent/fuel/holyoil, 5)
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -550,3 +561,9 @@
|
||||
|
||||
/mob/living/proc/getFireLoss_nonProsthetic()
|
||||
return getFireLoss()
|
||||
|
||||
/mob/living/proc/set_last_attacker(mob/attacker)
|
||||
lastattacker = attacker.real_name
|
||||
lastattackerckey = attacker.ckey
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_ATTACKER_SET, attacker)
|
||||
SEND_SIGNAL(attacker, COMSIG_LIVING_SET_AS_ATTACKER, src)
|
||||
|
||||
@@ -90,11 +90,11 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
var/static/list/one_character_prefix = list(MODE_HEADSET = TRUE, MODE_ROBOT = TRUE, MODE_WHISPER = TRUE)
|
||||
|
||||
var/ic_blocked = FALSE
|
||||
/*
|
||||
if(client && !forced && config.ic_filter_regex && findtext(message, config.ic_filter_regex))
|
||||
|
||||
if(client && !forced && CHAT_FILTER_CHECK(message))
|
||||
//The filter doesn't act on the sanitized message, but the raw message.
|
||||
ic_blocked = TRUE
|
||||
*/
|
||||
|
||||
if(sanitize)
|
||||
message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN))
|
||||
if(!message || message == "")
|
||||
@@ -103,6 +103,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
if(ic_blocked)
|
||||
//The filter warning message shows the sanitized message though.
|
||||
to_chat(src, "<span class='warning'>That message contained a word prohibited in IC chat! Consider reviewing the server rules.\n<span replaceRegex='show_filtered_ic_chat'>\"[message]\"</span></span>")
|
||||
SSblackbox.record_feedback("tally", "ic_blocked_words", 1, lowertext(config.ic_filter_regex.match))
|
||||
return
|
||||
|
||||
var/datum/saymode/saymode = SSradio.saymodes[talk_key]
|
||||
@@ -333,7 +334,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
var/obj/item/bodypart/rightarm = get_bodypart(BODY_ZONE_R_ARM)
|
||||
if(HAS_TRAIT(src, TRAIT_MUTE) && get_selected_language() != /datum/language/signlanguage)
|
||||
return 0
|
||||
|
||||
|
||||
if (get_selected_language() == /datum/language/signlanguage)
|
||||
var/left_disabled = FALSE
|
||||
var/right_disabled = FALSE
|
||||
|
||||
@@ -92,12 +92,9 @@
|
||||
name = "ai_multicam_room"
|
||||
icon_state = "ai_camera_room"
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
|
||||
valid_territory = FALSE
|
||||
ambientsounds = list()
|
||||
blob_allowed = FALSE
|
||||
noteleport = TRUE
|
||||
hidden = TRUE
|
||||
safe = TRUE
|
||||
area_flags = NOTELEPORT | HIDDEN_AREA | UNIQUE_AREA
|
||||
ambientsounds = null
|
||||
flags_1 = NONE
|
||||
|
||||
GLOBAL_DATUM(ai_camera_room_landmark, /obj/effect/landmark/ai_multicam_room)
|
||||
|
||||
|
||||
@@ -1059,5 +1059,5 @@ Pass a positive integer as an argument to override a bot's default speed.
|
||||
I.icon_state = null
|
||||
path.Cut(1, 2)
|
||||
|
||||
/mob/living/silicon/rust_heretic_act()
|
||||
/mob/living/simple_animal/bot/rust_heretic_act()
|
||||
adjustBruteLoss(500)
|
||||
|
||||
@@ -192,6 +192,11 @@
|
||||
back.contract_next_chain_into_single_tile()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/eldritch/armsy/proc/get_length()
|
||||
. += 1
|
||||
if(back)
|
||||
. += back.get_length()
|
||||
|
||||
///Updates the next mob in the chain to move to our last location, fixed the worm if somehow broken.
|
||||
/mob/living/simple_animal/hostile/eldritch/armsy/proc/update_chain_links()
|
||||
gib_trail()
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
verb_yell = "buzzes intensely"
|
||||
emote_see = list("buzzes.", "makes a loud buzz.", "rolls several times.", "buzzes happily.")
|
||||
speak_chance = 1
|
||||
unique_name = TRUE
|
||||
unique_name = FALSE
|
||||
|
||||
/mob/living/simple_animal/pet/bumbles/Initialize()
|
||||
. = ..()
|
||||
|
||||
@@ -425,7 +425,9 @@
|
||||
/mob/living/simple_animal/pet/dog/corgi/Ian/BiologicalLife()
|
||||
if(!(. = ..()))
|
||||
return
|
||||
INVOKE_ASYNC(src, .proc/corgi_ai_behavior)
|
||||
|
||||
/mob/living/simple_animal/pet/dog/corgi/Ian/proc/corgi_ai_behavior()
|
||||
//Feeding, chasing food, FOOOOODDDD
|
||||
if(!stat && CHECK_MULTIPLE_BITFIELDS(mobility_flags, MOBILITY_STAND|MOBILITY_MOVE) && !buckled)
|
||||
turns_since_scan++
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
//Drone hands
|
||||
|
||||
|
||||
/mob/living/simple_animal/drone/doUnEquip(obj/item/I, force, silent = FALSE)
|
||||
/mob/living/simple_animal/drone/doUnEquip(obj/item/I, force, newloc, no_move, invdrop = TRUE, silent = FALSE)
|
||||
if(..())
|
||||
update_inv_hands()
|
||||
if(I == head)
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
melee_damage_upper = 25
|
||||
attack_verb_continuous = "slashes"
|
||||
attack_verb_simple = "slash"
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
speak_emote = list("hisses")
|
||||
bubble_icon = "alien"
|
||||
a_intent = INTENT_HARM
|
||||
@@ -36,7 +37,6 @@
|
||||
see_in_dark = 8
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
unique_name = 1
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
death_sound = 'sound/voice/hiss6.ogg'
|
||||
deathmessage = "lets out a waning guttural screech, green blood bubbling from its maw..."
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
/obj/item/stack/sheet/animalhide/xeno = 1)
|
||||
projectiletype = /obj/item/projectile/neurotox
|
||||
projectilesound = 'sound/weapons/pierce.ogg'
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
status_flags = 0
|
||||
unique_name = 0
|
||||
var/sterile = 1
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#define MEDAL_PREFIX "Bubblegum"
|
||||
|
||||
/*
|
||||
|
||||
BUBBLEGUM
|
||||
@@ -7,24 +5,25 @@ BUBBLEGUM
|
||||
Bubblegum spawns randomly wherever a lavaland creature is able to spawn. It is the most powerful slaughter demon in existence.
|
||||
Bubblegum's footsteps are heralded by shaking booms, proving its tremendous size.
|
||||
|
||||
It acts as a melee creature, chasing down and attacking its target while also using different attacks to augment its power that increase as it takes damage.
|
||||
It acts as a melee creature, chasing down and attacking its target while also using different attacks to augment its power
|
||||
|
||||
It often charges, dealing massive damage to anything unfortunate enough to be standing where it's aiming.
|
||||
Whenever it isn't chasing something down, it will sink into nearby blood pools (if possible) and springs out of the closest one to its target.
|
||||
To make this possible, it sprays streams of blood at random.
|
||||
From these blood pools Bubblegum may summon slaughterlings - weak, low-damage minions designed to impede the target's progress.
|
||||
It leaves blood trails behind wherever it goes, its clones do as well.
|
||||
It tries to strike at its target through any bloodpools under them; if it fails to do that.
|
||||
If it does warp it will enter an enraged state, becoming immune to all projectiles, becoming much faster, and dealing damage and knockback to anything that gets in the cloud around it.
|
||||
It may summon clones charging from all sides, one of these charges being bubblegum himself.
|
||||
It can charge at its target, and also heavily damaging anything directly hit in the charge.
|
||||
If at half health it will start to charge from all sides with clones.
|
||||
|
||||
When Bubblegum dies, it leaves behind a H.E.C.K. suit+helmet as well as a chest that can contain three things:
|
||||
1. A spellblade that can slice off limbs at range
|
||||
2. A bottle that, when activated, drives everyone nearby into a frenzy
|
||||
3. A super double-barrel shotgun that shoots both shells at the same time.
|
||||
When Bubblegum dies, it leaves behind a H.E.C.K. mining suit as well as a chest that can contain three things:
|
||||
1. A bottle that, when activated, drives everyone nearby into a frenzy
|
||||
2. A scroll that teaches the reader a martial art that sacrifices health for raw demonic power with their bare hands.
|
||||
|
||||
Difficulty: Hard
|
||||
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum
|
||||
name = "bubblegum"
|
||||
name = "Bubblegum"
|
||||
desc = "In what passes for a hierarchy among slaughter demons, this one is king."
|
||||
health = 2500
|
||||
maxHealth = 2500
|
||||
@@ -42,15 +41,20 @@ Difficulty: Hard
|
||||
melee_damage_lower = 40
|
||||
melee_damage_upper = 40
|
||||
speed = 1
|
||||
move_to_delay = 10
|
||||
ranged_cooldown_time = 10
|
||||
move_to_delay = 5
|
||||
retreat_distance = 5
|
||||
minimum_distance = 5
|
||||
rapid_melee = 8 // every 1/4 second
|
||||
melee_queue_distance = 20 // as far as possible really, need this because of blood warp
|
||||
ranged = 1
|
||||
pixel_x = -32
|
||||
gender = MALE
|
||||
del_on_death = 1
|
||||
crusher_loot = list(/obj/structure/closet/crate/necropolis/bubblegum/crusher)
|
||||
loot = list(/obj/structure/closet/crate/necropolis/bubblegum)
|
||||
blood_volume = BLOOD_VOLUME_MAXIMUM //BLEED FOR ME
|
||||
var/charging = 0
|
||||
var/enrage_till = null
|
||||
|
||||
achievement_type = /datum/award/achievement/boss/bubblegum_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/bubblegum_crusher
|
||||
@@ -67,36 +71,60 @@ Difficulty: Hard
|
||||
desc = "You're not quite sure how a signal can be bloody."
|
||||
invisibility = 100
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/BiologicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
move_to_delay = clamp(round((health/maxHealth) * 10), 3, 10)
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE, only_robotic = FALSE, only_organic = TRUE)
|
||||
. = ..()
|
||||
if(. > 0 && prob(25))
|
||||
var/obj/effect/decal/cleanable/blood/gibs/bubblegum/B = new /obj/effect/decal/cleanable/blood/gibs/bubblegum(loc)
|
||||
if(prob(40))
|
||||
step(B, pick(GLOB.cardinals))
|
||||
else
|
||||
B.setDir(pick(GLOB.cardinals))
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/bubblegum
|
||||
name = "thick blood"
|
||||
desc = "Thick, splattered blood."
|
||||
random_icon_states = list("gib3", "gib5", "gib6")
|
||||
bloodiness = 20
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/bubblegum/can_bloodcrawl_in()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/OpenFire()
|
||||
anger_modifier = clamp(((maxHealth - health)/50),0,20)
|
||||
anger_modifier = clamp(((maxHealth - health)/60),0,20)
|
||||
if(charging)
|
||||
return
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
ranged_cooldown = world.time + 50
|
||||
if(!try_bloodattack())
|
||||
blood_warp()
|
||||
|
||||
blood_warp()
|
||||
|
||||
if(prob(25))
|
||||
INVOKE_ASYNC(src, .proc/blood_spray)
|
||||
|
||||
else if(prob(5+anger_modifier/2))
|
||||
slaughterlings()
|
||||
else
|
||||
if(health > maxHealth/2 && !client)
|
||||
INVOKE_ASYNC(src, .proc/charge)
|
||||
if(health > maxHealth * 0.5)
|
||||
if(prob(50 + anger_modifier))
|
||||
charge(delay = 6)
|
||||
charge(delay = 4) // The FitnessGram Pacer Test is a multistage aerobic capacity test that progressively gets more difficult as it continues.
|
||||
charge(delay = 2)
|
||||
SetRecoveryTime(15)
|
||||
else
|
||||
INVOKE_ASYNC(src, .proc/triple_charge)
|
||||
hallucination_charge_around(times = 6, delay = 10 - anger_modifier / 5)
|
||||
SetRecoveryTime(10)
|
||||
else
|
||||
if(prob(50 - anger_modifier))
|
||||
hallucination_charge_around(times = 4, delay = 9)
|
||||
hallucination_charge_around(times = 4, delay = 8)
|
||||
hallucination_charge_around(times = 4, delay = 7)
|
||||
SetRecoveryTime(15)
|
||||
else
|
||||
for(var/i = 1 to 5)
|
||||
INVOKE_ASYNC(src, .proc/hallucination_charge_around, 2, 10, 2, 0)
|
||||
sleep(5)
|
||||
SetRecoveryTime(10)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Initialize()
|
||||
. = ..()
|
||||
for(var/mob/living/simple_animal/hostile/megafauna/bubblegum/B in GLOB.mob_list)
|
||||
if(B != src)
|
||||
return INITIALIZE_HINT_QDEL //There can be only one
|
||||
if(istype(src, /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination))
|
||||
return
|
||||
for(var/mob/living/simple_animal/hostile/megafauna/bubblegum/B in GLOB.mob_living_list) if(B != src)
|
||||
return INITIALIZE_HINT_QDEL //There can be only one
|
||||
var/obj/effect/proc_holder/spell/bloodcrawl/bloodspell = new
|
||||
AddSpell(bloodspell)
|
||||
if(istype(loc, /obj/effect/dummy/phased_mob/slaughter))
|
||||
@@ -109,52 +137,78 @@ Difficulty: Hard
|
||||
SSshuttle.shuttle_purchase_requirements_met |= "bubblegum"
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
|
||||
if(charging)
|
||||
return
|
||||
..()
|
||||
if(!charging)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/AttackingTarget()
|
||||
if(charging)
|
||||
if(!charging)
|
||||
. = ..()
|
||||
if(.)
|
||||
recovery_time = world.time + 20 // can only attack melee once every 2 seconds but rapid_melee gives higher priority
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/bullet_act(obj/item/projectile/P)
|
||||
if(is_enraged())
|
||||
visible_message("<span class='danger'>[src] deflects the projectile; [p_they()] can't be hit with ranged weapons while enraged!</span>", "<span class='userdanger'>You deflect the projectile!</span>")
|
||||
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 300, 1)
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/ex_act(severity, target)
|
||||
if(severity >= EXPLODE_LIGHT)
|
||||
return
|
||||
..()
|
||||
severity = EXPLODE_LIGHT // puny mortals
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination))
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Goto(target, delay, minimum_distance)
|
||||
if(charging)
|
||||
return
|
||||
..()
|
||||
if(!charging)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/MoveToTarget(list/possible_targets)
|
||||
if(!charging)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Move()
|
||||
if(!stat)
|
||||
playsound(src.loc, 'sound/effects/meteorimpact.ogg', 200, 1, 2, 1)
|
||||
if(charging)
|
||||
new/obj/effect/temp_visual/decoy/fading(loc,src)
|
||||
new /obj/effect/temp_visual/decoy/fading(loc,src)
|
||||
DestroySurroundings()
|
||||
. = ..()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Moved()
|
||||
new /obj/effect/decal/cleanable/blood(src.loc)
|
||||
if(charging)
|
||||
DestroySurroundings()
|
||||
playsound(src, 'sound/effects/meteorimpact.ogg', 200, 1, 2, 1)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/triple_charge()
|
||||
charge()
|
||||
sleep(10)
|
||||
charge()
|
||||
sleep(10)
|
||||
charge()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge()
|
||||
var/turf/T = get_turf(target)
|
||||
if(!T || T == loc)
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge(atom/chargeat = target, delay = 3, chargepast = 2)
|
||||
if(!chargeat)
|
||||
return
|
||||
new /obj/effect/temp_visual/dragon_swoop(T)
|
||||
var/chargeturf = get_turf(chargeat)
|
||||
if(!chargeturf)
|
||||
return
|
||||
var/dir = get_dir(src, chargeturf)
|
||||
var/turf/T = get_ranged_target_turf(chargeturf, dir, chargepast)
|
||||
if(!T)
|
||||
return
|
||||
new /obj/effect/temp_visual/dragon_swoop/bubblegum(T)
|
||||
charging = 1
|
||||
DestroySurroundings()
|
||||
walk(src, 0)
|
||||
setDir(get_dir(src, T))
|
||||
setDir(dir)
|
||||
var/obj/effect/temp_visual/decoy/D = new /obj/effect/temp_visual/decoy(loc,src)
|
||||
animate(D, alpha = 0, color = "#FF0000", transform = matrix()*2, time = 5)
|
||||
sleep(5)
|
||||
throw_at(T, get_dist(src, T), 1, src, 0)
|
||||
animate(D, alpha = 0, color = "#FF0000", transform = matrix()*2, time = 3)
|
||||
sleep(delay)
|
||||
var/movespeed = 0.7
|
||||
walk_towards(src, T, movespeed)
|
||||
sleep(get_dist(src, T) * movespeed)
|
||||
walk(src, 0) // cancel the movement
|
||||
try_bloodattack()
|
||||
charging = 0
|
||||
Goto(target, move_to_delay, minimum_distance)
|
||||
|
||||
/**
|
||||
* Attack by override for bubblegum
|
||||
@@ -176,36 +230,147 @@ Difficulty: Hard
|
||||
if(isturf(A) || isobj(A) && A.density)
|
||||
A.ex_act(EXPLODE_HEAVY)
|
||||
DestroySurroundings()
|
||||
if(isliving(A))
|
||||
var/mob/living/L = A
|
||||
L.visible_message("<span class='danger'>[src] slams into [L]!</span>", "<span class='userdanger'>[src] tramples you into the ground!</span>")
|
||||
src.forceMove(get_turf(L))
|
||||
L.apply_damage(istype(src, /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination) ? 15 : 30, BRUTE)
|
||||
playsound(get_turf(L), 'sound/effects/meteorimpact.ogg', 100, 1)
|
||||
shake_camera(L, 4, 3)
|
||||
shake_camera(src, 2, 3)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
|
||||
if(!charging)
|
||||
return ..()
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_mobs_on_blood()
|
||||
var/list/targets = ListTargets()
|
||||
. = list()
|
||||
for(var/mob/living/L in targets)
|
||||
var/list/bloodpool = get_pools(get_turf(L), 0)
|
||||
if(bloodpool.len && (!faction_check_mob(L) || L.stat == DEAD))
|
||||
. += L
|
||||
|
||||
else if(isliving(hit_atom))
|
||||
var/mob/living/L = hit_atom
|
||||
L.visible_message("<span class='danger'>[src] slams into [L]!</span>", "<span class='userdanger'>[src] slams into you!</span>")
|
||||
L.apply_damage(40, BRUTE)
|
||||
playsound(get_turf(L), 'sound/effects/meteorimpact.ogg', 100, 1)
|
||||
shake_camera(L, 4, 3)
|
||||
shake_camera(src, 2, 3)
|
||||
var/throwtarget = get_edge_target_turf(src, get_dir(src, get_step_away(L, src)))
|
||||
L.throw_at(throwtarget, 3)
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/try_bloodattack()
|
||||
var/list/targets = get_mobs_on_blood()
|
||||
if(targets.len)
|
||||
INVOKE_ASYNC(src, .proc/bloodattack, targets, prob(50))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
charging = 0
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodattack(list/targets, handedness)
|
||||
var/mob/living/target_one = pick_n_take(targets)
|
||||
var/turf/target_one_turf = get_turf(target_one)
|
||||
var/mob/living/target_two
|
||||
if(targets.len)
|
||||
target_two = pick_n_take(targets)
|
||||
var/turf/target_two_turf = get_turf(target_two)
|
||||
if(target_two.stat != CONSCIOUS || prob(10))
|
||||
bloodgrab(target_two_turf, handedness)
|
||||
else
|
||||
bloodsmack(target_two_turf, handedness)
|
||||
|
||||
if(target_one)
|
||||
var/list/pools = get_pools(get_turf(target_one), 0)
|
||||
if(pools.len)
|
||||
target_one_turf = get_turf(target_one)
|
||||
if(target_one_turf)
|
||||
if(target_one.stat != CONSCIOUS || prob(10))
|
||||
bloodgrab(target_one_turf, !handedness)
|
||||
else
|
||||
bloodsmack(target_one_turf, !handedness)
|
||||
|
||||
if(!target_two && target_one)
|
||||
var/list/poolstwo = get_pools(get_turf(target_one), 0)
|
||||
if(poolstwo.len)
|
||||
target_one_turf = get_turf(target_one)
|
||||
if(target_one_turf)
|
||||
if(target_one.stat != CONSCIOUS || prob(10))
|
||||
bloodgrab(target_one_turf, handedness)
|
||||
else
|
||||
bloodsmack(target_one_turf, handedness)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodsmack(turf/T, handedness)
|
||||
if(handedness)
|
||||
new /obj/effect/temp_visual/bubblegum_hands/rightsmack(T)
|
||||
else
|
||||
new /obj/effect/temp_visual/bubblegum_hands/leftsmack(T)
|
||||
sleep(4)
|
||||
for(var/mob/living/L in T)
|
||||
if(!faction_check_mob(L))
|
||||
to_chat(L, "<span class='userdanger'>[src] rends you!</span>")
|
||||
playsound(T, attack_sound, 100, 1, -1)
|
||||
var/limb_to_hit = L.get_bodypart(pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG))
|
||||
L.apply_damage(10, BRUTE, limb_to_hit, L.run_armor_check(limb_to_hit, "melee", null, null, armour_penetration))
|
||||
sleep(3)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodgrab(turf/T, handedness)
|
||||
if(handedness)
|
||||
new /obj/effect/temp_visual/bubblegum_hands/rightpaw(T)
|
||||
new /obj/effect/temp_visual/bubblegum_hands/rightthumb(T)
|
||||
else
|
||||
new /obj/effect/temp_visual/bubblegum_hands/leftpaw(T)
|
||||
new /obj/effect/temp_visual/bubblegum_hands/leftthumb(T)
|
||||
sleep(6)
|
||||
for(var/mob/living/L in T)
|
||||
if(!faction_check_mob(L))
|
||||
if(L.stat != CONSCIOUS)
|
||||
to_chat(L, "<span class='userdanger'>[src] drags you through the blood!</span>")
|
||||
playsound(T, 'sound/magic/enter_blood.ogg', 100, 1, -1)
|
||||
var/turf/targetturf = get_step(src, dir)
|
||||
L.forceMove(targetturf)
|
||||
playsound(targetturf, 'sound/magic/exit_blood.ogg', 100, 1, -1)
|
||||
addtimer(CALLBACK(src, .proc/devour, L), 2)
|
||||
sleep(1)
|
||||
|
||||
/obj/effect/temp_visual/dragon_swoop/bubblegum
|
||||
duration = 10
|
||||
|
||||
/obj/effect/temp_visual/bubblegum_hands
|
||||
icon = 'icons/effects/bubblegum.dmi'
|
||||
duration = 9
|
||||
|
||||
/obj/effect/temp_visual/bubblegum_hands/rightthumb
|
||||
icon_state = "rightthumbgrab"
|
||||
|
||||
/obj/effect/temp_visual/bubblegum_hands/leftthumb
|
||||
icon_state = "leftthumbgrab"
|
||||
|
||||
/obj/effect/temp_visual/bubblegum_hands/rightpaw
|
||||
icon_state = "rightpawgrab"
|
||||
layer = BELOW_MOB_LAYER
|
||||
|
||||
/obj/effect/temp_visual/bubblegum_hands/leftpaw
|
||||
icon_state = "leftpawgrab"
|
||||
layer = BELOW_MOB_LAYER
|
||||
|
||||
/obj/effect/temp_visual/bubblegum_hands/rightsmack
|
||||
icon_state = "rightsmack"
|
||||
|
||||
/obj/effect/temp_visual/bubblegum_hands/leftsmack
|
||||
icon_state = "leftsmack"
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_warp()
|
||||
if(Adjacent(target) || (enrage_till + 30 > world.time))
|
||||
return FALSE
|
||||
var/list/can_jaunt = get_pools(get_turf(src), 1)
|
||||
if(!can_jaunt.len)
|
||||
return FALSE
|
||||
|
||||
var/list/pools = get_pools(get_turf(target), 2)
|
||||
var/list/pools_to_remove = get_pools(get_turf(target), 1)
|
||||
pools -= pools_to_remove
|
||||
if(!pools.len)
|
||||
return FALSE
|
||||
|
||||
var/obj/effect/temp_visual/decoy/DA = new /obj/effect/temp_visual/decoy(loc,src)
|
||||
DA.color = "#FF0000"
|
||||
var/oldtransform = DA.transform
|
||||
DA.transform = matrix()*2
|
||||
animate(DA, alpha = 255, color = initial(DA.color), transform = oldtransform, time = 3)
|
||||
sleep(3)
|
||||
qdel(DA)
|
||||
var/obj/effect/decal/cleanable/blood/found_bloodpool
|
||||
var/list/pools = list()
|
||||
var/can_jaunt = FALSE
|
||||
for(var/obj/effect/decal/cleanable/blood/nearby in view(src,2))
|
||||
can_jaunt = TRUE
|
||||
break
|
||||
if(!can_jaunt)
|
||||
return
|
||||
for(var/obj/effect/decal/cleanable/blood/nearby in view(get_turf(target),2))
|
||||
pools += nearby
|
||||
pools = get_pools(get_turf(target), 2)
|
||||
pools_to_remove = get_pools(get_turf(target), 1)
|
||||
pools -= pools_to_remove
|
||||
if(pools.len)
|
||||
shuffle_inplace(pools)
|
||||
found_bloodpool = pick(pools)
|
||||
@@ -215,48 +380,110 @@ Difficulty: Hard
|
||||
forceMove(get_turf(found_bloodpool))
|
||||
playsound(get_turf(src), 'sound/magic/exit_blood.ogg', 100, 1, -1)
|
||||
visible_message("<span class='danger'>And springs back out!</span>")
|
||||
blood_enrage()
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_enrage(var/boost_time = 30)
|
||||
enrage_till = world.time + boost_time
|
||||
retreat_distance = null
|
||||
minimum_distance = 1
|
||||
change_move_delay(3.75)
|
||||
var/newcolor = rgb(149, 10, 10)
|
||||
add_atom_colour(newcolor, TEMPORARY_COLOUR_PRIORITY)
|
||||
var/datum/callback/cb = CALLBACK(src, .proc/blood_enrage_end)
|
||||
addtimer(cb, boost_time)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_spray()
|
||||
visible_message("<span class='danger'>[src] sprays a stream of gore!</span>")
|
||||
var/turf/E = get_edge_target_turf(src, src.dir)
|
||||
var/range = 10
|
||||
var/turf/previousturf = get_turf(src)
|
||||
for(var/turf/J in getline(src,E))
|
||||
if(!range)
|
||||
break
|
||||
new /obj/effect/temp_visual/dir_setting/bloodsplatter(previousturf, get_dir(previousturf, J))
|
||||
if(!previousturf.CanAtmosPass(J))
|
||||
break
|
||||
playsound(J,'sound/effects/splat.ogg', 100, 1, -1)
|
||||
new /obj/effect/decal/cleanable/blood(J)
|
||||
range--
|
||||
previousturf = J
|
||||
sleep(1)
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_enrage_end(var/newcolor = rgb(149, 10, 10))
|
||||
retreat_distance = initial(retreat_distance)
|
||||
minimum_distance = initial(minimum_distance)
|
||||
change_move_delay()
|
||||
remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, newcolor)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/slaughterlings()
|
||||
visible_message("<span class='danger'>[src] summons a shoal of slaughterlings!</span>")
|
||||
for(var/obj/effect/decal/cleanable/blood/H in range(src, 10))
|
||||
if(prob(25))
|
||||
new /mob/living/simple_animal/hostile/asteroid/hivelordbrood/slaughter(H.loc)
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/is_enraged()
|
||||
return (enrage_till > world.time)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/slaughter
|
||||
name = "slaughterling"
|
||||
desc = "Though not yet strong enough to create a true physical form, it's nonetheless determined to murder you."
|
||||
icon_state = "bloodbrood"
|
||||
icon_living = "bloodbrood"
|
||||
icon_aggro = "bloodbrood"
|
||||
attack_verb_continuous = "pierces"
|
||||
attack_verb_simple = "pierce"
|
||||
color = "#C80000"
|
||||
density = FALSE
|
||||
faction = list("mining", "boss")
|
||||
weather_immunities = list("lava","ash")
|
||||
has_field_of_vision = FALSE
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/change_move_delay(var/newmove = initial(move_to_delay))
|
||||
move_to_delay = newmove
|
||||
handle_automated_action() // need to recheck movement otherwise move_to_delay won't update until the next checking aka will be wrong speed for a bit
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/slaughter/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum))
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_pools(turf/T, range)
|
||||
. = list()
|
||||
for(var/obj/effect/decal/cleanable/nearby in view(T, range))
|
||||
if(nearby.can_bloodcrawl_in())
|
||||
. += nearby
|
||||
|
||||
/obj/effect/decal/cleanable/blood/bubblegum
|
||||
bloodiness = 0
|
||||
|
||||
/obj/effect/decal/cleanable/blood/bubblegum/can_bloodcrawl_in()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/hallucination_charge_around(var/times = 4, var/delay = 6, var/chargepast = 0, var/useoriginal = 1)
|
||||
var/startingangle = rand(1, 360)
|
||||
if(!target)
|
||||
return
|
||||
var/turf/chargeat = get_turf(target)
|
||||
var/srcplaced = 0
|
||||
for(var/i = 1 to times)
|
||||
var/ang = (startingangle + 360/times * i)
|
||||
if(!chargeat)
|
||||
return
|
||||
var/turf/place = locate(chargeat.x + cos(ang) * times, chargeat.y + sin(ang) * times, chargeat.z)
|
||||
if(!place)
|
||||
continue
|
||||
if(!srcplaced && useoriginal)
|
||||
forceMove(place)
|
||||
srcplaced = 1
|
||||
continue
|
||||
var/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/B = new /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination(src.loc)
|
||||
B.forceMove(place)
|
||||
INVOKE_ASYNC(B, .proc/charge, chargeat, delay, chargepast)
|
||||
if(useoriginal)
|
||||
charge(chargeat, delay, chargepast)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination
|
||||
name = "Bubblegum's hallucination"
|
||||
desc = "Is that really just a hallucination?"
|
||||
health = 1
|
||||
maxHealth = 1
|
||||
alpha = 127.5
|
||||
crusher_loot = null
|
||||
loot = null
|
||||
deathmessage = "Explodes into a pool of blood!"
|
||||
deathsound = 'sound/effects/splat.ogg'
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Initialize()
|
||||
..()
|
||||
toggle_ai(AI_OFF)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/charge(atom/chargeat = target, delay = 3, chargepast = 2)
|
||||
..()
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Destroy()
|
||||
new /obj/effect/decal/cleanable/blood(get_turf(src))
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum)) // hallucinations should not be stopping bubblegum or eachother
|
||||
return 1
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
#undef MEDAL_PREFIX
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Life()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE, only_robotic = FALSE, only_organic = TRUE)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/OpenFire()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/AttackingTarget()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/try_bloodattack()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/grant_achievement(medaltype,scoretype)
|
||||
return
|
||||
|
||||
@@ -60,10 +60,10 @@ Difficulty: Medium
|
||||
pixel_x = -16
|
||||
crusher_loot = list(/obj/structure/closet/crate/necropolis/dragon/crusher)
|
||||
loot = list(/obj/structure/closet/crate/necropolis/dragon)
|
||||
butcher_results = list(/obj/item/stack/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/bone = 30)
|
||||
butcher_results = list(/obj/item/stack/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/bone = 30, /obj/item/reagent_containers/food/snacks/meat/slab/dragon = 5)
|
||||
guaranteed_butcher_results = list(/obj/item/stack/sheet/animalhide/ashdrake = 10)
|
||||
var/swooping = NONE
|
||||
var/swoop_cooldown = 0
|
||||
var/player_cooldown = 0
|
||||
achievement_type = /datum/award/achievement/boss/drake_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/drake_crusher
|
||||
score_achievement_type = /datum/award/score/drake_score
|
||||
@@ -116,66 +116,167 @@ Difficulty: Medium
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
|
||||
if(prob(15 + anger_modifier) && !client)
|
||||
if(health < maxHealth/2)
|
||||
INVOKE_ASYNC(src, .proc/swoop_attack, TRUE, null, 50)
|
||||
if(health < maxHealth*0.5)
|
||||
swoop_attack(lava_arena = TRUE)
|
||||
else
|
||||
fire_rain()
|
||||
lava_swoop()
|
||||
|
||||
else if(prob(10+anger_modifier) && !client)
|
||||
if(health > maxHealth/2)
|
||||
INVOKE_ASYNC(src, .proc/swoop_attack)
|
||||
if(health < maxHealth*0.5)
|
||||
mass_fire()
|
||||
else
|
||||
INVOKE_ASYNC(src, .proc/triple_swoop)
|
||||
fire_cone()
|
||||
else
|
||||
fire_walls()
|
||||
if(prob(50) && !client)
|
||||
INVOKE_ASYNC(src, .proc/lava_pools, 10, 2)
|
||||
fire_cone()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_rain()
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/lava_pools(var/amount, var/delay = 0.8)
|
||||
if(!target)
|
||||
return
|
||||
target.visible_message("<span class='boldwarning'>Fire rains from the sky!</span>")
|
||||
for(var/turf/turf in range(9,get_turf(target)))
|
||||
if(prob(11))
|
||||
new /obj/effect/temp_visual/target(turf)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_walls()
|
||||
playsound(get_turf(src),'sound/magic/fireball.ogg', 200, 1)
|
||||
|
||||
for(var/d in GLOB.cardinals)
|
||||
INVOKE_ASYNC(src, .proc/fire_wall, d)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_wall(dir)
|
||||
var/list/hit_things = list(src)
|
||||
var/turf/E = get_edge_target_turf(src, dir)
|
||||
var/range = 10
|
||||
var/turf/previousturf = get_turf(src)
|
||||
for(var/turf/J in getline(src,E))
|
||||
if(!range || (J != previousturf && (!previousturf.atmos_adjacent_turfs || !previousturf.atmos_adjacent_turfs[J])))
|
||||
target.visible_message("<span class='boldwarning'>Lava starts to pool up around you!</span>")
|
||||
while(amount > 0)
|
||||
if(!target)
|
||||
break
|
||||
range--
|
||||
new /obj/effect/hotspot(J)
|
||||
J.hotspot_expose(DRAKE_FIRE_TEMP, DRAKE_FIRE_EXPOSURE, 1)
|
||||
for(var/mob/living/L in J.contents - hit_things)
|
||||
if(istype(L, /mob/living/simple_animal/hostile/megafauna/dragon))
|
||||
var/turf/T = pick(RANGE_TURFS(1, target))
|
||||
new /obj/effect/temp_visual/lava_warning(T, 60) // longer reset time for the lava
|
||||
amount--
|
||||
sleep(delay)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/lava_swoop(var/amount = 30)
|
||||
INVOKE_ASYNC(src, .proc/lava_pools, amount)
|
||||
swoop_attack(FALSE, target, 1000) // longer cooldown until it gets reset below
|
||||
fire_cone()
|
||||
if(health < maxHealth*0.5)
|
||||
sleep(10)
|
||||
fire_cone()
|
||||
sleep(10)
|
||||
fire_cone()
|
||||
SetRecoveryTime(40)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/mass_fire(var/spiral_count = 12, var/range = 15, var/times = 3)
|
||||
for(var/i = 1 to times)
|
||||
SetRecoveryTime(50)
|
||||
playsound(get_turf(src),'sound/magic/fireball.ogg', 200, 1)
|
||||
var/increment = 360 / spiral_count
|
||||
for(var/j = 1 to spiral_count)
|
||||
var/list/turfs = line_target(j * increment + i * increment / 2, range, src)
|
||||
INVOKE_ASYNC(src, .proc/fire_line, turfs)
|
||||
sleep(25)
|
||||
SetRecoveryTime(30)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/lava_arena()
|
||||
if(!target)
|
||||
return
|
||||
target.visible_message("<span class='boldwarning'>[src] encases you in an arena of fire!</span>")
|
||||
var/amount = 3
|
||||
var/turf/center = get_turf(target)
|
||||
var/list/walled = RANGE_TURFS(3, center) - RANGE_TURFS(2, center)
|
||||
var/list/drakewalls = list()
|
||||
for(var/turf/T in walled)
|
||||
drakewalls += new /obj/effect/temp_visual/drakewall(T) // no people with lava immunity can just run away from the attack for free
|
||||
var/list/indestructible_turfs = list()
|
||||
for(var/turf/T in RANGE_TURFS(2, center))
|
||||
if(istype(T, /turf/open/indestructible))
|
||||
continue
|
||||
if(!istype(T, /turf/closed/indestructible))
|
||||
T.ChangeTurf(/turf/open/floor/plating/asteroid/basalt/lava_land_surface)
|
||||
else
|
||||
indestructible_turfs += T
|
||||
sleep(10) // give them a bit of time to realize what attack is actually happening
|
||||
|
||||
var/list/turfs = RANGE_TURFS(2, center)
|
||||
while(amount > 0)
|
||||
var/list/empty = indestructible_turfs.Copy() // can't place safe turfs on turfs that weren't changed to be open
|
||||
var/any_attack = 0
|
||||
for(var/turf/T in turfs)
|
||||
for(var/mob/living/L in T.contents)
|
||||
if(L.client)
|
||||
empty += pick(((RANGE_TURFS(2, L) - RANGE_TURFS(1, L)) & turfs) - empty) // picks a turf within 2 of the creature not outside or in the shield
|
||||
any_attack = 1
|
||||
for(var/obj/mecha/M in T.contents)
|
||||
empty += pick(((RANGE_TURFS(2, M) - RANGE_TURFS(1, M)) & turfs) - empty)
|
||||
any_attack = 1
|
||||
if(!any_attack)
|
||||
for(var/obj/effect/temp_visual/drakewall/D in drakewalls)
|
||||
qdel(D)
|
||||
return 0 // nothing to attack in the arena time for enraged attack if we still have a target
|
||||
for(var/turf/T in turfs)
|
||||
if(!(T in empty))
|
||||
new /obj/effect/temp_visual/lava_warning(T)
|
||||
else if(!istype(T, /turf/closed/indestructible))
|
||||
new /obj/effect/temp_visual/lava_safe(T)
|
||||
amount--
|
||||
sleep(24)
|
||||
return 1 // attack finished completely
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/arena_escape_enrage() // you ran somehow / teleported away from my arena attack now i'm mad fucker
|
||||
SetRecoveryTime(80)
|
||||
visible_message("<span class='boldwarning'>[src] starts to glow vibrantly as its wounds close up!</span>")
|
||||
adjustBruteLoss(-250) // yeah you're gonna pay for that, don't run nerd
|
||||
add_atom_colour(rgb(255, 255, 0), TEMPORARY_COLOUR_PRIORITY)
|
||||
move_to_delay = move_to_delay / 2
|
||||
light_range = 10
|
||||
sleep(10) // run.
|
||||
mass_fire(20, 15, 3)
|
||||
remove_atom_colour(TEMPORARY_COLOUR_PRIORITY)
|
||||
move_to_delay = initial(move_to_delay)
|
||||
light_range = initial(light_range)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_cone(var/atom/at = target)
|
||||
playsound(get_turf(src),'sound/magic/fireball.ogg', 200, 1)
|
||||
if(QDELETED(src) || stat == DEAD) // we dead no fire
|
||||
return
|
||||
var/range = 15
|
||||
var/list/turfs = list()
|
||||
turfs = line_target(-40, range, at)
|
||||
INVOKE_ASYNC(src, .proc/fire_line, turfs)
|
||||
turfs = line_target(0, range, at)
|
||||
INVOKE_ASYNC(src, .proc/fire_line, turfs)
|
||||
turfs = line_target(40, range, at)
|
||||
INVOKE_ASYNC(src, .proc/fire_line, turfs)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/line_target(var/offset, var/range, var/atom/at = target)
|
||||
if(!at)
|
||||
return
|
||||
var/angle = ATAN2(at.x - src.x, at.y - src.y) + offset
|
||||
var/turf/T = get_turf(src)
|
||||
for(var/i in 1 to range)
|
||||
var/turf/check = locate(src.x + cos(angle) * i, src.y + sin(angle) * i, src.z)
|
||||
if(!check)
|
||||
break
|
||||
T = check
|
||||
return (getline(src, T) - get_turf(src))
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_line(var/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 == src)
|
||||
continue
|
||||
hit_list += L
|
||||
L.adjustFireLoss(20)
|
||||
to_chat(L, "<span class='userdanger'>You're hit by the drake's fire breath!</span>")
|
||||
hit_things += L
|
||||
previousturf = J
|
||||
sleep(1)
|
||||
to_chat(L, "<span class='userdanger'>You're hit by [src]'s fire breath!</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/triple_swoop()
|
||||
swoop_attack(swoop_duration = 30)
|
||||
swoop_attack(swoop_duration = 30)
|
||||
swoop_attack(swoop_duration = 30)
|
||||
// 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)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/swoop_attack(fire_rain, atom/movable/manual_target, swoop_duration = 40)
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/swoop_attack(lava_arena = FALSE, atom/movable/manual_target, var/swoop_cooldown = 30)
|
||||
if(stat || swooping)
|
||||
return
|
||||
if(manual_target)
|
||||
target = manual_target
|
||||
if(!target)
|
||||
return
|
||||
swoop_cooldown = world.time + 200
|
||||
stop_automated_movement = TRUE
|
||||
swooping |= SWOOP_DAMAGEABLE
|
||||
density = FALSE
|
||||
@@ -209,32 +310,16 @@ Difficulty: Medium
|
||||
swooping |= SWOOP_INVULNERABLE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
sleep(7)
|
||||
var/list/flame_hit = list()
|
||||
while(swoop_duration > 0)
|
||||
if(!target && !FindTarget())
|
||||
break //we lost our target while chasing it down and couldn't get a new one
|
||||
if(swoop_duration < 7)
|
||||
fire_rain = FALSE //stop raining fire near the end of the swoop
|
||||
if(loc == get_turf(target))
|
||||
if(!fire_rain)
|
||||
break //we're not spewing fire at our target, slam they
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(L.stat == DEAD)
|
||||
break //target is dead and we're on em, slam they
|
||||
if(fire_rain)
|
||||
new /obj/effect/temp_visual/target(loc, flame_hit)
|
||||
|
||||
while(target && loc != get_turf(target))
|
||||
forceMove(get_step(src, get_dir(src, target)))
|
||||
if(loc == get_turf(target))
|
||||
if(!fire_rain)
|
||||
break
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(L.stat == DEAD)
|
||||
break
|
||||
var/swoop_speed = 1.5
|
||||
swoop_duration -= swoop_speed
|
||||
sleep(swoop_speed)
|
||||
sleep(0.5)
|
||||
|
||||
// Ash drake flies onto its target and rains fire down upon them
|
||||
var/descentTime = 10;
|
||||
var/lava_success = 1
|
||||
if(lava_arena)
|
||||
lava_success = lava_arena()
|
||||
|
||||
//ensure swoop direction continuity.
|
||||
if(negative)
|
||||
@@ -245,8 +330,8 @@ Difficulty: Medium
|
||||
negative = TRUE
|
||||
new /obj/effect/temp_visual/dragon_flight/end(loc, negative)
|
||||
new /obj/effect/temp_visual/dragon_swoop(loc)
|
||||
animate(src, alpha = 255, transform = oldtransform, time = 5)
|
||||
sleep(5)
|
||||
animate(src, alpha = 255, transform = oldtransform, descentTime)
|
||||
sleep(descentTime)
|
||||
swooping &= ~SWOOP_INVULNERABLE
|
||||
mouse_opacity = initial(mouse_opacity)
|
||||
icon_state = "dragon"
|
||||
@@ -264,6 +349,8 @@ Difficulty: Medium
|
||||
var/throwtarget = get_edge_target_turf(src, throw_dir)
|
||||
L.throw_at(throwtarget, 3)
|
||||
visible_message("<span class='warning'>[L] is thrown clear of [src]!</span>")
|
||||
for(var/obj/mecha/M in orange(1, src))
|
||||
M.take_damage(75, BRUTE, "melee", 1)
|
||||
|
||||
for(var/mob/M in range(7, src))
|
||||
shake_camera(M, 15, 1)
|
||||
@@ -271,16 +358,20 @@ Difficulty: Medium
|
||||
density = TRUE
|
||||
sleep(1)
|
||||
swooping &= ~SWOOP_DAMAGEABLE
|
||||
SetRecoveryTime(MEGAFAUNA_DEFAULT_RECOVERY_TIME)
|
||||
SetRecoveryTime(swoop_cooldown)
|
||||
if(!lava_success)
|
||||
arena_escape_enrage()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/AltClickOn(atom/movable/A)
|
||||
if(!istype(A))
|
||||
AltClickNoInteract(src, A)
|
||||
return
|
||||
if(swoop_cooldown >= world.time)
|
||||
to_chat(src, "<span class='warning'>You need to wait 20 seconds between swoop attacks!</span>")
|
||||
if(player_cooldown >= world.time)
|
||||
to_chat(src, "<span class='warning'>You need to wait [(player_cooldown - world.time) / 10] seconds before swooping again!</span>")
|
||||
return
|
||||
swoop_attack(TRUE, A, 25)
|
||||
swoop_attack(FALSE, A)
|
||||
lava_pools(10, 2) // less pools but longer delay before spawns
|
||||
player_cooldown = world.time + 200 // needs seperate cooldown or cant use fire attacks
|
||||
|
||||
/obj/item/gps/internal/dragon
|
||||
icon_state = null
|
||||
@@ -289,54 +380,63 @@ Difficulty: Medium
|
||||
invisibility = 100
|
||||
|
||||
|
||||
/obj/effect/temp_visual/fireball
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "fireball"
|
||||
name = "fireball"
|
||||
desc = "Get out of the way!"
|
||||
layer = FLY_LAYER
|
||||
randomdir = FALSE
|
||||
duration = 9
|
||||
pixel_z = DRAKE_SWOOP_HEIGHT
|
||||
|
||||
/obj/effect/temp_visual/fireball/Initialize()
|
||||
. = ..()
|
||||
animate(src, pixel_z = 0, time = duration)
|
||||
|
||||
/obj/effect/temp_visual/target
|
||||
icon = 'icons/mob/actions/actions_items.dmi'
|
||||
icon_state = "sniper_zoom"
|
||||
/obj/effect/temp_visual/lava_warning
|
||||
icon_state = "lavastaff_warn"
|
||||
layer = BELOW_MOB_LAYER
|
||||
light_range = 2
|
||||
duration = 9
|
||||
duration = 13
|
||||
|
||||
/obj/effect/temp_visual/target/ex_act()
|
||||
/obj/effect/temp_visual/lava_warning/ex_act()
|
||||
return
|
||||
|
||||
/obj/effect/temp_visual/target/Initialize(mapload, list/flame_hit)
|
||||
/obj/effect/temp_visual/lava_warning/Initialize(mapload, var/reset_time = 10)
|
||||
. = ..()
|
||||
INVOKE_ASYNC(src, .proc/fall, flame_hit)
|
||||
INVOKE_ASYNC(src, .proc/fall, reset_time)
|
||||
src.alpha = 63.75
|
||||
animate(src, alpha = 255, time = duration)
|
||||
|
||||
/obj/effect/temp_visual/target/proc/fall(list/flame_hit)
|
||||
/obj/effect/temp_visual/lava_warning/proc/fall(var/reset_time)
|
||||
var/turf/T = get_turf(src)
|
||||
playsound(T,'sound/magic/fleshtostone.ogg', 80, 1)
|
||||
new /obj/effect/temp_visual/fireball(T)
|
||||
sleep(duration)
|
||||
if(ismineralturf(T))
|
||||
var/turf/closed/mineral/M = T
|
||||
M.gets_drilled()
|
||||
playsound(T, "explosion", 80, 1)
|
||||
new /obj/effect/hotspot(T)
|
||||
T.hotspot_expose(700, 50, 1)
|
||||
playsound(T,'sound/magic/fireball.ogg', 200, 1)
|
||||
|
||||
for(var/mob/living/L in T.contents)
|
||||
if(istype(L, /mob/living/simple_animal/hostile/megafauna/dragon))
|
||||
continue
|
||||
if(islist(flame_hit) && !flame_hit[L])
|
||||
L.adjustFireLoss(40)
|
||||
to_chat(L, "<span class='userdanger'>You're hit by the drake's fire breath!</span>")
|
||||
flame_hit[L] = TRUE
|
||||
else
|
||||
L.adjustFireLoss(10) //if we've already hit them, do way less damage
|
||||
L.adjustFireLoss(10)
|
||||
to_chat(L, "<span class='userdanger'>You fall directly into the pool of lava!</span>")
|
||||
|
||||
// deals damage to mechs
|
||||
for(var/obj/mecha/M in T.contents)
|
||||
M.take_damage(45, BRUTE, "melee", 1)
|
||||
|
||||
// changes turf to lava temporarily
|
||||
if(!istype(T, /turf/closed) && !istype(T, /turf/open/lava))
|
||||
var/lava_turf = /turf/open/lava/smooth
|
||||
var/reset_turf = T.type
|
||||
T.ChangeTurf(lava_turf)
|
||||
sleep(reset_time)
|
||||
T.ChangeTurf(reset_turf)
|
||||
|
||||
/obj/effect/temp_visual/drakewall
|
||||
desc = "An ash drakes true flame."
|
||||
name = "Fire Barrier"
|
||||
icon = 'icons/effects/fire.dmi'
|
||||
icon_state = "1"
|
||||
anchored = TRUE
|
||||
opacity = 0
|
||||
density = TRUE
|
||||
CanAtmosPass = ATMOS_PASS_DENSITY
|
||||
duration = 82
|
||||
color = COLOR_DARK_ORANGE
|
||||
|
||||
/obj/effect/temp_visual/lava_safe
|
||||
icon = 'icons/obj/hand_of_god_structures.dmi'
|
||||
icon_state = "trap-earth"
|
||||
layer = BELOW_MOB_LAYER
|
||||
light_range = 2
|
||||
duration = 13
|
||||
|
||||
/obj/effect/temp_visual/dragon_swoop
|
||||
name = "certain death"
|
||||
@@ -347,7 +447,7 @@ Difficulty: Medium
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
color = "#FF0000"
|
||||
duration = 5
|
||||
duration = 10
|
||||
|
||||
/obj/effect/temp_visual/dragon_flight
|
||||
icon = 'icons/mob/lavaland/64x64megafauna.dmi'
|
||||
@@ -376,7 +476,7 @@ Difficulty: Medium
|
||||
/obj/effect/temp_visual/dragon_flight/end
|
||||
pixel_x = DRAKE_SWOOP_HEIGHT
|
||||
pixel_z = DRAKE_SWOOP_HEIGHT
|
||||
duration = 5
|
||||
duration = 10
|
||||
|
||||
/obj/effect/temp_visual/dragon_flight/end/flight(negative)
|
||||
if(negative)
|
||||
@@ -399,6 +499,16 @@ Difficulty: Medium
|
||||
crusher_loot = list()
|
||||
butcher_results = list(/obj/item/stack/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/bone = 30)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/lesser/AltClickOn(atom/movable/A)
|
||||
if(!istype(A))
|
||||
return
|
||||
if(player_cooldown >= world.time)
|
||||
to_chat(src, "<span class='warning'>You need to wait [(player_cooldown - world.time) / 10] seconds before swooping again!</span>")
|
||||
return
|
||||
swoop_attack(FALSE, A)
|
||||
lava_pools(10, 2) // less pools but longer delay before spawns
|
||||
player_cooldown = world.time + 200 // needs seperate cooldown or cant use fire attacks
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/lesser/transformed //ash drake balanced around player control
|
||||
name = "transformed ash drake"
|
||||
desc = "A sentient being transformed into an ash drake"
|
||||
|
||||
@@ -64,7 +64,6 @@
|
||||
friendly_verb_simple = "groom"
|
||||
mob_size = MOB_SIZE_SMALL
|
||||
movement_type = FLYING
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
|
||||
var/parrot_damage_upper = 10
|
||||
var/parrot_state = PARROT_WANDER //Hunt for a perch when created
|
||||
|
||||
@@ -69,3 +69,6 @@
|
||||
|
||||
/mob/proc/update_inv_ears()
|
||||
return
|
||||
|
||||
/mob/proc/update_antag_overlays()
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user