mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-14 16:44:33 +01:00
Merge remote-tracking branch 'upstream/master' into universal-damage
This commit is contained in:
@@ -59,7 +59,8 @@ In all, this is a lot like the monkey code. /N
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/alien/attack_animal(mob/living/simple_animal/M)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
|
||||
switch(M.melee_damage_type)
|
||||
if(BRUTE)
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
var/blocked = 0
|
||||
if(ishuman(A))
|
||||
var/mob/living/carbon/human/H = A
|
||||
if(H.check_shields(0, "the [name]", src, attack_type = LEAP_ATTACK))
|
||||
if(H.check_shields(src, 0, "the [name]", attack_type = LEAP_ATTACK))
|
||||
blocked = 1
|
||||
if(!blocked)
|
||||
L.visible_message("<span class ='danger'>[src] pounces on [L]!</span>", "<span class ='userdanger'>[src] pounces on you!</span>")
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
var/custom_pixel_x_offset = 0 //for admin fuckery.
|
||||
var/custom_pixel_y_offset = 0
|
||||
pass_flags = PASSTABLE
|
||||
pressure_resistance = 100 //100 kPa difference required to push
|
||||
throw_pressure_limit = 120 //120 kPa difference required to throw
|
||||
|
||||
//This is fine right now, if we're adding organ specific damage this needs to be updated
|
||||
/mob/living/carbon/alien/humanoid/New()
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
heal_rate = 5
|
||||
large = 1
|
||||
ventcrawler = 0
|
||||
pressure_resistance = 200 //Because big, stompy xenos should not be blown around like paper.
|
||||
|
||||
/mob/living/carbon/alien/humanoid/queen/New()
|
||||
create_reagents(100)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/mob/living/carbon
|
||||
gender = MALE
|
||||
pressure_resistance = 15
|
||||
var/list/stomach_contents = list()
|
||||
var/list/internal_organs = list()
|
||||
var/list/internal_organs_slot = list() //Same as above, but stores "slot ID" - "organ" pairs for easy access.
|
||||
|
||||
@@ -328,7 +328,7 @@ This function restores all organs.
|
||||
return 0
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/get_organ(zone)
|
||||
/mob/living/carbon/human/get_organ(zone)
|
||||
if(!zone)
|
||||
zone = "chest"
|
||||
if(zone in list("eyes", "mouth"))
|
||||
|
||||
@@ -34,7 +34,7 @@ emp_act
|
||||
return -1 // complete projectile permutation
|
||||
|
||||
//Shields
|
||||
if(check_shields(P.damage, "the [P.name]", P, PROJECTILE_ATTACK, P.armour_penetration))
|
||||
if(check_shields(P, P.damage, "the [P.name]", PROJECTILE_ATTACK, P.armour_penetration))
|
||||
P.on_hit(src, 100, def_zone)
|
||||
return 2
|
||||
|
||||
@@ -136,24 +136,24 @@ emp_act
|
||||
|
||||
//End Here
|
||||
|
||||
/mob/living/carbon/human/proc/check_shields(damage = 0, attack_text = "the attack", atom/movable/AM, attack_type = MELEE_ATTACK, armour_penetration = 0)
|
||||
/mob/living/carbon/human/proc/check_shields(atom/AM, var/damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0)
|
||||
var/block_chance_modifier = round(damage / -3)
|
||||
|
||||
if(l_hand && !istype(l_hand, /obj/item/clothing))
|
||||
var/final_block_chance = l_hand.block_chance - (Clamp((armour_penetration-l_hand.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
|
||||
if(l_hand.hit_reaction(src, attack_text, final_block_chance, damage, attack_type, AM))
|
||||
if(l_hand.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
|
||||
return 1
|
||||
if(r_hand && !istype(r_hand, /obj/item/clothing))
|
||||
var/final_block_chance = r_hand.block_chance - (Clamp((armour_penetration-r_hand.armour_penetration)/2,0,100)) + block_chance_modifier //Need to reset the var so it doesn't carry over modifications between attempts
|
||||
if(r_hand.hit_reaction(src, attack_text, final_block_chance, damage, attack_type, AM))
|
||||
if(r_hand.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
|
||||
return 1
|
||||
if(wear_suit)
|
||||
var/final_block_chance = wear_suit.block_chance - (Clamp((armour_penetration-wear_suit.armour_penetration)/2,0,100)) + block_chance_modifier
|
||||
if(wear_suit.hit_reaction(src, attack_text, final_block_chance, damage, attack_type, AM))
|
||||
if(wear_suit.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
|
||||
return 1
|
||||
if(w_uniform)
|
||||
var/final_block_chance = w_uniform.block_chance - (Clamp((armour_penetration-w_uniform.armour_penetration)/2,0,100)) + block_chance_modifier
|
||||
if(w_uniform.hit_reaction(src, attack_text, final_block_chance, damage, attack_type, AM))
|
||||
if(w_uniform.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -363,7 +363,7 @@ emp_act
|
||||
|
||||
if(user != src)
|
||||
user.do_attack_animation(src)
|
||||
if(check_shields(I.force, "the [I.name]", I, MELEE_ATTACK, I.armour_penetration))
|
||||
if(check_shields(I, I.force, "the [I.name]", MELEE_ATTACK, I.armour_penetration))
|
||||
return 0
|
||||
|
||||
if(check_block())
|
||||
@@ -457,7 +457,7 @@ emp_act
|
||||
throwpower = I.throwforce
|
||||
if(I.thrownby == src) //No throwing stuff at yourself to trigger reactions
|
||||
return ..()
|
||||
if(check_shields(throwpower, "\the [AM.name]", AM, THROWN_PROJECTILE_ATTACK))
|
||||
if(check_shields(AM, throwpower, "\the [AM.name]", THROWN_PROJECTILE_ATTACK))
|
||||
hitpush = 0
|
||||
skipcatch = 1
|
||||
blocked = 1
|
||||
@@ -538,7 +538,7 @@ emp_act
|
||||
updatehealth("larva attack")
|
||||
|
||||
/mob/living/carbon/human/attack_alien(mob/living/carbon/alien/humanoid/M)
|
||||
if(check_shields(0, M.name))
|
||||
if(check_shields(M, 0, M.name))
|
||||
visible_message("<span class='danger'>[M] attempted to touch [src]!</span>")
|
||||
return 0
|
||||
|
||||
@@ -583,16 +583,17 @@ emp_act
|
||||
visible_message("<span class='danger'>[M] has tried to disarm [src]!</span>")
|
||||
|
||||
/mob/living/carbon/human/attack_animal(mob/living/simple_animal/M)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
|
||||
if(check_shields(damage, "the [M.name]", null, MELEE_ATTACK, M.armour_penetration))
|
||||
return 0
|
||||
if(check_shields(M, damage, "the [M.name]", MELEE_ATTACK, M.armour_penetration))
|
||||
return FALSE
|
||||
var/dam_zone = pick("head", "chest", "groin", "l_arm", "l_hand", "r_arm", "r_hand", "l_leg", "l_foot", "r_leg", "r_foot")
|
||||
var/obj/item/organ/external/affecting = get_organ(ran_zone(dam_zone))
|
||||
if(!affecting)
|
||||
affecting = get_organ("chest")
|
||||
affecting.add_autopsy_data(M.name, damage) // Add the mob's name to the autopsy data
|
||||
var/armor = run_armor_check(affecting, "melee", armour_penetration = M.armour_penetration)
|
||||
var/obj/item/organ/external/affected = src.get_organ(dam_zone)
|
||||
if(affected)
|
||||
affected.add_autopsy_data(M.name, damage) // Add the mob's name to the autopsy data
|
||||
apply_damage(damage, M.melee_damage_type, affecting, armor)
|
||||
updatehealth("animal attack")
|
||||
|
||||
@@ -646,11 +647,12 @@ emp_act
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/experience_pressure_difference(pressure_difference, direction)
|
||||
playsound(src, 'sound/effects/space_wind.ogg', 50, 1)
|
||||
if(shoes)
|
||||
if(istype(shoes,/obj/item/clothing/shoes/magboots) && (shoes.flags & NOSLIP)) //TODO: Make a not-shit shoe var system to negate airflow.
|
||||
return 0
|
||||
..()
|
||||
playsound(src, 'sound/effects/space_wind.ogg', 50, TRUE)
|
||||
if(shoes && istype(shoes, /obj/item/clothing))
|
||||
var/obj/item/clothing/S = shoes
|
||||
if (S.flags & NOSLIP)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/water_act(volume, temperature, source, method = TOUCH)
|
||||
. = ..()
|
||||
|
||||
@@ -2,7 +2,7 @@ var/global/default_martial_art = new/datum/martial_art
|
||||
/mob/living/carbon/human
|
||||
|
||||
hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD,IMPMINDSHIELD_HUD,IMPCHEM_HUD,IMPTRACK_HUD,SPECIALROLE_HUD,GLAND_HUD)
|
||||
|
||||
pressure_resistance = 25
|
||||
//Marking colour and style
|
||||
var/list/m_colours = DEFAULT_MARKING_COLOURS //All colours set to #000000.
|
||||
var/list/m_styles = DEFAULT_MARKING_STYLES //All markings set to None.
|
||||
|
||||
@@ -522,7 +522,7 @@
|
||||
to_chat(M, "<span class='warning'>You can't use your hand.</span>")
|
||||
return
|
||||
|
||||
if((M != H) && M.a_intent != INTENT_HELP && H.check_shields(0, M.name, attack_type = UNARMED_ATTACK))
|
||||
if((M != H) && M.a_intent != INTENT_HELP && H.check_shields(M, 0, M.name, attack_type = UNARMED_ATTACK))
|
||||
add_attack_logs(M, H, "Melee attacked with fists (miss/block)")
|
||||
H.visible_message("<span class='warning'>[M] attempted to touch [H]!</span>")
|
||||
return FALSE
|
||||
|
||||
@@ -258,7 +258,8 @@
|
||||
M.updatehealth()
|
||||
|
||||
/mob/living/carbon/slime/attack_animal(mob/living/simple_animal/M)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
|
||||
attacked += 10
|
||||
adjustBruteLoss(damage)
|
||||
|
||||
@@ -608,6 +608,34 @@
|
||||
else
|
||||
return pick("trails_1", "trails_2")
|
||||
|
||||
/mob/living/experience_pressure_difference(pressure_difference, direction, pressure_resistance_prob_delta = 0)
|
||||
if(buckled)
|
||||
return
|
||||
if(client && client.move_delay >= world.time + world.tick_lag * 2)
|
||||
pressure_resistance_prob_delta -= 30
|
||||
|
||||
var/list/turfs_to_check = list()
|
||||
|
||||
if(has_limbs)
|
||||
var/turf/T = get_step(src, angle2dir(dir2angle(direction) + 90))
|
||||
if (T)
|
||||
turfs_to_check += T
|
||||
|
||||
T = get_step(src, angle2dir(dir2angle(direction) - 90))
|
||||
if(T)
|
||||
turfs_to_check += T
|
||||
|
||||
for(var/t in turfs_to_check)
|
||||
T = t
|
||||
if(T.density)
|
||||
pressure_resistance_prob_delta -= 20
|
||||
continue
|
||||
for(var/atom/movable/AM in T)
|
||||
if(AM.density && AM.anchored)
|
||||
pressure_resistance_prob_delta -= 20
|
||||
break
|
||||
|
||||
..(pressure_difference, direction, pressure_resistance_prob_delta)
|
||||
|
||||
/*//////////////////////
|
||||
START RESIST PROCS
|
||||
@@ -621,6 +649,8 @@
|
||||
return
|
||||
changeNext_move(CLICK_CD_RESIST)
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_RESIST, src)
|
||||
|
||||
if(!restrained())
|
||||
if(resist_grab())
|
||||
return
|
||||
|
||||
@@ -303,17 +303,17 @@
|
||||
return
|
||||
|
||||
/mob/living/attack_animal(mob/living/simple_animal/M)
|
||||
M.face_atom(src)
|
||||
if((M.a_intent == INTENT_HELP && M.ckey) || M.melee_damage_upper == 0)
|
||||
M.custom_emote(1, "[M.friendly] [src].")
|
||||
return 0
|
||||
else
|
||||
if(M.attack_sound)
|
||||
playsound(loc, M.attack_sound, 50, 1, 1)
|
||||
M.do_attack_animation(src)
|
||||
visible_message("<span class='danger'>\The [M] [M.attacktext] [src]!</span>", \
|
||||
"<span class='userdanger'>\The [M] [M.attacktext] [src]!</span>")
|
||||
add_attack_logs(M, src, "Animal attacked")
|
||||
return 1
|
||||
return FALSE
|
||||
if(M.attack_sound)
|
||||
playsound(loc, M.attack_sound, 50, 1, 1)
|
||||
M.do_attack_animation(src)
|
||||
visible_message("<span class='danger'>\The [M] [M.attacktext] [src]!</span>", \
|
||||
"<span class='userdanger'>\The [M] [M.attacktext] [src]!</span>")
|
||||
add_attack_logs(M, src, "Animal attacked")
|
||||
return TRUE
|
||||
|
||||
/mob/living/attack_larva(mob/living/carbon/alien/larva/L)
|
||||
switch(L.a_intent)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/mob/living
|
||||
see_invisible = SEE_INVISIBLE_LIVING
|
||||
pressure_resistance = 10
|
||||
|
||||
//Health and life related vars
|
||||
var/maxHealth = 100 //Maximum health that should be possible.
|
||||
@@ -65,7 +66,7 @@
|
||||
hud_possible = list(HEALTH_HUD,STATUS_HUD,SPECIALROLE_HUD)
|
||||
|
||||
var/list/status_effects //a list of all status effects the mob has
|
||||
|
||||
|
||||
var/deathgasp_on_death = FALSE
|
||||
|
||||
var/stun_absorption = null //converted to a list of stun absorption sources this mob has when one is added
|
||||
|
||||
@@ -227,14 +227,8 @@
|
||||
// See software.dm for Topic()
|
||||
|
||||
/mob/living/silicon/pai/attack_animal(mob/living/simple_animal/M)
|
||||
if((M.a_intent == INTENT_HELP && M.ckey) || M.melee_damage_upper == 0)
|
||||
M.custom_emote(1, "[M.friendly] [src].")
|
||||
else
|
||||
M.do_attack_animation(src)
|
||||
if(M.attack_sound)
|
||||
playsound(loc, M.attack_sound, 50, 1, 1)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message("<span class='danger'>[M]</span> [M.attacktext] [src]!", 1)
|
||||
. = ..()
|
||||
if(.)
|
||||
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
|
||||
add_attack_logs(M, src, "Animal attacked for [damage] damage")
|
||||
adjustBruteLoss(damage)
|
||||
|
||||
@@ -252,7 +252,7 @@
|
||||
modules += new /obj/item/soap/nanotrasen(src)
|
||||
modules += new /obj/item/storage/bag/trash/cyborg(src)
|
||||
modules += new /obj/item/mop/advanced/cyborg(src)
|
||||
modules += new /obj/item/lightreplacer(src)
|
||||
modules += new /obj/item/lightreplacer/cyborg(src)
|
||||
modules += new /obj/item/holosign_creator(src)
|
||||
emag = new /obj/item/reagent_containers/spray(src)
|
||||
|
||||
@@ -544,7 +544,7 @@
|
||||
modules += new /obj/item/crowbar/cyborg(src)
|
||||
modules += new /obj/item/wirecutters/cyborg(src)
|
||||
modules += new /obj/item/multitool/cyborg(src)
|
||||
modules += new /obj/item/lightreplacer(src)
|
||||
modules += new /obj/item/lightreplacer/cyborg(src)
|
||||
modules += new /obj/item/gripper(src)
|
||||
modules += new /obj/item/matter_decompiler(src)
|
||||
modules += new /obj/item/reagent_containers/spray/cleaner/drone(src)
|
||||
@@ -562,10 +562,6 @@
|
||||
/obj/item/robot_module/drone/respawn_consumable(mob/living/silicon/robot/R)
|
||||
var/obj/item/reagent_containers/spray/cleaner/C = locate() in modules
|
||||
C.reagents.add_reagent("cleaner", 3)
|
||||
|
||||
var/obj/item/lightreplacer/LR = locate() in modules
|
||||
LR.Charge(R)
|
||||
|
||||
..()
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
modtype = "Syndicate"
|
||||
req_access = list(access_syndicate)
|
||||
ionpulse = 1
|
||||
magpulse = 1
|
||||
lawchannel = "State"
|
||||
var/playstyle_string = "<span class='userdanger'>You are a Syndicate assault cyborg!</span><br>\
|
||||
<b>You are armed with powerful offensive tools to aid you in your mission: help the operatives secure the nuclear authentication disk. \
|
||||
@@ -80,7 +79,7 @@
|
||||
|
||||
var/datum/action/thermals = new /datum/action/innate/robot_sight/thermal()
|
||||
thermals.Grant(src)
|
||||
|
||||
|
||||
/mob/living/silicon/robot/syndicate/saboteur/verb/modify_name()
|
||||
set name = "Modify Name"
|
||||
set desc = "Change your systems' registered name to fool Nanotrasen systems. No cost."
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
return
|
||||
|
||||
/mob/living/silicon/attack_animal(mob/living/simple_animal/M)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
|
||||
switch(M.melee_damage_type)
|
||||
if(BRUTE)
|
||||
|
||||
@@ -53,9 +53,10 @@
|
||||
L.amount_grown = min(L.amount_grown + damage, L.max_grown)
|
||||
|
||||
/mob/living/simple_animal/attack_animal(mob/living/simple_animal/M)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
|
||||
attack_threshold_check(damage, M.melee_damage_type)
|
||||
return attack_threshold_check(damage, M.melee_damage_type)
|
||||
|
||||
/mob/living/simple_animal/attack_slime(mob/living/carbon/slime/M)
|
||||
..()
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
faction = list("syndicate")
|
||||
shoot_sound = 'sound/weapons/wave.ogg'
|
||||
anchored = 1
|
||||
pressure_resistance = 100 //100 kPa difference required to push
|
||||
throw_pressure_limit = 120
|
||||
window_id = "syndiebot"
|
||||
window_name = "Syndicate Bot Interface"
|
||||
var/turf/saved_turf
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
minbodytemp = 0
|
||||
faction = list("cult")
|
||||
flying = 1
|
||||
pressure_resistance = 100
|
||||
universal_speak = 1
|
||||
AIStatus = AI_OFF //normal constructs don't have AI
|
||||
var/const_type = "shade"
|
||||
@@ -79,7 +80,7 @@
|
||||
else
|
||||
to_chat(M, "<span class='cult'>You cannot repair your own dents, as you have none!</span>")
|
||||
else if(src != M)
|
||||
..()
|
||||
return ..()
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/narsie_act()
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
unsuitable_atmos_damage = 15
|
||||
heat_damage_per_tick = 20
|
||||
pressure_resistance = 100 //100 kPa difference required to push
|
||||
throw_pressure_limit = 120 //120 kPa difference required to throw
|
||||
faction = list("alien")
|
||||
status_flags = CANPUSH
|
||||
minbodytemp = 0
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
faction = list("carp")
|
||||
flying = 1
|
||||
pressure_resistance = 200
|
||||
gold_core_spawnable = CHEM_MOB_SPAWN_HOSTILE
|
||||
|
||||
var/carp_color = "carp" //holder for icon set
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
attack_sound = 'sound/creatures/headcrab_attack.ogg'
|
||||
speak_emote = list("hisses")
|
||||
var/is_zombie = 0
|
||||
stat_attack = UNCONSCIOUS //so they continue to attack when they are on the ground.
|
||||
stat_attack = DEAD //so they continue to attack when they are on the ground.
|
||||
var/host_species = ""
|
||||
var/list/human_overlays = list()
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Difficulty: Medium
|
||||
icon = 'icons/mob/alienqueen.dmi'
|
||||
light_color = "#E4C7C5"
|
||||
speak_emote = list("roars")
|
||||
speed = 1
|
||||
speed = 3
|
||||
move_to_delay = 3
|
||||
projectiletype = /obj/item/projectile/kinetic/miner
|
||||
projectilesound = 'sound/weapons/kenetic_accel.ogg'
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
#define BUBBLEGUM_SMASH (health <= maxHealth * 0.5) // angery
|
||||
#define BUBBLEGUM_CAN_ENRAGE (enrage_till + (enrage_time * 2) <= world.time)
|
||||
#define BUBBLEGUM_IS_ENRAGED (enrage_till > world.time)
|
||||
|
||||
|
||||
/*
|
||||
|
||||
BUBBLEGUM
|
||||
@@ -5,14 +10,16 @@ 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 tries to strike at its target through any bloodpools under them; if it fails to do that, it will spray blood and then attempt to warp to a bloodpool near the target.
|
||||
If it fails to warp to a target, it may summon up to 6 slaughterlings from the blood around it.
|
||||
If it does not summon all 6 slaughterlings, it will instead charge at its target, dealing massive damage to anything it hits and spraying a stream of blood.
|
||||
At half health, it will either charge three times or warp, then charge, instead of doing a single charge.
|
||||
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 chest that can contain three things:
|
||||
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 contract that marks for death the chosen target
|
||||
3. A spellblade that can slice off limbs at range
|
||||
@@ -37,19 +44,31 @@ Difficulty: Hard
|
||||
armour_penetration = 40
|
||||
melee_damage_lower = 40
|
||||
melee_damage_upper = 40
|
||||
speed = 1
|
||||
move_to_delay = 10
|
||||
ranged = 1
|
||||
speed = 5
|
||||
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 = TRUE
|
||||
pixel_x = -32
|
||||
del_on_death = 1
|
||||
del_on_death = TRUE
|
||||
crusher_loot = list(/obj/structure/closet/crate/necropolis/bubblegum/crusher)
|
||||
loot = list(/obj/structure/closet/crate/necropolis/bubblegum)
|
||||
var/charging = 0
|
||||
blood_volume = BLOOD_VOLUME_MAXIMUM //BLEED FOR ME
|
||||
var/charging = FALSE
|
||||
var/enrage_till = 0
|
||||
var/enrage_time = 70
|
||||
var/revving_charge = FALSE
|
||||
internal_type = /obj/item/gps/internal/bubblegum
|
||||
medal_type = BOSS_MEDAL_BUBBLEGUM
|
||||
score_type = BUBBLEGUM_SCORE
|
||||
deathmessage = "sinks into a pool of blood, fleeing the battle. You've won, for now... "
|
||||
death_sound = 'sound/misc/enter_blood.ogg'
|
||||
attack_action_types = list(/datum/action/innate/megafauna_attack/triple_charge,
|
||||
/datum/action/innate/megafauna_attack/hallucination_charge,
|
||||
/datum/action/innate/megafauna_attack/hallucination_surround,
|
||||
/datum/action/innate/megafauna_attack/blood_warp)
|
||||
|
||||
/obj/item/gps/internal/bubblegum
|
||||
icon_state = null
|
||||
@@ -57,54 +76,6 @@ Difficulty: Hard
|
||||
desc = "You're not quite sure how a signal can be bloody."
|
||||
invisibility = 100
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/adjustBruteLoss(amount)
|
||||
if(amount > 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(cardinal))
|
||||
else
|
||||
B.dir = pick(cardinal)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/bubblegum
|
||||
name = "thick blood"
|
||||
desc = "Thick, splattered blood."
|
||||
random_icon_states = list("gib3", "gib5", "gib6")
|
||||
amount = 20
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/bubblegum/can_bloodcrawl_in()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Life(seconds, times_fired)
|
||||
..()
|
||||
move_to_delay = Clamp((health/maxHealth) * 10, 5, 10)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/OpenFire()
|
||||
anger_modifier = Clamp(((maxHealth - health)/60),0,20)
|
||||
if(charging)
|
||||
return
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
|
||||
var/warped = FALSE
|
||||
if(!try_bloodattack())
|
||||
spawn(0)
|
||||
blood_spray()
|
||||
warped = blood_warp()
|
||||
if(warped && prob(100 - anger_modifier))
|
||||
return
|
||||
|
||||
if(prob(90 - anger_modifier) || slaughterlings())
|
||||
if(health > maxHealth * 0.5)
|
||||
spawn(0)
|
||||
charge()
|
||||
else
|
||||
if(prob(70) || warped)
|
||||
spawn(0)
|
||||
triple_charge()
|
||||
else
|
||||
spawn(0)
|
||||
warp_charge()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Initialize(mapload)
|
||||
. = ..()
|
||||
if(true_spawn)
|
||||
@@ -112,88 +83,118 @@ Difficulty: Hard
|
||||
if(B != src)
|
||||
qdel(src) //There can be only one
|
||||
return
|
||||
var/obj/effect/proc_holder/spell/bloodcrawl/bloodspell = new
|
||||
AddSpell(bloodspell)
|
||||
if(istype(loc, /obj/effect/dummy/slaughter))
|
||||
bloodspell.phased = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/do_attack_animation(atom/A, visual_effect_icon, used_item, no_effect, end_pixel_y)
|
||||
if(!charging)
|
||||
..()
|
||||
/datum/action/innate/megafauna_attack/triple_charge
|
||||
name = "Triple Charge"
|
||||
icon_icon = 'icons/mob/actions/actions.dmi'
|
||||
button_icon_state = "sniper_zoom"
|
||||
chosen_message = "<span class='colossus'>You are now triple charging at the target you click on.</span>"
|
||||
chosen_attack_num = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/AttackingTarget()
|
||||
if(!charging)
|
||||
return ..()
|
||||
/datum/action/innate/megafauna_attack/hallucination_charge
|
||||
name = "Hallucination Charge"
|
||||
icon_icon = 'icons/effects/bubblegum.dmi'
|
||||
button_icon_state = "smack ya one"
|
||||
chosen_message = "<span class='colossus'>You are now charging with hallucinations at the target you click on.</span>"
|
||||
chosen_attack_num = 2
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Goto(target, delay, minimum_distance)
|
||||
if(!charging)
|
||||
..()
|
||||
/datum/action/innate/megafauna_attack/hallucination_surround
|
||||
name = "Surround Target"
|
||||
icon_icon = 'icons/turf/walls/wall.dmi'
|
||||
button_icon_state = "wall"
|
||||
chosen_message = "<span class='colossus'>You are now surrounding the target you click on with hallucinations.</span>"
|
||||
chosen_attack_num = 3
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/MoveToTarget(list/possible_targets)
|
||||
if(!charging)
|
||||
..()
|
||||
/datum/action/innate/megafauna_attack/blood_warp
|
||||
name = "Blood Warp"
|
||||
icon_icon = 'icons/effects/blood.dmi'
|
||||
button_icon_state = "floor1"
|
||||
chosen_message = "<span class='colossus'>You are now warping to blood around your clicked position.</span>"
|
||||
chosen_attack_num = 4
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Move()
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/OpenFire()
|
||||
if(charging)
|
||||
new /obj/effect/temp_visual/decoy/fading(loc, src)
|
||||
DestroySurroundings()
|
||||
. = ..()
|
||||
if(!stat && .)
|
||||
playsound(src, 'sound/effects/meteorimpact.ogg', 200, 1, 2, 1)
|
||||
if(charging)
|
||||
DestroySurroundings()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/warp_charge()
|
||||
blood_warp()
|
||||
charge()
|
||||
anger_modifier = Clamp(((maxHealth - health)/60),0,20)
|
||||
enrage_time = initial(enrage_time) * Clamp(anger_modifier / 20, 0.5, 1)
|
||||
ranged_cooldown = world.time + 50
|
||||
|
||||
if(client)
|
||||
switch(chosen_attack)
|
||||
if(1)
|
||||
triple_charge()
|
||||
if(2)
|
||||
hallucination_charge()
|
||||
if(3)
|
||||
surround_with_hallucinations()
|
||||
if(4)
|
||||
blood_warp()
|
||||
return
|
||||
|
||||
if(!try_bloodattack() || prob(25 + anger_modifier))
|
||||
blood_warp()
|
||||
|
||||
if(!BUBBLEGUM_SMASH)
|
||||
triple_charge()
|
||||
else
|
||||
if(prob(50 + anger_modifier))
|
||||
hallucination_charge()
|
||||
else
|
||||
surround_with_hallucinations()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/triple_charge()
|
||||
charge()
|
||||
charge()
|
||||
charge()
|
||||
charge(delay = 6)
|
||||
charge(delay = 4)
|
||||
charge(delay = 2)
|
||||
SetRecoveryTime(15)
|
||||
|
||||
/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/hallucination_charge()
|
||||
if(!BUBBLEGUM_SMASH || prob(33))
|
||||
hallucination_charge_around(times = 6, delay = 8)
|
||||
SetRecoveryTime(10)
|
||||
else
|
||||
hallucination_charge_around(times = 4, delay = 9)
|
||||
hallucination_charge_around(times = 4, delay = 8)
|
||||
hallucination_charge_around(times = 4, delay = 7)
|
||||
triple_charge()
|
||||
SetRecoveryTime(20)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/surround_with_hallucinations()
|
||||
for(var/i = 1 to 5)
|
||||
INVOKE_ASYNC(src, .proc/hallucination_charge_around, 2, 8, 2, 0, 4)
|
||||
if(ismob(target))
|
||||
charge(delay = 6)
|
||||
else
|
||||
SLEEP_CHECK_DEATH(6)
|
||||
SetRecoveryTime(20)
|
||||
|
||||
/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)
|
||||
charging = 1
|
||||
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 = TRUE
|
||||
revving_charge = TRUE
|
||||
DestroySurroundings()
|
||||
walk(src, 0)
|
||||
dir = get_dir(src, T)
|
||||
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)
|
||||
charging = 0
|
||||
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 = 3)
|
||||
SLEEP_CHECK_DEATH(delay)
|
||||
revving_charge = FALSE
|
||||
var/movespeed = 0.7
|
||||
walk_towards(src, T, movespeed)
|
||||
SLEEP_CHECK_DEATH(get_dist(src, T) * movespeed)
|
||||
walk(src, 0) // cancel the movement
|
||||
try_bloodattack()
|
||||
if(target)
|
||||
Goto(target, move_to_delay, minimum_distance)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Bump(atom/A)
|
||||
if(charging)
|
||||
if(isturf(A) || isobj(A) && A.density)
|
||||
A.ex_act(2)
|
||||
DestroySurroundings()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/throw_impact(atom/A)
|
||||
if(!charging)
|
||||
return ..()
|
||||
|
||||
else if(isliving(A))
|
||||
var/mob/living/L = A
|
||||
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)
|
||||
|
||||
charging = 0
|
||||
|
||||
charging = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_mobs_on_blood()
|
||||
var/list/targets = ListTargets()
|
||||
@@ -206,9 +207,7 @@ Difficulty: Hard
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/try_bloodattack()
|
||||
var/list/targets = get_mobs_on_blood()
|
||||
if(targets.len)
|
||||
spawn(0)
|
||||
bloodattack(targets, prob(50))
|
||||
|
||||
INVOKE_ASYNC(src, .proc/bloodattack, targets, prob(50))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -249,14 +248,14 @@ Difficulty: Hard
|
||||
new /obj/effect/temp_visual/bubblegum_hands/rightsmack(T)
|
||||
else
|
||||
new /obj/effect/temp_visual/bubblegum_hands/leftsmack(T)
|
||||
sleep(2.5)
|
||||
SLEEP_CHECK_DEATH(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 = pick("head", "chest", "r_arm", "l_arm", "r_leg", "l_leg")
|
||||
L.apply_damage(25, BRUTE, limb_to_hit, L.run_armor_check(limb_to_hit, "melee", null, null, armour_penetration))
|
||||
sleep(3)
|
||||
playsound(T, attack_sound, 100, TRUE, -1)
|
||||
var/limb_to_hit = L.get_organ(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_CHECK_DEATH(3)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodgrab(turf/T, handedness)
|
||||
if(handedness)
|
||||
@@ -265,18 +264,221 @@ Difficulty: Hard
|
||||
else
|
||||
new /obj/effect/temp_visual/bubblegum_hands/leftpaw(T)
|
||||
new /obj/effect/temp_visual/bubblegum_hands/leftthumb(T)
|
||||
sleep(6)
|
||||
SLEEP_CHECK_DEATH(6)
|
||||
for(var/mob/living/L in T)
|
||||
if(!faction_check_mob(L))
|
||||
to_chat(L, "<span class='userdanger'>[src] drags you through the blood!</span>")
|
||||
playsound(T, 'sound/misc/enter_blood.ogg', 100, 1, -1)
|
||||
var/turf/targetturf = get_step(src, dir)
|
||||
L.forceMove(targetturf)
|
||||
playsound(targetturf, 'sound/misc/exit_blood.ogg', 100, 1, -1)
|
||||
if(L.stat != CONSCIOUS)
|
||||
spawn(2)
|
||||
devour(L)
|
||||
sleep(1)
|
||||
to_chat(L, "<span class='userdanger'>[src] drags you through the blood!</span>")
|
||||
playsound(T, 'sound/misc/enter_blood.ogg', 100, TRUE, -1)
|
||||
var/turf/targetturf = get_step(src, dir)
|
||||
L.forceMove(targetturf)
|
||||
playsound(targetturf, 'sound/misc/exit_blood.ogg', 100, TRUE, -1)
|
||||
addtimer(CALLBACK(src, .proc/devour, L), 2)
|
||||
SLEEP_CHECK_DEATH(1)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_warp()
|
||||
if(Adjacent(target))
|
||||
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), 5)
|
||||
var/list/pools_to_remove = get_pools(get_turf(target), 4)
|
||||
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_CHECK_DEATH(3)
|
||||
qdel(DA)
|
||||
|
||||
var/obj/effect/decal/cleanable/blood/found_bloodpool
|
||||
pools = get_pools(get_turf(target), 5)
|
||||
pools_to_remove = get_pools(get_turf(target), 4)
|
||||
pools -= pools_to_remove
|
||||
if(pools.len)
|
||||
shuffle_inplace(pools)
|
||||
found_bloodpool = pick(pools)
|
||||
if(found_bloodpool)
|
||||
visible_message("<span class='danger'>[src] sinks into the blood...</span>")
|
||||
playsound(get_turf(src), 'sound/misc/enter_blood.ogg', 100, TRUE, -1)
|
||||
forceMove(get_turf(found_bloodpool))
|
||||
playsound(get_turf(src), 'sound/misc/exit_blood.ogg', 100, TRUE, -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/be_aggressive()
|
||||
if(BUBBLEGUM_IS_ENRAGED)
|
||||
return TRUE
|
||||
if(isliving(target))
|
||||
var/mob/living/livingtarget = target
|
||||
return (livingtarget.stat != CONSCIOUS || livingtarget.lying)
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_retreat_distance()
|
||||
return (be_aggressive() ? null : initial(retreat_distance))
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_minimum_distance()
|
||||
return (be_aggressive() ? 1 : initial(minimum_distance))
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/update_approach()
|
||||
retreat_distance = get_retreat_distance()
|
||||
minimum_distance = get_minimum_distance()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_enrage()
|
||||
if(!BUBBLEGUM_CAN_ENRAGE)
|
||||
return FALSE
|
||||
enrage_till = world.time + enrage_time
|
||||
update_approach()
|
||||
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, enrage_time)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_enrage_end(newcolor = rgb(149, 10, 10))
|
||||
update_approach()
|
||||
change_move_delay()
|
||||
remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, newcolor)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/change_move_delay(newmove = initial(move_to_delay))
|
||||
move_to_delay = newmove
|
||||
speed = move_to_delay
|
||||
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/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(times = 4, delay = 6, chargepast = 0, useoriginal = 1, radius)
|
||||
var/startingangle = rand(1, 360)
|
||||
if(!target)
|
||||
return
|
||||
var/turf/chargeat = get_turf(target)
|
||||
var/srcplaced = FALSE
|
||||
if(!radius)
|
||||
radius = times
|
||||
for(var/i = 1 to times)
|
||||
var/ang = (startingangle + 360/times * i)
|
||||
if(!chargeat)
|
||||
return
|
||||
var/turf/place = locate(chargeat.x + cos(ang) * radius, chargeat.y + sin(ang) * radius, chargeat.z)
|
||||
if(!place)
|
||||
continue
|
||||
if(!nest || nest && nest.parent && get_dist(nest.parent, place) <= nest_range)
|
||||
if(!srcplaced && useoriginal)
|
||||
forceMove(place)
|
||||
srcplaced = TRUE
|
||||
continue
|
||||
var/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/B = new /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination(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/adjustBruteLoss(amount, updating_health = 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(cardinal))
|
||||
else
|
||||
B.setDir(pick(cardinal))
|
||||
|
||||
/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/do_attack_animation(atom/A, visual_effect_icon)
|
||||
if(!charging)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/AttackingTarget()
|
||||
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(BUBBLEGUM_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, TRUE)
|
||||
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 TRUE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Goto(target, delay, minimum_distance)
|
||||
if(!charging)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/MoveToTarget(list/possible_targets)
|
||||
if(!charging)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Move()
|
||||
update_approach()
|
||||
if(revving_charge)
|
||||
return FALSE
|
||||
if(charging)
|
||||
new /obj/effect/temp_visual/decoy/fading(loc,src)
|
||||
DestroySurroundings()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Moved(atom/OldLoc, Dir, Forced = FALSE)
|
||||
if(Dir)
|
||||
new /obj/effect/decal/cleanable/blood/bubblegum(loc)
|
||||
if(charging)
|
||||
DestroySurroundings()
|
||||
playsound(src, 'sound/effects/meteorimpact.ogg', 200, TRUE, 2, TRUE)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Bump(atom/A)
|
||||
if(charging)
|
||||
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>")
|
||||
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, TRUE)
|
||||
shake_camera(L, 4, 3)
|
||||
shake_camera(src, 2, 3)
|
||||
..()
|
||||
|
||||
/obj/effect/temp_visual/dragon_swoop/bubblegum
|
||||
duration = 10
|
||||
|
||||
/obj/effect/temp_visual/bubblegum_hands
|
||||
icon = 'icons/effects/bubblegum.dmi'
|
||||
@@ -290,11 +492,11 @@ Difficulty: Hard
|
||||
|
||||
/obj/effect/temp_visual/bubblegum_hands/rightpaw
|
||||
icon_state = "rightpawgrab"
|
||||
layer = MOB_LAYER - 0.1
|
||||
layer = BELOW_MOB_LAYER
|
||||
|
||||
/obj/effect/temp_visual/bubblegum_hands/leftpaw
|
||||
icon_state = "leftpawgrab"
|
||||
layer = MOB_LAYER - 0.1
|
||||
layer = BELOW_MOB_LAYER
|
||||
|
||||
/obj/effect/temp_visual/bubblegum_hands/rightsmack
|
||||
icon_state = "rightsmack"
|
||||
@@ -302,94 +504,48 @@ Difficulty: Hard
|
||||
/obj/effect/temp_visual/bubblegum_hands/leftsmack
|
||||
icon_state = "leftsmack"
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_warp()
|
||||
if(Adjacent(target))
|
||||
return FALSE
|
||||
var/list/can_jaunt = get_pools(get_turf(src), 1)
|
||||
if(!can_jaunt.len)
|
||||
return FALSE
|
||||
/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
|
||||
medal_type = null
|
||||
score_type = null
|
||||
deathmessage = "Explodes into a pool of blood!"
|
||||
death_sound = 'sound/effects/splat.ogg'
|
||||
true_spawn = 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
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Initialize(mapload)
|
||||
. = ..()
|
||||
toggle_ai(AI_OFF)
|
||||
|
||||
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 = 5)
|
||||
sleep(5)
|
||||
qdel(DA)
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/charge(atom/chargeat = target, delay = 3, chargepast = 2)
|
||||
..()
|
||||
qdel(src)
|
||||
|
||||
var/obj/effect/decal/cleanable/blood/found_bloodpool
|
||||
pools = get_pools(get_turf(target), 2)
|
||||
pools_to_remove = get_pools(get_turf(target), 1)
|
||||
pools -= pools_to_remove
|
||||
if(pools.len)
|
||||
shuffle(pools)
|
||||
found_bloodpool = pick(pools)
|
||||
if(found_bloodpool)
|
||||
visible_message("<span class='danger'>[src] sinks into the blood...</span>")
|
||||
playsound(get_turf(src), 'sound/misc/enter_blood.ogg', 100, 1, -1)
|
||||
forceMove(get_turf(found_bloodpool))
|
||||
playsound(get_turf(src), 'sound/misc/exit_blood.ogg', 100, 1, -1)
|
||||
visible_message("<span class='danger'>And springs back out!</span>")
|
||||
/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 TRUE
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/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
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Life()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_spray()
|
||||
visible_message("<span class='danger'>[src] sprays a stream of gore!</span>")
|
||||
var/range = 6 + round(anger_modifier * 0.4)
|
||||
var/turf/previousturf = get_turf(src)
|
||||
var/turf/J = previousturf
|
||||
var/targetdir = get_dir(src, target)
|
||||
if(target.loc == loc)
|
||||
targetdir = dir
|
||||
face_atom(target)
|
||||
new /obj/effect/decal/cleanable/blood/bubblegum(J)
|
||||
for(var/i in 1 to range)
|
||||
J = get_step(previousturf, targetdir)
|
||||
new /obj/effect/temp_visual/dir_setting/bloodsplatter(previousturf, get_dir(previousturf, J))
|
||||
playsound(previousturf,'sound/effects/splat.ogg', 100, 1, -1)
|
||||
if(!J || !previousturf.CanAtmosPass(J))
|
||||
break
|
||||
new /obj/effect/decal/cleanable/blood/bubblegum(J)
|
||||
previousturf = J
|
||||
sleep(1)
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/adjustBruteLoss(amount, updating_health = TRUE)
|
||||
return
|
||||
|
||||
/obj/effect/decal/cleanable/blood/bubblegum
|
||||
amount = 0
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/OpenFire()
|
||||
return
|
||||
|
||||
/obj/effect/decal/cleanable/blood/bubblegum/can_bloodcrawl_in()
|
||||
return TRUE
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/AttackingTarget()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/slaughterlings()
|
||||
visible_message("<span class='danger'>[src] summons a shoal of slaughterlings!</span>")
|
||||
var/max_amount = 6
|
||||
for(var/H in get_pools(get_turf(src), 1))
|
||||
if(!max_amount)
|
||||
break
|
||||
max_amount--
|
||||
var/obj/effect/decal/cleanable/blood/B = H
|
||||
new /mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/slaughter(B.loc)
|
||||
return max_amount
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/slaughter
|
||||
name = "slaughterling"
|
||||
desc = "Though not yet strong enough to create a true physical form, it's nonetheless determined to murder you."
|
||||
density = 0
|
||||
faction = list("mining", "boss")
|
||||
weather_immunities = list("lava","ash")
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/slaughter/CanPass(atom/movable/mover, turf/target, height = 0)
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum))
|
||||
return 1
|
||||
return 0
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/try_bloodattack()
|
||||
return
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/*
|
||||
|
||||
COLOSSUS
|
||||
@@ -31,35 +30,74 @@ Difficulty: Very Hard
|
||||
attack_sound = 'sound/magic/ratvar_attack.ogg'
|
||||
icon_state = "eva"
|
||||
icon_living = "eva"
|
||||
icon_dead = "dragon_dead"
|
||||
icon_dead = ""
|
||||
friendly = "stares down"
|
||||
icon = 'icons/mob/lavaland/96x96megafauna.dmi'
|
||||
speak_emote = list("roars")
|
||||
armour_penetration = 40
|
||||
melee_damage_lower = 40
|
||||
melee_damage_upper = 40
|
||||
speed = 1
|
||||
speed = 10
|
||||
move_to_delay = 10
|
||||
ranged = 1
|
||||
ranged = TRUE
|
||||
pixel_x = -32
|
||||
del_on_death = 1
|
||||
del_on_death = TRUE
|
||||
internal_type = /obj/item/gps/internal/colossus
|
||||
medal_type = BOSS_MEDAL_COLOSSUS
|
||||
score_type = COLOSSUS_SCORE
|
||||
crusher_loot = list(/obj/structure/closet/crate/necropolis/colossus/crusher)
|
||||
loot = list(/obj/structure/closet/crate/necropolis/colossus)
|
||||
butcher_results = list(/obj/item/stack/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/animalhide/ashdrake = 10, /obj/item/stack/sheet/bone = 30)
|
||||
deathmessage = "disintegrates, leaving a glowing core in its wake."
|
||||
death_sound = 'sound/misc/demon_dies.ogg'
|
||||
attack_action_types = list(/datum/action/innate/megafauna_attack/spiral_attack,
|
||||
/datum/action/innate/megafauna_attack/aoe_attack,
|
||||
/datum/action/innate/megafauna_attack/shotgun,
|
||||
/datum/action/innate/megafauna_attack/alternating_cardinals)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/devour(mob/living/L)
|
||||
visible_message("<span class='colossus'>[src] disintegrates [L]!</span>")
|
||||
L.dust()
|
||||
/datum/action/innate/megafauna_attack/spiral_attack
|
||||
name = "Spiral Shots"
|
||||
icon_icon = 'icons/mob/actions/actions.dmi'
|
||||
button_icon_state = "sniper_zoom"
|
||||
chosen_message = "<span class='colossus'>You are now firing in a spiral.</span>"
|
||||
chosen_attack_num = 1
|
||||
|
||||
/datum/action/innate/megafauna_attack/aoe_attack
|
||||
name = "All Directions"
|
||||
icon_icon = 'icons/effects/effects.dmi'
|
||||
button_icon_state = "at_shield2"
|
||||
chosen_message = "<span class='colossus'>You are now firing in all directions.</span>"
|
||||
chosen_attack_num = 2
|
||||
|
||||
/datum/action/innate/megafauna_attack/shotgun
|
||||
name = "Shotgun Fire"
|
||||
icon_icon = 'icons/obj/guns/projectile.dmi'
|
||||
button_icon_state = "shotgun"
|
||||
chosen_message = "<span class='colossus'>You are now firing shotgun shots where you aim.</span>"
|
||||
chosen_attack_num = 3
|
||||
|
||||
/datum/action/innate/megafauna_attack/alternating_cardinals
|
||||
name = "Alternating Shots"
|
||||
icon_icon = 'icons/obj/guns/projectile.dmi'
|
||||
button_icon_state = "pistol"
|
||||
chosen_message = "<span class='colossus'>You are now firing in alternating cardinal directions.</span>"
|
||||
chosen_attack_num = 4
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/OpenFire()
|
||||
anger_modifier = Clamp(((maxHealth - health)/50),0,20)
|
||||
ranged_cooldown = world.time + 120
|
||||
|
||||
if(client)
|
||||
switch(chosen_attack)
|
||||
if(1)
|
||||
select_spiral_attack()
|
||||
if(2)
|
||||
random_shots()
|
||||
if(3)
|
||||
blast()
|
||||
if(4)
|
||||
alternating_dir_shots()
|
||||
return
|
||||
|
||||
if(enrage(target))
|
||||
if(move_to_delay == initial(move_to_delay))
|
||||
visible_message("<span class='colossus'>\"<b>You can't dodge.</b>\"</span>")
|
||||
@@ -72,26 +110,111 @@ Difficulty: Very Hard
|
||||
move_to_delay = initial(move_to_delay)
|
||||
|
||||
if(prob(20+anger_modifier)) //Major attack
|
||||
telegraph()
|
||||
|
||||
if(health < maxHealth/3)
|
||||
double_spiral()
|
||||
else
|
||||
visible_message("<span class='colossus'>\"<b>Judgement.</b>\"</span>")
|
||||
spawn(0)
|
||||
spiral_shoot(rand(0, 1))
|
||||
|
||||
select_spiral_attack()
|
||||
else if(prob(20))
|
||||
ranged_cooldown = world.time + 30
|
||||
random_shots()
|
||||
else
|
||||
if(prob(70))
|
||||
ranged_cooldown = world.time + 20
|
||||
blast()
|
||||
else
|
||||
ranged_cooldown = world.time + 40
|
||||
spawn(0)
|
||||
alternating_dir_shots()
|
||||
alternating_dir_shots()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/enrage(mob/living/L)
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/H = L
|
||||
if(H.martial_art && prob(H.martial_art.deflection_chance))
|
||||
. = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/alternating_dir_shots()
|
||||
ranged_cooldown = world.time + 40
|
||||
dir_shots(diagonals)
|
||||
SLEEP_CHECK_DEATH(10)
|
||||
dir_shots(cardinal)
|
||||
SLEEP_CHECK_DEATH(10)
|
||||
dir_shots(diagonals)
|
||||
SLEEP_CHECK_DEATH(10)
|
||||
dir_shots(cardinal)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/select_spiral_attack()
|
||||
telegraph()
|
||||
if(health < maxHealth/3)
|
||||
return double_spiral()
|
||||
visible_message("<span class='colossus'>\"<b>Judgement.</b>\"</span>")
|
||||
return spiral_shoot()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/double_spiral()
|
||||
visible_message("<span class='colossus'>\"<b>Die.</b>\"</span>")
|
||||
|
||||
SLEEP_CHECK_DEATH(10)
|
||||
INVOKE_ASYNC(src, .proc/spiral_shoot, FALSE)
|
||||
INVOKE_ASYNC(src, .proc/spiral_shoot, TRUE)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/spiral_shoot(negative = pick(TRUE, FALSE), counter_start = 8)
|
||||
var/turf/start_turf = get_step(src, pick(alldirs))
|
||||
var/counter = counter_start
|
||||
for(var/i in 1 to 80)
|
||||
if(negative)
|
||||
counter--
|
||||
else
|
||||
counter++
|
||||
if(counter > 16)
|
||||
counter = 1
|
||||
if(counter < 1)
|
||||
counter = 16
|
||||
shoot_projectile(start_turf, counter * 22.5)
|
||||
playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE)
|
||||
SLEEP_CHECK_DEATH(1)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/shoot_projectile(turf/marker, set_angle)
|
||||
if(!isnum(set_angle) && (!marker || marker == loc))
|
||||
return
|
||||
var/turf/startloc = get_turf(src)
|
||||
var/obj/item/projectile/P = new /obj/item/projectile/colossus(startloc)
|
||||
P.preparePixelProjectile(marker, marker, startloc)
|
||||
P.firer = src
|
||||
if(target)
|
||||
P.original = target
|
||||
P.fire(set_angle)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/random_shots()
|
||||
ranged_cooldown = world.time + 30
|
||||
var/turf/U = get_turf(src)
|
||||
playsound(U, 'sound/magic/clockwork/invoke_general.ogg', 300, TRUE, 5)
|
||||
for(var/T in RANGE_TURFS(12, U) - U)
|
||||
if(prob(5))
|
||||
shoot_projectile(T)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/blast(set_angle)
|
||||
ranged_cooldown = world.time + 20
|
||||
var/turf/target_turf = get_turf(target)
|
||||
playsound(src, 'sound/magic/clockwork/invoke_general.ogg', 200, TRUE, 2)
|
||||
newtonian_move(get_dir(target_turf, src))
|
||||
var/angle_to_target = Get_Angle(src, target_turf)
|
||||
if(isnum(set_angle))
|
||||
angle_to_target = set_angle
|
||||
var/static/list/colossus_shotgun_shot_angles = list(12.5, 7.5, 2.5, -2.5, -7.5, -12.5)
|
||||
for(var/i in colossus_shotgun_shot_angles)
|
||||
shoot_projectile(target_turf, angle_to_target + i)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/dir_shots(list/dirs)
|
||||
if(!islist(dirs))
|
||||
dirs = alldirs.Copy()
|
||||
playsound(src, 'sound/magic/clockwork/invoke_general.ogg', 200, TRUE, 2)
|
||||
for(var/d in dirs)
|
||||
var/turf/E = get_step(src, d)
|
||||
shoot_projectile(E)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/telegraph()
|
||||
for(var/mob/M in range(10,src))
|
||||
if(M.client)
|
||||
flash_color(M.client, "#C80000", 1)
|
||||
shake_camera(M, 4, 3)
|
||||
playsound(src, 'sound/magic/narsie_attack.ogg', 200, TRUE)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/devour(mob/living/L)
|
||||
visible_message("<span class='colossus'>[src] disintegrates [L]!</span>")
|
||||
L.dust()
|
||||
|
||||
/obj/effect/temp_visual/at_shield
|
||||
name = "anti-toolbox field"
|
||||
@@ -99,15 +222,14 @@ Difficulty: Very Hard
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "at_shield2"
|
||||
layer = FLY_LAYER
|
||||
luminosity = 2
|
||||
light_range = 2
|
||||
duration = 8
|
||||
var/target
|
||||
|
||||
/obj/effect/temp_visual/at_shield/New(new_loc, new_target)
|
||||
..()
|
||||
/obj/effect/temp_visual/at_shield/Initialize(mapload, new_target)
|
||||
. = ..()
|
||||
target = new_target
|
||||
spawn(0)
|
||||
orbit(target, 0, FALSE, 0, 0, FALSE, TRUE)
|
||||
INVOKE_ASYNC(src, /atom/movable/proc/orbit, target, 0, FALSE, 0, 0, FALSE, TRUE)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/bullet_act(obj/item/projectile/P)
|
||||
if(!stat)
|
||||
@@ -117,126 +239,7 @@ Difficulty: Very Hard
|
||||
|
||||
var/random_y = rand(0, 72)
|
||||
AT.pixel_y += random_y
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/enrage(mob/living/L)
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/H = L
|
||||
if(H.martial_art && prob(H.martial_art.deflection_chance))
|
||||
. = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/alternating_dir_shots()
|
||||
dir_shots(diagonals)
|
||||
sleep(10)
|
||||
dir_shots(cardinal)
|
||||
sleep(10)
|
||||
dir_shots(diagonals)
|
||||
sleep(10)
|
||||
dir_shots(cardinal)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/double_spiral()
|
||||
visible_message("<span class='colossus'>\"<b>Die.</b>\"</span>")
|
||||
|
||||
sleep(10)
|
||||
spawn(0)
|
||||
spiral_shoot()
|
||||
spawn(0)
|
||||
spiral_shoot(1)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/spiral_shoot(negative = 0, counter_start = 1)
|
||||
var/counter = counter_start
|
||||
var/turf/marker
|
||||
for(var/i in 1 to 80)
|
||||
switch(counter)
|
||||
if(1)
|
||||
marker = locate(x, y - 2, z)
|
||||
if(2)
|
||||
marker = locate(x - 1, y - 2, z)
|
||||
if(3)
|
||||
marker = locate(x - 2, y - 2, z)
|
||||
if(4)
|
||||
marker = locate(x - 2, y - 1, z)
|
||||
if(5)
|
||||
marker = locate(x - 2, y, z)
|
||||
if(6)
|
||||
marker = locate(x - 2, y + 1, z)
|
||||
if(7)
|
||||
marker = locate(x - 2, y + 2, z)
|
||||
if(8)
|
||||
marker = locate(x - 1, y + 2, z)
|
||||
if(9)
|
||||
marker = locate(x, y + 2, z)
|
||||
if(10)
|
||||
marker = locate(x + 1, y + 2, z)
|
||||
if(11)
|
||||
marker = locate(x + 2, y + 2, z)
|
||||
if(12)
|
||||
marker = locate(x + 2, y + 1, z)
|
||||
if(13)
|
||||
marker = locate(x + 2, y, z)
|
||||
if(14)
|
||||
marker = locate(x + 2, y - 1, z)
|
||||
if(15)
|
||||
marker = locate(x + 2, y - 2, z)
|
||||
if(16)
|
||||
marker = locate(x + 1, y - 2, z)
|
||||
|
||||
if(negative)
|
||||
counter--
|
||||
else
|
||||
counter++
|
||||
if(counter > 16)
|
||||
counter = 1
|
||||
if(counter < 1)
|
||||
counter = 16
|
||||
shoot_projectile(marker)
|
||||
playsound(get_turf(src), 'sound/magic/invoke_general.ogg', 20, 1)
|
||||
sleep(1)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/shoot_projectile(turf/marker)
|
||||
if(!marker || marker == loc)
|
||||
return
|
||||
var/turf/startloc = get_turf(src)
|
||||
var/obj/item/projectile/P = new /obj/item/projectile/colossus(startloc)
|
||||
P.current = startloc
|
||||
P.starting = startloc
|
||||
P.firer = src
|
||||
P.yo = marker.y - startloc.y
|
||||
P.xo = marker.x - startloc.x
|
||||
if(target)
|
||||
P.original = target
|
||||
else
|
||||
P.original = marker
|
||||
P.fire()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/random_shots()
|
||||
var/turf/U = get_turf(src)
|
||||
playsound(U, 'sound/magic/invoke_general.ogg', 300, 1, 5)
|
||||
for(var/T in RANGE_TURFS(12, U) - U)
|
||||
if(prob(5))
|
||||
shoot_projectile(T)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/blast()
|
||||
playsound(get_turf(src), 'sound/magic/invoke_general.ogg', 200, 1, 2)
|
||||
var/turf/T = get_turf(target)
|
||||
newtonian_move(get_dir(T, targets_from))
|
||||
for(var/turf/turf in range(1, T))
|
||||
shoot_projectile(turf)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/dir_shots(list/dirs)
|
||||
if(!islist(dirs))
|
||||
dirs = alldirs.Copy()
|
||||
playsound(get_turf(src), 'sound/magic/invoke_general.ogg', 200, 1, 2)
|
||||
for(var/d in dirs)
|
||||
var/turf/E = get_step(src, d)
|
||||
shoot_projectile(E)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/telegraph()
|
||||
for(var/mob/M in range(10,src))
|
||||
if(M.client)
|
||||
flash_color(M.client, rgb(200, 0, 0), 1)
|
||||
shake_camera(M, 4, 3)
|
||||
playsound(get_turf(src),'sound/magic/narsie_attack.ogg', 200, 1)
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/colossus
|
||||
name ="death bolt"
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
#define DRAKE_SWOOP_HEIGHT 270 //how high up drakes go, in pixels
|
||||
#define DRAKE_SWOOP_DIRECTION_CHANGE_RANGE 5 //the range our x has to be within to not change the direction we slam from
|
||||
|
||||
#define SWOOP_DAMAGEABLE 1
|
||||
#define SWOOP_INVULNERABLE 2
|
||||
|
||||
/*
|
||||
|
||||
ASH DRAKE
|
||||
@@ -6,10 +12,11 @@ Ash drakes spawn randomly wherever a lavaland creature is able to spawn. They ar
|
||||
|
||||
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.
|
||||
|
||||
Whenever possible, the drake will breathe fire in the four cardinal directions, igniting and heavily damaging anything caught in the blast.
|
||||
It also often causes fire to rain from the sky - many nearby turfs will flash red as a fireball crashes into them, dealing damage to anything on the turfs.
|
||||
The drake also utilizes its wings to fly into the sky and crash down onto a specified point. Anything on this point takes tremendous damage.
|
||||
Whenever possible, the drake will breathe fire directly at it's target, igniting and heavily damaging anything caught in the blast.
|
||||
It also often causes lava to pool from the ground around you - many nearby turfs will temporarily turn into lava, dealing damage to anything on the turfs.
|
||||
The drake also utilizes its wings to fly into the sky, flying after its target and attempting to slam down on them. Anything near when it slams down takes huge damage.
|
||||
- Sometimes it will chain these swooping attacks over and over, making swiftness a necessity.
|
||||
- Sometimes, it will encase its target in an arena of lava
|
||||
|
||||
When an ash drake dies, it leaves behind a chest that can contain four things:
|
||||
1. A spectral blade that allows its wielder to call ghosts to it, enhancing its power
|
||||
@@ -39,31 +46,358 @@ Difficulty: Medium
|
||||
armour_penetration = 40
|
||||
melee_damage_lower = 40
|
||||
melee_damage_upper = 40
|
||||
speed = 1
|
||||
move_to_delay = 10
|
||||
ranged = 1
|
||||
speed = 5
|
||||
move_to_delay = 5
|
||||
ranged = TRUE
|
||||
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/animalhide/ashdrake = 10, /obj/item/stack/sheet/bone = 30)
|
||||
var/swooping = 0
|
||||
var/swoop_cooldown = 0
|
||||
var/swooping = NONE
|
||||
var/player_cooldown = 0
|
||||
internal_type = /obj/item/gps/internal/dragon
|
||||
medal_type = BOSS_MEDAL_DRAKE
|
||||
score_type = DRAKE_SCORE
|
||||
deathmessage = "collapses into a pile of bones, its flesh sloughing away."
|
||||
death_sound = 'sound/misc/demon_dies.ogg'
|
||||
attack_action_types = list(/datum/action/innate/megafauna_attack/fire_cone,
|
||||
/datum/action/innate/megafauna_attack/fire_cone_meteors,
|
||||
/datum/action/innate/megafauna_attack/mass_fire,
|
||||
/datum/action/innate/megafauna_attack/lava_swoop)
|
||||
|
||||
/datum/action/innate/megafauna_attack/fire_cone
|
||||
name = "Fire Cone"
|
||||
icon_icon = 'icons/obj/wizard.dmi'
|
||||
button_icon_state = "fireball"
|
||||
chosen_message = "<span class='colossus'>You are now shooting fire at your target.</span>"
|
||||
chosen_attack_num = 1
|
||||
|
||||
/datum/action/innate/megafauna_attack/fire_cone_meteors
|
||||
name = "Fire Cone With Meteors"
|
||||
icon_icon = 'icons/mob/actions/actions.dmi'
|
||||
button_icon_state = "sniper_zoom"
|
||||
chosen_message = "<span class='colossus'>You are now shooting fire at your target and raining fire around you.</span>"
|
||||
chosen_attack_num = 2
|
||||
|
||||
/datum/action/innate/megafauna_attack/mass_fire
|
||||
name = "Mass Fire Attack"
|
||||
icon_icon = 'icons/effects/fire.dmi'
|
||||
button_icon_state = "1"
|
||||
chosen_message = "<span class='colossus'>You are now shooting mass fire at your target.</span>"
|
||||
chosen_attack_num = 3
|
||||
|
||||
/datum/action/innate/megafauna_attack/lava_swoop
|
||||
name = "Lava Swoop"
|
||||
icon_icon = 'icons/effects/effects.dmi'
|
||||
button_icon_state = "lavastaff_warn"
|
||||
chosen_message = "<span class='colossus'>You are now swooping and raining lava at your target.</span>"
|
||||
chosen_attack_num = 4
|
||||
|
||||
/obj/item/gps/internal/dragon
|
||||
icon_state = null
|
||||
gpstag = "Fiery Signal"
|
||||
desc = "Here there be dragons."
|
||||
invisibility = 100
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/OpenFire()
|
||||
if(swooping)
|
||||
return
|
||||
|
||||
anger_modifier = Clamp(((maxHealth - health)/50),0,20)
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
|
||||
if(client)
|
||||
switch(chosen_attack)
|
||||
if(1)
|
||||
fire_cone(meteors = FALSE)
|
||||
if(2)
|
||||
fire_cone()
|
||||
if(3)
|
||||
mass_fire()
|
||||
if(4)
|
||||
lava_swoop()
|
||||
return
|
||||
|
||||
if(prob(15 + anger_modifier))
|
||||
lava_swoop()
|
||||
|
||||
else if(prob(10+anger_modifier))
|
||||
shoot_fire_attack()
|
||||
else
|
||||
fire_cone()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/shoot_fire_attack()
|
||||
if(health < maxHealth*0.5)
|
||||
mass_fire()
|
||||
else
|
||||
fire_cone()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_rain()
|
||||
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/lava_pools(var/amount, var/delay = 0.8)
|
||||
if(!target)
|
||||
return
|
||||
target.visible_message("<span class='boldwarning'>Lava starts to pool up around you!</span>")
|
||||
while(amount > 0)
|
||||
if(QDELETED(target))
|
||||
break
|
||||
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_CHECK_DEATH(delay)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/lava_swoop(var/amount = 30)
|
||||
if(health < maxHealth * 0.5)
|
||||
return swoop_attack(lava_arena = TRUE, swoop_cooldown = 60)
|
||||
INVOKE_ASYNC(src, .proc/lava_pools, amount)
|
||||
swoop_attack(FALSE, target, 1000) // longer cooldown until it gets reset below
|
||||
SLEEP_CHECK_DEATH(0)
|
||||
fire_cone()
|
||||
if(health < maxHealth*0.5)
|
||||
SLEEP_CHECK_DEATH(10)
|
||||
fire_cone()
|
||||
SLEEP_CHECK_DEATH(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)
|
||||
SLEEP_CHECK_DEATH(0)
|
||||
for(var/i = 1 to times)
|
||||
SetRecoveryTime(50)
|
||||
playsound(get_turf(src),'sound/magic/fireball.ogg', 200, TRUE)
|
||||
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_CHECK_DEATH(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/simulated/floor/indestructible))
|
||||
continue
|
||||
if(!istype(T, /turf/simulated/wall/indestructible))
|
||||
T.ChangeTurf(/turf/simulated/floor/plating/asteroid/basalt/lava_land_surface)
|
||||
else
|
||||
indestructible_turfs += T
|
||||
SLEEP_CHECK_DEATH(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/simulated/wall/indestructible))
|
||||
new /obj/effect/temp_visual/lava_safe(T)
|
||||
amount--
|
||||
SLEEP_CHECK_DEATH(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
|
||||
SLEEP_CHECK_DEATH(0)
|
||||
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_CHECK_DEATH(10) // run.
|
||||
mass_fire(20, 15, 3)
|
||||
move_to_delay = initial(move_to_delay)
|
||||
remove_atom_colour(TEMPORARY_COLOUR_PRIORITY)
|
||||
light_range = initial(light_range)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_cone(var/atom/at = target, var/meteors = TRUE)
|
||||
playsound(get_turf(src),'sound/magic/fireball.ogg', 200, TRUE)
|
||||
SLEEP_CHECK_DEATH(0)
|
||||
if(prob(50) && meteors)
|
||||
INVOKE_ASYNC(src, .proc/fire_rain)
|
||||
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)
|
||||
SLEEP_CHECK_DEATH(0)
|
||||
dragon_fire_line(src, turfs)
|
||||
|
||||
//fire line keeps going even if dragon is deleted
|
||||
/proc/dragon_fire_line(var/source, var/list/turfs)
|
||||
var/list/hit_list = list()
|
||||
for(var/turf/T in turfs)
|
||||
if(T.density)
|
||||
break
|
||||
new /obj/effect/hotspot(T)
|
||||
T.hotspot_expose(700,50,1)
|
||||
for(var/mob/living/L in T.contents)
|
||||
if(L in hit_list || L == source)
|
||||
continue
|
||||
hit_list += L
|
||||
L.adjustFireLoss(20)
|
||||
to_chat(L, "<span class='userdanger'>You're hit by [source]'s fire breath!</span>")
|
||||
|
||||
// deals damage to mechs
|
||||
for(var/obj/mecha/M in T.contents)
|
||||
if(M in hit_list)
|
||||
continue
|
||||
hit_list += M
|
||||
M.take_damage(45, BRUTE, "melee", 1)
|
||||
sleep(1.5)
|
||||
|
||||
/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
|
||||
stop_automated_movement = TRUE
|
||||
swooping |= SWOOP_DAMAGEABLE
|
||||
density = FALSE
|
||||
icon_state = "shadow"
|
||||
visible_message("<span class='boldwarning'>[src] swoops up high!</span>")
|
||||
|
||||
var/negative
|
||||
var/initial_x = x
|
||||
if(target.x < initial_x) //if the target's x is lower than ours, swoop to the left
|
||||
negative = TRUE
|
||||
else if(target.x > initial_x)
|
||||
negative = FALSE
|
||||
else if(target.x == initial_x) //if their x is the same, pick a direction
|
||||
negative = prob(50)
|
||||
var/obj/effect/temp_visual/dragon_flight/F = new /obj/effect/temp_visual/dragon_flight(loc, negative)
|
||||
|
||||
negative = !negative //invert it for the swoop down later
|
||||
|
||||
var/oldtransform = transform
|
||||
alpha = 255
|
||||
animate(src, alpha = 204, transform = matrix()*0.9, time = 3, easing = BOUNCE_EASING)
|
||||
for(var/i in 1 to 3)
|
||||
sleep(1)
|
||||
if(QDELETED(src) || stat == DEAD) //we got hit and died, rip us
|
||||
qdel(F)
|
||||
if(stat == DEAD)
|
||||
swooping &= ~SWOOP_DAMAGEABLE
|
||||
animate(src, alpha = 255, transform = oldtransform, time = 0, flags = ANIMATION_END_NOW) //reset immediately
|
||||
return
|
||||
animate(src, alpha = 100, transform = matrix()*0.7, time = 7)
|
||||
swooping |= SWOOP_INVULNERABLE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
SLEEP_CHECK_DEATH(7)
|
||||
|
||||
while(target && loc != get_turf(target))
|
||||
forceMove(get_step(src, get_dir(src, target)))
|
||||
SLEEP_CHECK_DEATH(0.5)
|
||||
|
||||
// Ash drake flies onto its target and rains fire down upon them
|
||||
var/descentTime = 10
|
||||
var/lava_success = TRUE
|
||||
if(lava_arena)
|
||||
lava_success = lava_arena()
|
||||
|
||||
|
||||
//ensure swoop direction continuity.
|
||||
if(negative)
|
||||
if(IsInRange(x, initial_x + 1, initial_x + DRAKE_SWOOP_DIRECTION_CHANGE_RANGE))
|
||||
negative = FALSE
|
||||
else
|
||||
if(IsInRange(x, initial_x - DRAKE_SWOOP_DIRECTION_CHANGE_RANGE, initial_x - 1))
|
||||
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, descentTime)
|
||||
SLEEP_CHECK_DEATH(descentTime)
|
||||
swooping &= ~SWOOP_INVULNERABLE
|
||||
mouse_opacity = initial(mouse_opacity)
|
||||
icon_state = "dragon"
|
||||
playsound(loc, 'sound/effects/meteorimpact.ogg', 200, TRUE)
|
||||
for(var/mob/living/L in orange(1, src))
|
||||
if(L.stat)
|
||||
visible_message("<span class='warning'>[src] slams down on [L], crushing [L.p_them()]!</span>")
|
||||
L.gib()
|
||||
else
|
||||
L.adjustBruteLoss(75)
|
||||
if(L && !QDELETED(L)) // Some mobs are deleted on death
|
||||
var/throw_dir = get_dir(src, L)
|
||||
if(L.loc == loc)
|
||||
throw_dir = pick(alldirs)
|
||||
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)
|
||||
|
||||
density = TRUE
|
||||
SLEEP_CHECK_DEATH(1)
|
||||
swooping &= ~SWOOP_DAMAGEABLE
|
||||
SetRecoveryTime(swoop_cooldown)
|
||||
if(!lava_success)
|
||||
arena_escape_enrage()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/ex_act(severity, target)
|
||||
if(severity == 3)
|
||||
if(severity == EXPLODE_LIGHT)
|
||||
return
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/adjustHealth(amount, updating_health = TRUE)
|
||||
if(swooping)
|
||||
if(swooping & SWOOP_INVULNERABLE)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/visible_message()
|
||||
if(swooping & SWOOP_INVULNERABLE) //to suppress attack messages without overriding every single proc that could send a message saying we got hit
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/AttackingTarget()
|
||||
if(!swooping)
|
||||
return ..()
|
||||
@@ -83,181 +417,161 @@ Difficulty: Medium
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/Process_Spacemove(movement_dir = 0)
|
||||
return 1
|
||||
|
||||
/obj/effect/temp_visual/fireball
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "fireball"
|
||||
name = "fireball"
|
||||
desc = "Get out of the way!"
|
||||
layer = 6
|
||||
randomdir = 0
|
||||
duration = 12
|
||||
pixel_z = 500
|
||||
/obj/effect/temp_visual/lava_warning
|
||||
icon_state = "lavastaff_warn"
|
||||
layer = BELOW_MOB_LAYER
|
||||
light_range = 2
|
||||
duration = 13
|
||||
|
||||
/obj/effect/temp_visual/fireball/New(loc)
|
||||
..()
|
||||
animate(src, pixel_z = 0, time = 12)
|
||||
/obj/effect/temp_visual/lava_warning/ex_act()
|
||||
return
|
||||
|
||||
/obj/effect/temp_visual/target
|
||||
icon = 'icons/mob/actions/actions.dmi'
|
||||
icon_state = "sniper_zoom"
|
||||
layer = MOB_LAYER - 0.1
|
||||
luminosity = 2
|
||||
duration = 12
|
||||
/obj/effect/temp_visual/lava_warning/Initialize(mapload, var/reset_time = 10)
|
||||
. = ..()
|
||||
INVOKE_ASYNC(src, .proc/fall, reset_time)
|
||||
src.alpha = 63.75
|
||||
animate(src, alpha = 255, time = duration)
|
||||
|
||||
/obj/effect/temp_visual/lava_warning/proc/fall(var/reset_time)
|
||||
var/turf/T = get_turf(src)
|
||||
playsound(T,'sound/magic/fleshtostone.ogg', 80, TRUE)
|
||||
sleep(duration)
|
||||
playsound(T,'sound/magic/fireball.ogg', 200, TRUE)
|
||||
|
||||
for(var/mob/living/L in T.contents)
|
||||
if(istype(L, /mob/living/simple_animal/hostile/megafauna/dragon))
|
||||
continue
|
||||
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(!T.density && !istype(T, /turf/simulated/floor/plating/lava))
|
||||
var/lava_turf = /turf/simulated/floor/plating/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
|
||||
duration = 82
|
||||
color = COLOR_DARK_ORANGE
|
||||
|
||||
/obj/effect/temp_visual/drakewall/CanAtmosPass()
|
||||
return !density
|
||||
|
||||
/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"
|
||||
desc = "Don't just stand there, move!"
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "landing"
|
||||
layer = MOB_LAYER - 0.1
|
||||
layer = BELOW_MOB_LAYER
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
color = "#FF0000"
|
||||
duration = 10
|
||||
|
||||
/obj/effect/temp_visual/dragon_flight
|
||||
icon = 'icons/mob/lavaland/64x64megafauna.dmi'
|
||||
icon_state = "dragon"
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
pixel_x = -16
|
||||
duration = 10
|
||||
randomdir = FALSE
|
||||
|
||||
/obj/effect/temp_visual/dragon_flight/Initialize(mapload, negative)
|
||||
. = ..()
|
||||
INVOKE_ASYNC(src, .proc/flight, negative)
|
||||
|
||||
/obj/effect/temp_visual/dragon_flight/proc/flight(negative)
|
||||
if(negative)
|
||||
animate(src, pixel_x = -DRAKE_SWOOP_HEIGHT*0.1, pixel_z = DRAKE_SWOOP_HEIGHT*0.15, time = 3, easing = BOUNCE_EASING)
|
||||
else
|
||||
animate(src, pixel_x = DRAKE_SWOOP_HEIGHT*0.1, pixel_z = DRAKE_SWOOP_HEIGHT*0.15, time = 3, easing = BOUNCE_EASING)
|
||||
sleep(3)
|
||||
icon_state = "swoop"
|
||||
if(negative)
|
||||
animate(src, pixel_x = -DRAKE_SWOOP_HEIGHT, pixel_z = DRAKE_SWOOP_HEIGHT, time = 7)
|
||||
else
|
||||
animate(src, pixel_x = DRAKE_SWOOP_HEIGHT, pixel_z = DRAKE_SWOOP_HEIGHT, time = 7)
|
||||
|
||||
/obj/effect/temp_visual/dragon_flight/end
|
||||
pixel_x = DRAKE_SWOOP_HEIGHT
|
||||
pixel_z = DRAKE_SWOOP_HEIGHT
|
||||
duration = 10
|
||||
|
||||
/obj/effect/temp_visual/dragon_flight/end/flight(negative)
|
||||
if(negative)
|
||||
pixel_x = -DRAKE_SWOOP_HEIGHT
|
||||
animate(src, pixel_x = -16, pixel_z = 0, time = 5)
|
||||
else
|
||||
animate(src, pixel_x = -16, pixel_z = 0, time = 5)
|
||||
|
||||
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 = 270
|
||||
|
||||
/obj/effect/temp_visual/fireball/Initialize()
|
||||
. = ..()
|
||||
animate(src, pixel_z = 0, time = duration)
|
||||
|
||||
/obj/effect/temp_visual/target
|
||||
icon = 'icons/mob/actions/actions.dmi'
|
||||
icon_state = "sniper_zoom"
|
||||
layer = BELOW_MOB_LAYER
|
||||
light_range = 2
|
||||
duration = 9
|
||||
|
||||
/obj/effect/temp_visual/target/ex_act()
|
||||
return
|
||||
|
||||
/obj/effect/temp_visual/target/New(loc)
|
||||
..()
|
||||
spawn(0)
|
||||
fall()
|
||||
/obj/effect/temp_visual/target/Initialize(mapload, list/flame_hit)
|
||||
. = ..()
|
||||
INVOKE_ASYNC(src, .proc/fall, flame_hit)
|
||||
|
||||
/obj/effect/temp_visual/target/proc/fall()
|
||||
/obj/effect/temp_visual/target/proc/fall(list/flame_hit)
|
||||
var/turf/T = get_turf(src)
|
||||
playsound(T,'sound/magic/fireball.ogg', 200, 1)
|
||||
playsound(T,'sound/magic/fleshtostone.ogg', 80, TRUE)
|
||||
new /obj/effect/temp_visual/fireball(T)
|
||||
sleep(12)
|
||||
explosion(T, 0, 0, 1, 0, 0, 0, 1, 1)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/OpenFire()
|
||||
anger_modifier = Clamp(((maxHealth - health)/50),0,20)
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
if(swooping)
|
||||
fire_rain()
|
||||
return
|
||||
|
||||
if(prob(15 + anger_modifier) && !client)
|
||||
if(health < maxHealth/2)
|
||||
spawn(0)
|
||||
swoop_attack(1)
|
||||
else
|
||||
fire_rain()
|
||||
|
||||
else if(prob(10+anger_modifier) && !client)
|
||||
if(health > maxHealth/2)
|
||||
spawn(0)
|
||||
swoop_attack(0)
|
||||
else
|
||||
spawn(0)
|
||||
triple_swoop(0)
|
||||
else
|
||||
fire_walls()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_rain()
|
||||
visible_message("<span class='boldwarning'>Fire rains from the sky!</span>")
|
||||
for(var/turf/turf in range(12,get_turf(src)))
|
||||
if(prob(10))
|
||||
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 cardinal)
|
||||
spawn(0)
|
||||
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 || !previousturf.CanAtmosPass(J))
|
||||
break
|
||||
range--
|
||||
new /obj/effect/hotspot(J)
|
||||
J.hotspot_expose(700,50,1)
|
||||
for(var/mob/living/L in J.contents - hit_things)
|
||||
L.adjustFireLoss(20)
|
||||
sleep(duration)
|
||||
if(ismineralturf(T))
|
||||
var/turf/simulated/mineral/M = T
|
||||
M.gets_drilled()
|
||||
playsound(T, "explosion", 80, TRUE)
|
||||
new /obj/effect/hotspot(T)
|
||||
T.hotspot_expose(700, 50, 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>")
|
||||
hit_things += L
|
||||
previousturf = J
|
||||
sleep(1)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/triple_swoop()
|
||||
swoop_attack()
|
||||
swoop_attack()
|
||||
swoop_attack()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/swoop_attack(fire_rain = 0, atom/movable/manual_target)
|
||||
if(stat || swooping)
|
||||
return
|
||||
swoop_cooldown = world.time + 200
|
||||
var/atom/swoop_target
|
||||
if(manual_target)
|
||||
swoop_target = manual_target
|
||||
else
|
||||
swoop_target = target
|
||||
stop_automated_movement = TRUE
|
||||
swooping = 1
|
||||
density = 0
|
||||
icon_state = "swoop"
|
||||
visible_message("<span class='boldwarning'>[src] swoops up high!</span>")
|
||||
if(prob(50))
|
||||
animate(src, pixel_x = 500, pixel_z = 500, time = 10)
|
||||
else
|
||||
animate(src, pixel_x = -500, pixel_z = 500, time = 10)
|
||||
sleep(30)
|
||||
|
||||
var/turf/tturf
|
||||
if(fire_rain)
|
||||
fire_rain()
|
||||
|
||||
icon_state = "dragon"
|
||||
if(swoop_target && !QDELETED(swoop_target) && swoop_target.z == src.z)
|
||||
tturf = get_turf(swoop_target)
|
||||
else
|
||||
tturf = get_turf(src)
|
||||
forceMove(tturf)
|
||||
new /obj/effect/temp_visual/dragon_swoop(tturf)
|
||||
animate(src, pixel_x = initial(pixel_x), pixel_z = 0, time = 10)
|
||||
sleep(10)
|
||||
playsound(src.loc, 'sound/effects/meteorimpact.ogg', 200, 1)
|
||||
for(var/mob/living/L in orange(1, src))
|
||||
if(L.stat)
|
||||
visible_message("<span class='warning'>[src] slams down on [L], crushing [L.p_them()]!</span>")
|
||||
L.gib()
|
||||
flame_hit[L] = TRUE
|
||||
else
|
||||
L.adjustBruteLoss(75)
|
||||
if(L && !QDELETED(L)) // Some mobs are deleted on death
|
||||
var/throw_dir = get_dir(src, L)
|
||||
if(L.loc == loc)
|
||||
throw_dir = pick(alldirs)
|
||||
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/mob/M in range(7, src))
|
||||
shake_camera(M, 15, 1)
|
||||
|
||||
stop_automated_movement = FALSE
|
||||
swooping = 0
|
||||
density = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/AltClickOn(atom/movable/A)
|
||||
if(!istype(A))
|
||||
return
|
||||
if(swoop_cooldown >= world.time)
|
||||
to_chat(src, "<span class='warning'>You need to wait 20 seconds between swoop attacks!</span>")
|
||||
return
|
||||
swoop_attack(1, A)
|
||||
|
||||
/obj/item/gps/internal/dragon
|
||||
icon_state = null
|
||||
gpstag = "Fiery Signal"
|
||||
desc = "Here there be dragons."
|
||||
invisibility = 100
|
||||
L.adjustFireLoss(10) //if we've already hit them, do way less damage
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/lesser
|
||||
name = "lesser ash drake"
|
||||
@@ -267,9 +581,92 @@ Difficulty: Medium
|
||||
obj_damage = 80
|
||||
melee_damage_upper = 30
|
||||
melee_damage_lower = 30
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
|
||||
loot = list()
|
||||
crusher_loot = list()
|
||||
butcher_results = list(/obj/item/stack/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/bone = 30)
|
||||
attack_action_types = list()
|
||||
|
||||
/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/grant_achievement(medaltype,scoretype)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/space_dragon
|
||||
name = "space dragon"
|
||||
maxHealth = 250
|
||||
health = 250
|
||||
faction = list("neutral")
|
||||
desc = "A space carp turned dragon by vile magic. Has the same ferocity of a space carp, but also a much more enabling body."
|
||||
icon = 'icons/mob/spacedragon.dmi'
|
||||
icon_state = "spacedragon"
|
||||
icon_living = "spacedragon"
|
||||
icon_dead = "spacedragon_dead"
|
||||
obj_damage = 80
|
||||
melee_damage_upper = 35
|
||||
melee_damage_lower = 35
|
||||
speed = 0
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
loot = list()
|
||||
crusher_loot = list()
|
||||
butcher_results = list(/obj/item/stack/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/bone = 30)
|
||||
move_force = MOVE_FORCE_NORMAL
|
||||
move_resist = MOVE_FORCE_NORMAL
|
||||
pull_force = MOVE_FORCE_NORMAL
|
||||
deathmessage = "screeches as its wings turn to dust and it collapses on the floor, life estinguished."
|
||||
attack_action_types = list()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/space_dragon/grant_achievement(medaltype, scoretype)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/space_dragon/Initialize(mapload)
|
||||
var/obj/effect/proc_holder/spell/aoe_turf/repulse/spacedragon/repulse_action = new /obj/effect/proc_holder/spell/aoe_turf/repulse/spacedragon(src)
|
||||
repulse_action.action.Grant(src)
|
||||
mob_spell_list += repulse_action
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/space_dragon/proc/fire_stream(var/atom/at = target)
|
||||
playsound(get_turf(src),'sound/magic/fireball.ogg', 200, TRUE)
|
||||
SLEEP_CHECK_DEATH(0)
|
||||
var/range = 20
|
||||
var/list/turfs = list()
|
||||
turfs = line_target(0, range, at)
|
||||
INVOKE_ASYNC(src, .proc/fire_line, turfs)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/space_dragon/OpenFire()
|
||||
if(swooping)
|
||||
return
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
fire_stream()
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/repulse/spacedragon
|
||||
name = "Tail Sweep"
|
||||
desc = "Throw back attackers with a sweep of your tail."
|
||||
sound = 'sound/magic/tail_swing.ogg'
|
||||
charge_max = 150
|
||||
clothes_req = FALSE
|
||||
range = 1
|
||||
cooldown_min = 150
|
||||
invocation_type = "none"
|
||||
sparkle_path = /obj/effect/temp_visual/dir_setting/tailsweep
|
||||
action_icon_state = "tailsweep"
|
||||
action_background_icon_state = "bg_alien"
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/repulse/spacedragon/cast(list/targets, mob/user = usr)
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
playsound(C.loc, 'sound/effects/hit_punch.ogg', 80, TRUE, TRUE)
|
||||
C.spin(6, 1)
|
||||
..(targets, user, 3)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/space_dragon/AltClickOn(atom/movable/A)
|
||||
return
|
||||
@@ -7,11 +7,11 @@
|
||||
sentience_type = SENTIENCE_BOSS
|
||||
environment_smash = ENVIRONMENT_SMASH_RWALLS
|
||||
obj_damage = 400
|
||||
luminosity = 3
|
||||
light_range = 3
|
||||
faction = list("mining", "boss")
|
||||
weather_immunities = list("lava","ash")
|
||||
flying = 1
|
||||
robust_searching = 1
|
||||
flying = TRUE
|
||||
robust_searching = TRUE
|
||||
ranged_ignores_vision = TRUE
|
||||
stat_attack = DEAD
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
@@ -20,6 +20,12 @@
|
||||
maxbodytemp = INFINITY
|
||||
vision_range = 5
|
||||
aggro_vision_range = 18
|
||||
move_force = MOVE_FORCE_OVERPOWERING
|
||||
move_resist = MOVE_FORCE_OVERPOWERING
|
||||
pull_force = MOVE_FORCE_OVERPOWERING
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
layer = LARGE_MOB_LAYER //Looks weird with them slipping under mineral walls and cameras and shit otherwise
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE // Easier to click on in melee, they're giant targets anyway
|
||||
var/list/crusher_loot
|
||||
var/medal_type
|
||||
var/score_type = BOSS_SCORE
|
||||
@@ -27,13 +33,9 @@
|
||||
var/anger_modifier = 0
|
||||
var/obj/item/gps/internal_gps
|
||||
var/internal_type
|
||||
move_force = MOVE_FORCE_OVERPOWERING
|
||||
move_resist = MOVE_FORCE_OVERPOWERING
|
||||
pull_force = MOVE_FORCE_OVERPOWERING
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
layer = LARGE_MOB_LAYER //Looks weird with them slipping under mineral walls and cameras and shit otherwise
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE // Easier to click on in melee, they're giant targets anyway
|
||||
var/recovery_time = 0
|
||||
var/true_spawn = TRUE // if this is a megafauna that should grant achievements, or have a gps signal
|
||||
var/nest_range = 10
|
||||
var/chosen_attack = 1 // chosen attack num
|
||||
var/list/attack_action_types = list()
|
||||
|
||||
@@ -50,6 +52,16 @@
|
||||
QDEL_NULL(internal_gps)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/Moved()
|
||||
if(nest && nest.parent && get_dist(nest.parent, src) > nest_range)
|
||||
var/turf/closest = get_turf(nest.parent)
|
||||
for(var/i = 1 to nest_range)
|
||||
closest = get_step(closest, get_dir(closest, src))
|
||||
forceMove(closest) // someone teleported out probably and the megafauna kept chasing them
|
||||
target = null
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/can_die()
|
||||
return ..() && health <= 0
|
||||
|
||||
@@ -68,6 +80,8 @@
|
||||
loot = crusher_loot
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/AttackingTarget()
|
||||
if(recovery_time >= world.time)
|
||||
return
|
||||
. = ..()
|
||||
if(. && isliving(target))
|
||||
var/mob/living/L = target
|
||||
@@ -90,13 +104,14 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/proc/devour(mob/living/L)
|
||||
if(!L)
|
||||
return
|
||||
return FALSE
|
||||
visible_message(
|
||||
"<span class='danger'>[src] devours [L]!</span>",
|
||||
"<span class='userdanger'>You feast on [L], restoring your health!</span>")
|
||||
if(!is_station_level(z) && !client) //NPC monsters won't heal while on station
|
||||
if(!is_station_level(z) || client) //NPC monsters won't heal while on station
|
||||
adjustBruteLoss(-L.maxHealth/2)
|
||||
L.gib()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/ex_act(severity, target)
|
||||
switch(severity)
|
||||
@@ -109,6 +124,10 @@
|
||||
if(3)
|
||||
adjustBruteLoss(50)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/proc/SetRecoveryTime(buffer_time)
|
||||
recovery_time = world.time + buffer_time
|
||||
ranged_cooldown = world.time + buffer_time
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/proc/grant_achievement(medaltype, scoretype, crusher_kill)
|
||||
if(!medal_type || admin_spawned || !SSmedals.hub_enabled) //Don't award medals if the medal type isn't set
|
||||
return FALSE
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
. = ..()
|
||||
if(.)
|
||||
var/mob/living/L = target
|
||||
if (istype(L))
|
||||
if(istype(L))
|
||||
L.adjust_fire_stacks(0.1)
|
||||
L.IgniteMob()
|
||||
|
||||
@@ -141,5 +141,12 @@
|
||||
damage_type = BURN
|
||||
nodamage = FALSE
|
||||
|
||||
/obj/item/projectile/temp/basilisk/icewing/on_hit(atom/target, blocked = FALSE)
|
||||
. = ..()
|
||||
if(.)
|
||||
var/mob/living/L = target
|
||||
if(istype(L))
|
||||
L.apply_status_effect(/datum/status_effect/freon/watcher)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/basilisk/watcher/tendril
|
||||
fromtendril = TRUE
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
|
||||
pressure_resistance = 300
|
||||
faction = list("undead") // did I mention ghost
|
||||
loot = list(/obj/item/reagent_containers/food/snacks/ectoplasm)
|
||||
del_on_death = 1
|
||||
|
||||
@@ -49,10 +49,6 @@ var/global/list/ts_spiderling_list = list()
|
||||
// '1' (default for most simple_mobs, including terror spiders) converts to 3.5, or 2.8 tiles/sec.
|
||||
// '2' converts to 4.5, or 2.2 tiles/sec.
|
||||
|
||||
// Atmos
|
||||
pressure_resistance = 50 //50 kPa difference required to push
|
||||
throw_pressure_limit = 100 //100 kPa difference required to throw
|
||||
|
||||
// Ventcrawling
|
||||
ventcrawler = 1 // allows player ventcrawling
|
||||
var/ai_ventcrawls = TRUE
|
||||
|
||||
@@ -556,6 +556,11 @@
|
||||
genemutcheck(src, block,null, MUTCHK_FORCED)
|
||||
dna.UpdateSE()
|
||||
|
||||
///////////////////////////////// FROZEN /////////////////////////////////////
|
||||
|
||||
/mob/living/proc/IsFrozen()
|
||||
return has_status_effect(/datum/status_effect/freon)
|
||||
|
||||
///////////////////////////////////// STUN ABSORPTION /////////////////////////////////////
|
||||
|
||||
/mob/living/proc/add_stun_absorption(key, duration, priority, message, self_message, examine_message)
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
else if((fall_over || resting) && !lying)
|
||||
fall(fall_over)
|
||||
|
||||
canmove = !(fall_over || resting || stunned || buckled)
|
||||
canmove = !(fall_over || resting || stunned || IsFrozen() || buckled)
|
||||
density = !lying
|
||||
if(lying)
|
||||
if(layer == initial(layer))
|
||||
|
||||
Reference in New Issue
Block a user