Merge branch 'master' into the-fuck-am-i-doing

This commit is contained in:
Fabian
2021-05-05 17:26:41 +02:00
641 changed files with 318305 additions and 311402 deletions
@@ -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////////////////////////////////////////
+2 -2
View File
@@ -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
+44 -4
View File
@@ -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)
+1 -1
View File
@@ -2,7 +2,7 @@
/**
* Applies damage to this mob
*
* Sends [COMSIG_MOB_APPLY_DAMGE]
* Sends [COMSIG_MOB_APPLY_DAMAGE]
*
* Arguuments:
* * damage - amount of damage
+3 -1
View File
@@ -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))
+2 -2
View File
@@ -3,7 +3,7 @@
* Splits off into PhysicalLife() and BiologicalLife(). Override those instead of this.
*/
/mob/living/proc/Life(seconds, times_fired)
//SHOULD_NOT_SLEEP(TRUE)
SHOULD_NOT_SLEEP(TRUE)
if(mob_transforming)
return
@@ -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
+19 -2
View File
@@ -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)
+5 -4
View File
@@ -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
+3
View File
@@ -69,3 +69,6 @@
/mob/proc/update_inv_ears()
return
/mob/proc/update_antag_overlays()
return