Merge branch 'master' into donut
This commit is contained in:
@@ -25,7 +25,7 @@
|
||||
features = random_features()
|
||||
age = rand(AGE_MIN,AGE_MAX)
|
||||
|
||||
/datum/preferences/proc/update_preview_icon()
|
||||
/datum/preferences/proc/update_preview_icon(equip_job = TRUE)
|
||||
// Determine what job is marked as 'High' priority, and dress them up as such.
|
||||
var/datum/job/previewJob
|
||||
var/highest_pref = 0
|
||||
@@ -45,12 +45,11 @@
|
||||
|
||||
// Set up the dummy for its photoshoot
|
||||
var/mob/living/carbon/human/dummy/mannequin = generate_or_wait_for_human_dummy(DUMMY_HUMAN_SLOT_PREFERENCES)
|
||||
mannequin.cut_overlays()
|
||||
// Apply the Dummy's preview background first so we properly layer everything else on top of it.
|
||||
mannequin.add_overlay(mutable_appearance('modular_citadel/icons/ui/backgrounds.dmi', bgstate, layer = SPACE_LAYER))
|
||||
copy_to(mannequin)
|
||||
|
||||
if(previewJob)
|
||||
if(previewJob && equip_job)
|
||||
mannequin.job = previewJob.title
|
||||
previewJob.equip(mannequin, TRUE, preference_source = parent)
|
||||
|
||||
|
||||
@@ -43,6 +43,18 @@
|
||||
name = "Knee-High - UK"
|
||||
icon_state = "uk_knee"
|
||||
|
||||
/datum/sprite_accessory/underwear/socks/christmas_knee
|
||||
name = "Knee-High - Christmas"
|
||||
icon_state = "christmas_knee"
|
||||
|
||||
/datum/sprite_accessory/underwear/socks/candycaner_knee
|
||||
name = "Knee-High - Red Candy Cane"
|
||||
icon_state = "candycaner_knee"
|
||||
|
||||
/datum/sprite_accessory/underwear/socks/candycaneg_knee
|
||||
name = "Knee-High - Green Candy Cane"
|
||||
icon_state = "candycaneg_knee"
|
||||
|
||||
/datum/sprite_accessory/underwear/socks/socks_norm
|
||||
name = "Normal"
|
||||
icon_state = "socks_norm"
|
||||
@@ -52,6 +64,18 @@
|
||||
name = "Normal - Bee"
|
||||
icon_state = "bee_norm"
|
||||
|
||||
/datum/sprite_accessory/underwear/socks/christmas_norm
|
||||
name = "Normal - Christmas"
|
||||
icon_state = "christmas_norm"
|
||||
|
||||
/datum/sprite_accessory/underwear/socks/candycaner_norm
|
||||
name = "Normal - Red Candy Cane"
|
||||
icon_state = "candycaner_norm"
|
||||
|
||||
/datum/sprite_accessory/underwear/socks/candycaneg_norm
|
||||
name = "Normal - Green Candy Cane"
|
||||
icon_state = "candycaneg_norm"
|
||||
|
||||
/datum/sprite_accessory/underwear/socks/pantyhose
|
||||
name = "Pantyhose"
|
||||
icon_state = "pantyhose"
|
||||
@@ -131,3 +155,15 @@
|
||||
/datum/sprite_accessory/underwear/socks/uk_thigh
|
||||
name = "Thigh-high - UK"
|
||||
icon_state = "uk_thigh"
|
||||
|
||||
/datum/sprite_accessory/underwear/socks/christmas_thigh
|
||||
name = "Thigh-high - Christmas"
|
||||
icon_state = "christmas_thigh"
|
||||
|
||||
/datum/sprite_accessory/underwear/socks/candycaner_thigh
|
||||
name = "Thigh-high - Red Candy Cane"
|
||||
icon_state = "candycaner_thigh"
|
||||
|
||||
/datum/sprite_accessory/underwear/socks/candycaneg_thigh
|
||||
name = "Thigh-high - Green Candy Cane"
|
||||
icon_state = "candycaneg_thigh"
|
||||
@@ -265,7 +265,7 @@ Works together with spawning an observer, noted above.
|
||||
|
||||
/mob/proc/ghostize(can_reenter_corpse = TRUE, special = FALSE, penalize = FALSE)
|
||||
penalize = suiciding || penalize // suicide squad.
|
||||
if(!key || cmptext(copytext(key,1,2),"@") || (!special && SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, can_reenter_corpse) & COMPONENT_BLOCK_GHOSTING))
|
||||
if(!key || cmptext(copytext(key,1,2),"@") || (SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, can_reenter_corpse, special, penalize) & COMPONENT_BLOCK_GHOSTING))
|
||||
return //mob has no key, is an aghost or some component hijacked.
|
||||
stop_sound_channel(CHANNEL_HEARTBEAT) //Stop heartbeat sounds because You Are A Ghost Now
|
||||
var/mob/dead/observer/ghost = new(src) // Transfer safety to observer spawning proc.
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
. = say_dead(message)
|
||||
|
||||
/mob/dead/observer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
/mob/dead/observer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
|
||||
. = ..()
|
||||
var/atom/movable/to_follow = speaker
|
||||
if(radio_freq)
|
||||
@@ -35,6 +35,6 @@
|
||||
to_follow = V.source
|
||||
var/link = FOLLOW_LINK(src, to_follow)
|
||||
// Recompose the message, because it's scrambled by default
|
||||
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
|
||||
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source)
|
||||
to_chat(src, "[link] [message]")
|
||||
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
if(bleed_rate <= 0)
|
||||
bleed_rate = 0
|
||||
|
||||
if(HAS_TRAIT(src, TRAIT_NOMARROW)) //Bloodsuckers don't need to be here.
|
||||
return
|
||||
|
||||
if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_NOCLONE))) //cryosleep or husked people do not pump the blood.
|
||||
|
||||
//Blood regeneration if there is some space
|
||||
|
||||
@@ -125,6 +125,7 @@
|
||||
else if(!brain)
|
||||
brain = new(src)
|
||||
brain.name = "[L.real_name]'s brain"
|
||||
brain.organ_flags |= ORGAN_FROZEN
|
||||
|
||||
name = "Man-Machine Interface: [brainmob.real_name]"
|
||||
update_icon()
|
||||
|
||||
@@ -355,30 +355,30 @@
|
||||
if (damage == 1)
|
||||
to_chat(src, "<span class='warning'>Your eyes sting a little.</span>")
|
||||
if(prob(40))
|
||||
adjust_eye_damage(1)
|
||||
eyes.applyOrganDamage(1)
|
||||
|
||||
else if (damage == 2)
|
||||
to_chat(src, "<span class='warning'>Your eyes burn.</span>")
|
||||
adjust_eye_damage(rand(2, 4))
|
||||
eyes.applyOrganDamage(rand(2, 4))
|
||||
|
||||
else if( damage >= 3)
|
||||
to_chat(src, "<span class='warning'>Your eyes itch and burn severely!</span>")
|
||||
adjust_eye_damage(rand(12, 16))
|
||||
eyes.applyOrganDamage(rand(12, 16))
|
||||
|
||||
if(eyes.eye_damage > 10)
|
||||
if(eyes.damage > 10)
|
||||
blind_eyes(damage)
|
||||
blur_eyes(damage * rand(3, 6))
|
||||
|
||||
if(eyes.eye_damage > 20)
|
||||
if(prob(eyes.eye_damage - 20))
|
||||
if(eyes.damage > 20)
|
||||
if(prob(eyes.damage - 20))
|
||||
if(!HAS_TRAIT(src, TRAIT_NEARSIGHT))
|
||||
to_chat(src, "<span class='warning'>Your eyes start to burn badly!</span>")
|
||||
become_nearsighted(EYE_DAMAGE)
|
||||
|
||||
else if(prob(eyes.eye_damage - 25))
|
||||
else if(prob(eyes.damage - 25))
|
||||
if(!HAS_TRAIT(src, TRAIT_BLIND))
|
||||
to_chat(src, "<span class='warning'>You can't see anything!</span>")
|
||||
become_blind(EYE_DAMAGE)
|
||||
eyes.applyOrganDamage(eyes.maxHealth)
|
||||
|
||||
else
|
||||
to_chat(src, "<span class='warning'>Your eyes are really starting to hurt. This can't be good for you!</span>")
|
||||
|
||||
@@ -65,6 +65,8 @@
|
||||
|
||||
|
||||
/mob/living/carbon/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE)
|
||||
if (!forced && amount < 0 && HAS_TRAIT(src,TRAIT_NONATURALHEAL))
|
||||
return FALSE
|
||||
if(!forced && (status_flags & GODMODE))
|
||||
return FALSE
|
||||
if(amount > 0)
|
||||
@@ -74,6 +76,8 @@
|
||||
return amount
|
||||
|
||||
/mob/living/carbon/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE)
|
||||
if (!forced && amount < 0 && HAS_TRAIT(src,TRAIT_NONATURALHEAL)) //Vamps don't heal naturally.
|
||||
return FALSE
|
||||
if(!forced && (status_flags & GODMODE))
|
||||
return FALSE
|
||||
if(amount > 0)
|
||||
|
||||
@@ -17,6 +17,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
|
||||
|
||||
/mob/living/carbon/human/dummy/proc/wipe_state()
|
||||
delete_equipment()
|
||||
icon_render_key = null
|
||||
cut_overlays(TRUE)
|
||||
|
||||
//Inefficient pooling/caching way.
|
||||
|
||||
@@ -15,6 +15,13 @@
|
||||
|
||||
. = list("<span class='info'>*---------*\nThis is <EM>[!obscure_name ? name : "Unknown"]</EM>!")
|
||||
|
||||
var/vampDesc = ReturnVampExamine(user) // Vamps recognize the names of other vamps.
|
||||
var/vassDesc = ReturnVassalExamine(user) // Vassals recognize each other's marks.
|
||||
if (vampDesc != "") // If we don't do it this way, we add a blank space to the string...something to do with this --> . += ""
|
||||
. += vampDesc
|
||||
if (vassDesc != "")
|
||||
. += vassDesc
|
||||
|
||||
var/list/obscured = check_obscured_slots()
|
||||
var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))
|
||||
|
||||
@@ -237,13 +244,13 @@
|
||||
if(DISGUST_LEVEL_DISGUSTED to INFINITY)
|
||||
msg += "[t_He] look[p_s()] extremely disgusted.\n"
|
||||
|
||||
if(blood_volume < (BLOOD_VOLUME_SAFE*blood_ratio))
|
||||
if(ShowAsPaleExamine())
|
||||
msg += "[t_He] [t_has] pale skin.\n"
|
||||
|
||||
if(bleedsuppress)
|
||||
msg += "[t_He] [t_is] bandaged with something.\n"
|
||||
else if(bleed_rate)
|
||||
if(reagents.has_reagent("heparin"))
|
||||
if(bleed_rate >= 8) //8 is the rate at which heparin causes you to bleed
|
||||
msg += "<b>[t_He] [t_is] bleeding uncontrollably!</b>\n"
|
||||
else
|
||||
msg += "<B>[t_He] [t_is] bleeding!</B>\n"
|
||||
|
||||
@@ -858,6 +858,7 @@
|
||||
.["Make slime"] = "?_src_=vars;[HrefToken()];makeslime=[REF(src)]"
|
||||
.["Toggle Purrbation"] = "?_src_=vars;[HrefToken()];purrbation=[REF(src)]"
|
||||
.["Copy outfit"] = "?_src_=vars;[HrefToken()];copyoutfit=[REF(src)]"
|
||||
.["Add/Remove Quirks"] = "?_src_=vars;[HrefToken()];modquirks=[REF(src)]"
|
||||
|
||||
/mob/living/carbon/human/MouseDrop_T(mob/living/target, mob/living/user)
|
||||
if(pulling == target && grab_state >= GRAB_AGGRESSIVE && stat == CONSCIOUS)
|
||||
@@ -867,8 +868,9 @@
|
||||
return
|
||||
//If you dragged them to you and you're aggressively grabbing try to fireman carry them
|
||||
else if(user != target)
|
||||
fireman_carry(target)
|
||||
return
|
||||
if(user.a_intent == INTENT_GRAB)
|
||||
fireman_carry(target)
|
||||
return
|
||||
. = ..()
|
||||
|
||||
//src is the user that will be carrying, target is the mob to be carried
|
||||
@@ -890,7 +892,10 @@
|
||||
return
|
||||
visible_message("<span class='warning'>[src] fails to fireman carry [target]!")
|
||||
else
|
||||
to_chat(src, "<span class='notice'>You can't fireman carry [target] while they're standing!</span>")
|
||||
if (ishuman(target))
|
||||
to_chat(src, "<span class='notice'>You can't fireman carry [target] while they're standing!</span>")
|
||||
else
|
||||
to_chat(src, "<span class='notice'>You can't seem to fireman carry that kind of species.</span>")
|
||||
|
||||
/mob/living/carbon/human/proc/piggyback(mob/living/carbon/target)
|
||||
if(can_piggyback(target))
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
if(!d_type)
|
||||
return 0
|
||||
var/protection = 0
|
||||
var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform, back, gloves, shoes, belt, s_store, glasses, ears, wear_id) //Everything but pockets. Pockets are l_store and r_store. (if pockets were allowed, putting something armored, gloves or hats for example, would double up on the armor)
|
||||
var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform, back, gloves, shoes, belt, s_store, glasses, ears, wear_id, wear_neck) //Everything but pockets. Pockets are l_store and r_store. (if pockets were allowed, putting something armored, gloves or hats for example, would double up on the armor)
|
||||
for(var/bp in body_parts)
|
||||
if(!bp)
|
||||
continue
|
||||
@@ -116,6 +116,10 @@
|
||||
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, AM, attack_text, final_block_chance, damage, attack_type))
|
||||
return 1
|
||||
if(wear_neck)
|
||||
var/final_block_chance = wear_neck.block_chance - (CLAMP((armour_penetration-wear_neck.armour_penetration)/2,0,100)) + block_chance_modifier
|
||||
if(wear_neck.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/human/proc/check_block()
|
||||
@@ -388,43 +392,34 @@
|
||||
return
|
||||
var/b_loss = 0
|
||||
var/f_loss = 0
|
||||
var/bomb_armor = getarmor(null, "bomb")
|
||||
var/bomb_armor = max(0,(100-getarmor(null, "bomb"))/100)
|
||||
|
||||
switch (severity)
|
||||
if (1)
|
||||
if(prob(bomb_armor))
|
||||
b_loss = 500
|
||||
if(bomb_armor)
|
||||
b_loss = 500*bomb_armor
|
||||
var/atom/throw_target = get_edge_target_turf(src, get_dir(src, get_step_away(src, src)))
|
||||
throw_at(throw_target, 200, 4)
|
||||
damage_clothes(400 - bomb_armor, BRUTE, "bomb")
|
||||
damage_clothes(400*bomb_armor, BRUTE, "bomb")
|
||||
else
|
||||
for(var/I in contents)
|
||||
var/atom/A = I
|
||||
A.ex_act(severity)
|
||||
damage_clothes(400,BRUTE,"bomb")
|
||||
gib()
|
||||
return
|
||||
|
||||
if (2)
|
||||
b_loss = 60
|
||||
f_loss = 60
|
||||
if(bomb_armor)
|
||||
b_loss = 30*(2 - round(bomb_armor*0.01, 0.05))
|
||||
f_loss = b_loss
|
||||
damage_clothes(200 - bomb_armor, BRUTE, "bomb")
|
||||
b_loss = 60*bomb_armor
|
||||
f_loss = 60*bomb_armor
|
||||
damage_clothes(200*bomb_armor, BRUTE, "bomb")
|
||||
if (!istype(ears, /obj/item/clothing/ears/earmuffs))
|
||||
adjustEarDamage(30, 120)
|
||||
if (prob(max(70 - (bomb_armor * 0.5), 0)))
|
||||
Unconscious(200)
|
||||
Unconscious(200*bomb_armor)
|
||||
|
||||
if(3)
|
||||
b_loss = 30
|
||||
if(bomb_armor)
|
||||
b_loss = 15*(2 - round(bomb_armor*0.01, 0.05))
|
||||
b_loss = 30*bomb_armor
|
||||
damage_clothes(max(50 - bomb_armor, 0), BRUTE, "bomb")
|
||||
if (!istype(ears, /obj/item/clothing/ears/earmuffs))
|
||||
adjustEarDamage(15,60)
|
||||
if (prob(max(50 - (bomb_armor * 0.5), 0)))
|
||||
Unconscious(160)
|
||||
Unconscious(100*bomb_armor)
|
||||
|
||||
take_overall_damage(b_loss,f_loss)
|
||||
|
||||
|
||||
@@ -119,16 +119,12 @@
|
||||
. = ..()
|
||||
|
||||
if(G.trigger_guard == TRIGGER_GUARD_NORMAL)
|
||||
if(src.dna.check_mutation(HULK))
|
||||
if(HAS_TRAIT(src, TRAIT_CHUNKYFINGERS))
|
||||
to_chat(src, "<span class='warning'>Your meaty finger is much too large for the trigger guard!</span>")
|
||||
return FALSE
|
||||
if(HAS_TRAIT(src, TRAIT_NOGUNS))
|
||||
to_chat(src, "<span class='warning'>Your fingers don't fit in the trigger guard!</span>")
|
||||
return FALSE
|
||||
if(mind)
|
||||
if(mind.martial_art && mind.martial_art.no_guns) //great dishonor to famiry
|
||||
to_chat(src, "<span class='warning'>Use of ranged weaponry would bring dishonor to the clan.</span>")
|
||||
return FALSE
|
||||
|
||||
return .
|
||||
/*
|
||||
|
||||
@@ -191,7 +191,6 @@
|
||||
if(G.vision_correction)
|
||||
if(HAS_TRAIT(src, TRAIT_NEARSIGHT))
|
||||
overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1)
|
||||
adjust_eye_damage(0)
|
||||
if(G.vision_flags || G.darkness_view || G.invis_override || G.invis_view || !isnull(G.lighting_alpha))
|
||||
update_sight()
|
||||
if(!QDELETED(src))
|
||||
|
||||
@@ -252,7 +252,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
QDEL_NULL(eyes)
|
||||
if(should_have_eyes && !eyes)
|
||||
eyes = new mutanteyes
|
||||
eyes.Insert(C)
|
||||
eyes.Insert(C, TRUE)
|
||||
|
||||
if(ears && (replace_current || !should_have_ears))
|
||||
ears.Remove(C,1)
|
||||
@@ -1279,6 +1279,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
////////
|
||||
|
||||
/datum/species/proc/handle_digestion(mob/living/carbon/human/H)
|
||||
if(HAS_TRAIT(src, TRAIT_NOHUNGER))
|
||||
return //hunger is for BABIES
|
||||
|
||||
//The fucking TRAIT_FAT mutation is the dumbest shit ever. It makes the code so difficult to work with
|
||||
if(HAS_TRAIT(H, TRAIT_FAT))//I share your pain, past coder.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
say_mod = "gibbers"
|
||||
sexes = FALSE
|
||||
species_traits = list(NOBLOOD,NOEYES,NOGENITALS,NOAROUSAL)
|
||||
inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NOGUNS,TRAIT_NOHUNGER,TRAIT_NOBREATH)
|
||||
inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_CHUNKYFINGERS,TRAIT_NOHUNGER,TRAIT_NOBREATH)
|
||||
mutanttongue = /obj/item/organ/tongue/abductor
|
||||
|
||||
/datum/species/abductor/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
name = "Golem"
|
||||
id = "iron golem"
|
||||
species_traits = list(NOBLOOD,MUTCOLORS,NO_UNDERWEAR,NOGENITALS,NOAROUSAL)
|
||||
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOFIRE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER)
|
||||
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOFIRE,TRAIT_CHUNKYFINGERS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER)
|
||||
inherent_biotypes = list(MOB_INORGANIC, MOB_HUMANOID)
|
||||
mutant_organs = list(/obj/item/organ/adamantine_resonator)
|
||||
speedmod = 2
|
||||
@@ -88,7 +88,7 @@
|
||||
fixed_mut_color = "a3d"
|
||||
meat = /obj/item/stack/ore/plasma
|
||||
//Can burn and takes damage from heat
|
||||
inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER) //no RESISTHEAT, NOFIRE
|
||||
inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_CHUNKYFINGERS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER) //no RESISTHEAT, NOFIRE
|
||||
info_text = "As a <span class='danger'>Plasma Golem</span>, you burn easily. Be careful, if you get hot enough while burning, you'll blow up!"
|
||||
heatmod = 0 //fine until they blow up
|
||||
prefix = "Plasma"
|
||||
@@ -266,7 +266,7 @@
|
||||
fixed_mut_color = "9E704B"
|
||||
meat = /obj/item/stack/sheet/mineral/wood
|
||||
//Can burn and take damage from heat
|
||||
inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER)
|
||||
inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_CHUNKYFINGERS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER)
|
||||
armor = 30
|
||||
burnmod = 1.25
|
||||
heatmod = 1.5
|
||||
@@ -693,7 +693,7 @@
|
||||
info_text = "As a <span class='danger'>Cloth Golem</span>, you are able to reform yourself after death, provided your remains aren't burned or destroyed. You are, of course, very flammable. \
|
||||
Being made of cloth, your body is magic resistant and faster than that of other golems, but weaker and less resilient."
|
||||
species_traits = list(NOBLOOD,NO_UNDERWEAR,NOGENITALS,NOAROUSAL) //no mutcolors, and can burn
|
||||
inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_NOBREATH,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOGUNS)
|
||||
inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_NOBREATH,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_CHUNKYFINGERS)
|
||||
inherent_biotypes = list(MOB_UNDEAD, MOB_HUMANOID)
|
||||
armor = 15 //feels no pain, but not too resistant
|
||||
burnmod = 2 // don't get burned
|
||||
@@ -893,7 +893,7 @@
|
||||
special_names = list("Box")
|
||||
info_text = "As a <span class='danger'>Cardboard Golem</span>, you aren't very strong, but you are a bit quicker and can easily create more brethren by using cardboard on yourself."
|
||||
species_traits = list(NOBLOOD,NO_UNDERWEAR,NOGENITALS,NOAROUSAL,MUTCOLORS)
|
||||
inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER)
|
||||
inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_CHUNKYFINGERS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER)
|
||||
fixed_mut_color = "ffffff"
|
||||
limbs_id = "c_golem" //special sprites
|
||||
attack_verb = "bash"
|
||||
@@ -936,7 +936,7 @@
|
||||
name = "Leather Golem"
|
||||
id = "leather golem"
|
||||
special_names = list("Face", "Man", "Belt") //Ah dude 4 strength 4 stam leather belt AHHH
|
||||
inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER, TRAIT_STRONG_GRABBER)
|
||||
inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_CHUNKYFINGERS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER, TRAIT_STRONG_GRABBER)
|
||||
prefix = "Leather"
|
||||
fixed_mut_color = "624a2e"
|
||||
info_text = "As a <span class='danger'>Leather Golem</span>, you are flammable, but you can grab things with incredible ease, allowing all your grabs to start at a strong level."
|
||||
@@ -952,7 +952,7 @@
|
||||
special_names = list("Boll","Weave")
|
||||
species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYES)
|
||||
fixed_mut_color = null
|
||||
inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER)
|
||||
inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_CHUNKYFINGERS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER)
|
||||
info_text = "As a <span class='danger'>Durathread Golem</span>, your strikes will cause those your targets to start choking, but your woven body won't withstand fire as well."
|
||||
|
||||
/datum/species/golem/durathread/spec_unarmedattacked(mob/living/carbon/human/user, mob/living/carbon/human/target)
|
||||
@@ -974,7 +974,7 @@
|
||||
fixed_mut_color = "ffffff"
|
||||
attack_verb = "rattl"
|
||||
species_traits = list(NOBLOOD,NO_UNDERWEAR,NOGENITALS,NOAROUSAL,MUTCOLORS)
|
||||
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOFIRE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_FAKEDEATH,TRAIT_CALCIUM_HEALER)
|
||||
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOFIRE,TRAIT_CHUNKYFINGERS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_FAKEDEATH,TRAIT_CALCIUM_HEALER)
|
||||
info_text = "As a <span class='danger'>Bone Golem</span>, You have a powerful spell that lets you chill your enemies with fear, and milk heals you! Just make sure to watch our for bone-hurting juice."
|
||||
var/datum/action/innate/bonechill/bonechill
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
C.faction |= "slime"
|
||||
|
||||
/datum/species/jelly/spec_life(mob/living/carbon/human/H)
|
||||
if(H.stat == DEAD) //can't farm slime jelly from a dead slime/jelly person indefinitely
|
||||
if(H.stat == DEAD || HAS_TRAIT(H, TRAIT_NOMARROW)) //can't farm slime jelly from a dead slime/jelly person indefinitely, and no regeneration for vampires
|
||||
return
|
||||
if(!H.blood_volume)
|
||||
H.blood_volume += 5
|
||||
@@ -116,6 +116,33 @@
|
||||
return
|
||||
to_chat(H, "<span class='warning'>...but there is not enough of you to go around! You must attain more mass to heal!</span>")
|
||||
|
||||
/datum/species/jelly/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
|
||||
/datum/species/jelly/spec_stun(mob/living/carbon/human/H,amount)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
. = ..()
|
||||
|
||||
/datum/species/jelly/can_wag_tail(mob/living/carbon/human/H)
|
||||
return ("mam_tail" in mutant_bodyparts) || ("mam_waggingtail" in mutant_bodyparts)
|
||||
|
||||
/datum/species/jelly/is_wagging_tail(mob/living/carbon/human/H)
|
||||
return ("mam_waggingtail" in mutant_bodyparts)
|
||||
|
||||
/datum/species/jelly/start_wagging_tail(mob/living/carbon/human/H)
|
||||
if("mam_tail" in mutant_bodyparts)
|
||||
mutant_bodyparts -= "mam_tail"
|
||||
mutant_bodyparts |= "mam_waggingtail"
|
||||
H.update_body()
|
||||
|
||||
/datum/species/jelly/stop_wagging_tail(mob/living/carbon/human/H)
|
||||
if("mam_waggingtail" in mutant_bodyparts)
|
||||
mutant_bodyparts -= "mam_waggingtail"
|
||||
mutant_bodyparts |= "mam_tail"
|
||||
H.update_body()
|
||||
|
||||
////////////////////////////////////////////////////////SLIMEPEOPLE///////////////////////////////////////////////////////////////////
|
||||
|
||||
//Slime people are able to split like slimes, retaining a single mind that can swap between bodies at will, even after death.
|
||||
@@ -177,6 +204,8 @@
|
||||
bodies = old_species.bodies
|
||||
|
||||
/datum/species/jelly/slime/spec_life(mob/living/carbon/human/H)
|
||||
if((HAS_TRAIT(H, TRAIT_NOMARROW)))
|
||||
return
|
||||
if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
|
||||
if(prob(5))
|
||||
to_chat(H, "<span class='notice'>You feel very bloated!</span>")
|
||||
@@ -410,34 +439,6 @@
|
||||
heatmod = 1
|
||||
burnmod = 1
|
||||
|
||||
/datum/species/jelly/roundstartslime/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
|
||||
/datum/species/jelly/roundstartslime/spec_stun(mob/living/carbon/human/H,amount)
|
||||
if(H)
|
||||
stop_wagging_tail(H)
|
||||
. = ..()
|
||||
|
||||
/datum/species/jelly/roundstartslime/can_wag_tail(mob/living/carbon/human/H)
|
||||
return ("mam_tail" in mutant_bodyparts) || ("mam_waggingtail" in mutant_bodyparts)
|
||||
|
||||
/datum/species/jelly/roundstartslime/is_wagging_tail(mob/living/carbon/human/H)
|
||||
return ("mam_waggingtail" in mutant_bodyparts)
|
||||
|
||||
/datum/species/jelly/roundstartslime/start_wagging_tail(mob/living/carbon/human/H)
|
||||
if("mam_tail" in mutant_bodyparts)
|
||||
mutant_bodyparts -= "mam_tail"
|
||||
mutant_bodyparts |= "mam_waggingtail"
|
||||
H.update_body()
|
||||
|
||||
/datum/species/jelly/roundstartslime/stop_wagging_tail(mob/living/carbon/human/H)
|
||||
if("mam_waggingtail" in mutant_bodyparts)
|
||||
mutant_bodyparts -= "mam_waggingtail"
|
||||
mutant_bodyparts |= "mam_tail"
|
||||
H.update_body()
|
||||
|
||||
|
||||
/datum/action/innate/slime_change
|
||||
name = "Alter Form"
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
@@ -838,19 +839,16 @@
|
||||
link_minds = new(src)
|
||||
link_minds.Grant(C)
|
||||
slimelink_owner = C
|
||||
link_mob(C)
|
||||
link_mob(C, TRUE)
|
||||
|
||||
/datum/species/jelly/stargazer/proc/link_mob(mob/living/M)
|
||||
if(QDELETED(M) || M.stat == DEAD)
|
||||
/datum/species/jelly/stargazer/proc/link_mob(mob/living/M, selflink = FALSE)
|
||||
if(QDELETED(M) || (M in linked_mobs))
|
||||
return FALSE
|
||||
if(HAS_TRAIT(M, TRAIT_MINDSHIELD)) //mindshield implant, no dice
|
||||
return FALSE
|
||||
if(M.anti_magic_check(FALSE, FALSE, TRUE, 0))
|
||||
return FALSE
|
||||
if(M in linked_mobs)
|
||||
if(!selflink && (M.stat == DEAD || HAS_TRAIT(M, TRAIT_MINDSHIELD) || M.anti_magic_check(FALSE, FALSE, TRUE, 0)))
|
||||
return FALSE
|
||||
linked_mobs.Add(M)
|
||||
to_chat(M, "<span class='notice'>You are now connected to [slimelink_owner.real_name]'s Slime Link.</span>")
|
||||
if(!selflink)
|
||||
to_chat(M, "<span class='notice'>You are now connected to [slimelink_owner.real_name]'s Slime Link.</span>")
|
||||
var/datum/action/innate/linked_speech/action = new(src)
|
||||
linked_actions.Add(action)
|
||||
action.Grant(M)
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
id = "ashlizard"
|
||||
limbs_id = "lizard"
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE)
|
||||
inherent_traits = list(TRAIT_NOGUNS)
|
||||
inherent_traits = list(TRAIT_CHUNKYFINGERS)
|
||||
mutantlungs = /obj/item/organ/lungs/ashwalker
|
||||
burnmod = 0.9
|
||||
brutemod = 0.9
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
blacklisted = TRUE
|
||||
no_equip = list(SLOT_WEAR_MASK, SLOT_WEAR_SUIT, SLOT_GLOVES, SLOT_SHOES, SLOT_W_UNIFORM, SLOT_S_STORE)
|
||||
species_traits = list(NOBLOOD,NO_UNDERWEAR,NO_DNA_COPY,NOTRANSSTING,NOEYES,NOGENITALS,NOAROUSAL)
|
||||
inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_NOBREATH,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER)
|
||||
inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_NOBREATH,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_CHUNKYFINGERS,TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER)
|
||||
mutanteyes = /obj/item/organ/eyes/night_vision/nightmare
|
||||
mutant_organs = list(/obj/item/organ/heart/nightmare)
|
||||
mutant_brain = /obj/item/organ/brain/nightmare
|
||||
|
||||
@@ -659,6 +659,9 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put
|
||||
|
||||
//used in human and monkey handle_environment()
|
||||
/mob/living/carbon/proc/natural_bodytemperature_stabilization()
|
||||
if (HAS_TRAIT(src, TRAIT_COLDBLOODED))
|
||||
return 0 //Return 0 as your natural temperature. Species proc handle_environment() will adjust your temperature based on this.
|
||||
|
||||
var/body_temperature_difference = BODYTEMP_NORMAL - bodytemperature
|
||||
switch(bodytemperature)
|
||||
if(-INFINITY to BODYTEMP_COLD_DAMAGE_LIMIT) //Cold damage limit is 50 below the default, the temperature where you start to feel effects.
|
||||
|
||||
@@ -2,44 +2,6 @@
|
||||
//The effects include: stun, knockdown, unconscious, sleeping, resting, jitteriness, dizziness, ear damage,
|
||||
// eye damage, eye_blind, eye_blurry, druggy, TRAIT_BLIND trait, TRAIT_NEARSIGHT trait, and TRAIT_HUSK trait.
|
||||
|
||||
/mob/living/carbon/damage_eyes(amount)
|
||||
var/obj/item/organ/eyes/eyes = getorganslot(ORGAN_SLOT_EYES)
|
||||
if (!eyes)
|
||||
return
|
||||
if(amount>0)
|
||||
eyes.eye_damage = amount
|
||||
if(eyes.eye_damage > 20)
|
||||
if(eyes.eye_damage > 30)
|
||||
overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 2)
|
||||
else
|
||||
overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 1)
|
||||
|
||||
/mob/living/carbon/set_eye_damage(amount)
|
||||
var/obj/item/organ/eyes/eyes = getorganslot(ORGAN_SLOT_EYES)
|
||||
if (!eyes)
|
||||
return
|
||||
eyes.eye_damage = max(amount,0)
|
||||
if(eyes.eye_damage > 20)
|
||||
if(eyes.eye_damage > 30)
|
||||
overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 2)
|
||||
else
|
||||
overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 1)
|
||||
else
|
||||
clear_fullscreen("eye_damage")
|
||||
|
||||
/mob/living/carbon/adjust_eye_damage(amount)
|
||||
var/obj/item/organ/eyes/eyes = getorganslot(ORGAN_SLOT_EYES)
|
||||
if (!eyes)
|
||||
return
|
||||
eyes.eye_damage = max(eyes.eye_damage+amount, 0)
|
||||
if(eyes.eye_damage > 20)
|
||||
if(eyes.eye_damage > 30)
|
||||
overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 2)
|
||||
else
|
||||
overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 1)
|
||||
else
|
||||
clear_fullscreen("eye_damage")
|
||||
|
||||
/mob/living/carbon/adjust_drugginess(amount)
|
||||
druggy = max(druggy+amount, 0)
|
||||
if(druggy)
|
||||
|
||||
@@ -62,12 +62,8 @@
|
||||
unset_machine()
|
||||
timeofdeath = world.time
|
||||
tod = STATION_TIME_TIMESTAMP("hh:mm:ss")
|
||||
var/turf/T = get_turf(src)
|
||||
for(var/obj/item/I in contents)
|
||||
I.on_mob_death(src, gibbed)
|
||||
if(mind && mind.name && mind.active && !istype(T.loc, /area/ctf))
|
||||
var/rendered = "<span class='deadsay'><b>[mind.name]</b> has died at <b>[get_area_name(T)]</b>.</span>"
|
||||
deadchat_broadcast(rendered, follow_target = src, turf_target = T, message_type=DEADCHAT_DEATHRATTLE)
|
||||
if(mind)
|
||||
mind.store_memory("Time of death: [tod]", 0)
|
||||
GLOB.alive_mob_list -= src
|
||||
@@ -89,7 +85,12 @@
|
||||
addtimer(CALLBACK(src, .proc/med_hud_set_status), (DEFIB_TIME_LIMIT * 10) + 1)
|
||||
stop_pulling()
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_MOB_DEATH, gibbed)
|
||||
var/signal = SEND_SIGNAL(src, COMSIG_MOB_DEATH, gibbed)
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
if(mind && mind.name && mind.active && !istype(T.loc, /area/ctf) && !(signal & COMPONENT_BLOCK_DEATH_BROADCAST))
|
||||
var/rendered = "<span class='deadsay'><b>[mind.name]</b> has died at <b>[get_area_name(T)]</b>.</span>"
|
||||
deadchat_broadcast(rendered, follow_target = src, turf_target = T, message_type=DEADCHAT_DEATHRATTLE)
|
||||
|
||||
if (client)
|
||||
client.move_delay = initial(client.move_delay)
|
||||
|
||||
@@ -87,6 +87,12 @@
|
||||
message_simple = S.deathmessage
|
||||
. = ..()
|
||||
message_simple = initial(message_simple)
|
||||
if(. && user.deathsound)
|
||||
if(isliving(user))
|
||||
var/mob/living/L = user
|
||||
if(!L.can_speak_vocal() || L.oxyloss >= 50)
|
||||
return //stop the sound if oxyloss too high/cant speak
|
||||
playsound(user, user.deathsound, 200, TRUE, TRUE)
|
||||
if(. && isalienadult(user))
|
||||
playsound(user.loc, 'sound/voice/hiss6.ogg', 80, 1, 1)
|
||||
|
||||
|
||||
@@ -502,7 +502,6 @@
|
||||
bodytemperature = BODYTEMP_NORMAL
|
||||
set_blindness(0)
|
||||
set_blurriness(0)
|
||||
set_eye_damage(0)
|
||||
cure_nearsighted()
|
||||
cure_blind()
|
||||
cure_husk()
|
||||
@@ -1221,7 +1220,8 @@
|
||||
if("eye_blind")
|
||||
set_blindness(var_value)
|
||||
if("eye_damage")
|
||||
set_eye_damage(var_value)
|
||||
var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
|
||||
E?.setOrganDamage(var_value)
|
||||
if("eye_blurry")
|
||||
set_blurriness(var_value)
|
||||
if("maxHealth")
|
||||
|
||||
@@ -212,11 +212,11 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
|
||||
if(succumbed)
|
||||
succumb()
|
||||
to_chat(src, compose_message(src, language, message, , spans, message_mode))
|
||||
to_chat(src, compose_message(src, language, message, null, spans, message_mode))
|
||||
|
||||
return 1
|
||||
|
||||
/mob/living/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
/mob/living/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
|
||||
. = ..()
|
||||
if(!client)
|
||||
return
|
||||
@@ -231,7 +231,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
deaf_type = 2 // Since you should be able to hear yourself without looking
|
||||
|
||||
// Recompose message for AI hrefs, language incomprehension.
|
||||
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
|
||||
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source)
|
||||
|
||||
show_message(message, MSG_AUDIBLE, deaf_message, deaf_type)
|
||||
return message
|
||||
@@ -244,8 +244,8 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
var/list/listening = get_hearers_in_view(message_range+eavesdrop_range, source)
|
||||
var/list/the_dead = list()
|
||||
var/list/yellareas //CIT CHANGE - adds the ability for yelling to penetrate walls and echo throughout areas
|
||||
if(say_test(message) == "2") //CIT CHANGE - ditto
|
||||
yellareas = get_areas_in_range(message_range*0.5,src) //CIT CHANGE - ditto
|
||||
if(!eavesdrop_range && say_test(message) == "2") //CIT CHANGE - ditto
|
||||
yellareas = get_areas_in_range(message_range*0.5, source) //CIT CHANGE - ditto
|
||||
for(var/_M in GLOB.player_list)
|
||||
var/mob/M = _M
|
||||
if(M.stat != DEAD) //not dead, not important
|
||||
@@ -256,7 +256,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
continue
|
||||
if(!M.client || !client) //client is so that ghosts don't have to listen to mice
|
||||
continue
|
||||
if(get_dist(M, src) > 7 || M.z != z) //they're out of range of normal hearing
|
||||
if(get_dist(M, source) > 7 || M.z != z) //they're out of range of normal hearing
|
||||
if(eavesdropping_modes[message_mode] && !(M.client.prefs.chat_toggles & CHAT_GHOSTWHISPER)) //they're whispering and we have hearing whispers at any range off
|
||||
continue
|
||||
if(!(M.client.prefs.chat_toggles & CHAT_GHOSTEARS)) //they're talking normally and we have hearing at any range off
|
||||
@@ -268,15 +268,15 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
var/eavesrendered
|
||||
if(eavesdrop_range)
|
||||
eavesdropping = stars(message)
|
||||
eavesrendered = compose_message(src, message_language, eavesdropping, , spans, message_mode)
|
||||
eavesrendered = compose_message(src, message_language, eavesdropping, null, spans, message_mode, FALSE, source)
|
||||
|
||||
var/rendered = compose_message(src, message_language, message, , spans, message_mode)
|
||||
var/rendered = compose_message(src, message_language, message, null, spans, message_mode, FALSE, source)
|
||||
for(var/_AM in listening)
|
||||
var/atom/movable/AM = _AM
|
||||
if(eavesdrop_range && get_dist(source, AM) > message_range && !(the_dead[AM]))
|
||||
AM.Hear(eavesrendered, src, message_language, eavesdropping, , spans, message_mode)
|
||||
AM.Hear(eavesrendered, src, message_language, eavesdropping, null, spans, message_mode, source)
|
||||
else
|
||||
AM.Hear(rendered, src, message_language, message, , spans, message_mode)
|
||||
AM.Hear(rendered, src, message_language, message, null, spans, message_mode, source)
|
||||
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_LIVING_SAY_SPECIAL, src, message)
|
||||
|
||||
//speech bubble
|
||||
|
||||
@@ -176,13 +176,13 @@
|
||||
fire_stacks = 0
|
||||
. = ..()
|
||||
|
||||
/mob/living/silicon/ai/proc/set_core_display_icon(client/C)
|
||||
/mob/living/silicon/ai/proc/set_core_display_icon(input, client/C)
|
||||
if(client && !C)
|
||||
C = client
|
||||
if(!(C?.prefs?.preferred_ai_core_display))
|
||||
icon_state = display_icon_override || initial(icon_state)
|
||||
if(!input && !C?.prefs?.preferred_ai_core_display)
|
||||
icon_state = initial(icon_state)
|
||||
else
|
||||
var/preferred_icon = display_icon_override || C.prefs.preferred_ai_core_display
|
||||
var/preferred_icon = input ? input : C.prefs.preferred_ai_core_display
|
||||
icon_state = resolve_ai_icon(preferred_icon)
|
||||
|
||||
/mob/living/silicon/ai/verb/pick_icon()
|
||||
@@ -202,8 +202,9 @@
|
||||
|
||||
if(!ai_core_icon || incapacitated())
|
||||
return
|
||||
|
||||
display_icon_override = ai_core_icon
|
||||
set_core_display_icon()
|
||||
set_core_display_icon(ai_core_icon)
|
||||
|
||||
/mob/living/silicon/ai/Stat()
|
||||
..()
|
||||
@@ -600,7 +601,10 @@
|
||||
if(incapacitated())
|
||||
return
|
||||
var/list/ai_emotions = list("Very Happy", "Happy", "Neutral", "Unsure", "Confused", "Sad", "BSOD", "Blank", "Problems?", "Awesome", "Facepalm", "Thinking", "Friend Computer", "Dorfy", "Blue Glow", "Red Glow")
|
||||
emote_display = input("Please, select a status!", "AI Status", null, null) in ai_emotions
|
||||
var/n_emote = input("Please, select a status!", "AI Status", null, null) in ai_emotions
|
||||
if(!n_emote)
|
||||
return
|
||||
emote_display = n_emote
|
||||
for (var/each in GLOB.ai_status_displays) //change status of displays
|
||||
var/obj/machinery/status_display/ai/M = each
|
||||
M.emotion = emote_display
|
||||
@@ -887,7 +891,7 @@
|
||||
. = ..()
|
||||
if(.) //successfully ressuscitated from death
|
||||
set_eyeobj_visible(TRUE)
|
||||
set_core_display_icon()
|
||||
set_core_display_icon(display_icon_override)
|
||||
|
||||
/mob/living/silicon/ai/proc/malfhacked(obj/machinery/power/apc/apc)
|
||||
malfhack = null
|
||||
|
||||
@@ -191,7 +191,7 @@
|
||||
acceleration = !acceleration
|
||||
to_chat(usr, "Camera acceleration has been toggled [acceleration ? "on" : "off"].")
|
||||
|
||||
/mob/camera/aiEye/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
/mob/camera/aiEye/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
|
||||
. = ..()
|
||||
if(relay_speech && speaker && ai && !radio_freq && speaker != ai && near_camera(speaker))
|
||||
ai.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
else
|
||||
padloc = "(UNKNOWN)"
|
||||
src.log_talk(message, LOG_SAY, tag="HOLOPAD in [padloc]")
|
||||
send_speech(message, 7, T, "robot", language)
|
||||
send_speech(message, 7, T, "robot", message_language = language)
|
||||
to_chat(src, "<i><span class='game say'>Holopad transmitted, <span class='name'>[real_name]</span> <span class='message robot'>\"[message]\"</span></span></i>")
|
||||
else
|
||||
to_chat(src, "No holopad connected.")
|
||||
|
||||
@@ -4,4 +4,7 @@
|
||||
var/datum/antagonist/rev/rev = mind.has_antag_datum(/datum/antagonist/rev)
|
||||
if(rev)
|
||||
rev.remove_revolutionary(TRUE)
|
||||
var/datum/antagonist/bloodsucker/V = mind.has_antag_datum(/datum/antagonist/bloodsucker)
|
||||
if(V)
|
||||
mind.remove_antag_datum(V)
|
||||
..()
|
||||
|
||||
@@ -112,6 +112,8 @@
|
||||
var/bellyup = 0
|
||||
var/dogborg = FALSE
|
||||
|
||||
var/cansprint = 1
|
||||
|
||||
/mob/living/silicon/robot/get_cell()
|
||||
return cell
|
||||
|
||||
@@ -159,6 +161,7 @@
|
||||
else if(!mmi || !mmi.brainmob)
|
||||
mmi = new (src)
|
||||
mmi.brain = new /obj/item/organ/brain(mmi)
|
||||
mmi.brain.organ_flags |= ORGAN_FROZEN
|
||||
mmi.brain.name = "[real_name]'s brain"
|
||||
mmi.icon_state = "mmi_full"
|
||||
mmi.name = "Man-Machine Interface: [real_name]"
|
||||
@@ -233,7 +236,6 @@
|
||||
var/list/modulelist = list("Standard" = /obj/item/robot_module/standard, \
|
||||
"Engineering" = /obj/item/robot_module/engineering, \
|
||||
"Medical" = /obj/item/robot_module/medical, \
|
||||
"Medihound" = /obj/item/robot_module/medihound, \
|
||||
"Miner" = /obj/item/robot_module/miner, \
|
||||
"Service" = /obj/item/robot_module/butler)
|
||||
if(!CONFIG_GET(flag/disable_peaceborg))
|
||||
@@ -832,7 +834,7 @@
|
||||
robot_suit.head.flash2.burn_out()
|
||||
robot_suit.head.flash2 = null
|
||||
robot_suit.head = null
|
||||
robot_suit.updateicon()
|
||||
robot_suit.update_icon()
|
||||
else
|
||||
new /obj/item/robot_suit(T)
|
||||
new /obj/item/bodypart/l_leg/robot(T)
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
var/moduleselect_icon = "nomod"
|
||||
|
||||
var/can_be_pushed = TRUE
|
||||
var/can_be_pushed = FALSE
|
||||
var/magpulsing = FALSE
|
||||
var/clean_on_move = FALSE
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
|
||||
//Adds flavoursome dogborg items to dogborg variants without mechanical benefits
|
||||
/obj/item/robot_module/proc/dogborg_equip()
|
||||
if(istype(src, /obj/item/robot_module/k9) || istype(src, /obj/item/robot_module/medihound))
|
||||
if(istype(src, /obj/item/robot_module/k9))
|
||||
return //Bandaid fix to prevent stacking until I merge these two modules into their base types
|
||||
var/obj/item/I = new /obj/item/analyzer/nose/flavour(src)
|
||||
basic_modules += I
|
||||
@@ -322,19 +322,21 @@
|
||||
/obj/item/stack/medical/gauze/cyborg,
|
||||
/obj/item/organ_storage,
|
||||
/obj/item/borg/lollipop,
|
||||
/obj/item/sensor_device)
|
||||
/obj/item/sensor_device,
|
||||
/obj/item/twohanded/shockpaddles/cyborg)
|
||||
emag_modules = list(/obj/item/reagent_containers/borghypo/hacked)
|
||||
ratvar_modules = list(
|
||||
/obj/item/clockwork/slab/cyborg/medical,
|
||||
/obj/item/clockwork/weapon/ratvarian_spear)
|
||||
cyborg_base_icon = "medical"
|
||||
moduleselect_icon = "medical"
|
||||
can_be_pushed = FALSE
|
||||
hat_offset = 3
|
||||
|
||||
/obj/item/robot_module/medical/be_transformed_to(obj/item/robot_module/old_module)
|
||||
var/mob/living/silicon/robot/R = loc
|
||||
var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Heavy", "Sleek", "Marina", "Droid", "Eyebot")
|
||||
var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Heavy", "Sleek", "Marina", "Droid", "Eyebot", "Medihound", "Medihound Dark", "Vale")
|
||||
if(R.client && R.client.ckey in list("nezuli"))
|
||||
borg_icon += "Alina"
|
||||
if(!borg_icon)
|
||||
return FALSE
|
||||
switch(borg_icon)
|
||||
@@ -356,59 +358,46 @@
|
||||
if("Heavy")
|
||||
cyborg_base_icon = "heavymed"
|
||||
cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
|
||||
return ..()
|
||||
|
||||
/obj/item/robot_module/medihound
|
||||
name = "MediHound"
|
||||
basic_modules = list(
|
||||
/obj/item/dogborg/jaws/small,
|
||||
/obj/item/storage/bag/borgdelivery,
|
||||
/obj/item/analyzer/nose,
|
||||
/obj/item/soap/tongue,
|
||||
/obj/item/extinguisher/mini,
|
||||
/obj/item/healthanalyzer,
|
||||
/obj/item/dogborg/sleeper/medihound,
|
||||
/obj/item/roller/robo,
|
||||
/obj/item/reagent_containers/borghypo,
|
||||
/obj/item/twohanded/shockpaddles/cyborg/hound,
|
||||
/obj/item/stack/medical/gauze/cyborg,
|
||||
/obj/item/pinpointer/crew,
|
||||
/obj/item/sensor_device)
|
||||
emag_modules = list(/obj/item/dogborg/pounce)
|
||||
ratvar_modules = list(/obj/item/clockwork/slab/cyborg/medical,
|
||||
/obj/item/clockwork/weapon/ratvarian_spear)
|
||||
cyborg_base_icon = "medihound"
|
||||
moduleselect_icon = "medihound"
|
||||
moduleselect_alternate_icon = 'modular_citadel/icons/ui/screen_cyborg.dmi'
|
||||
can_be_pushed = FALSE
|
||||
hat_offset = INFINITY
|
||||
sleeper_overlay = "msleeper"
|
||||
cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
|
||||
has_snowflake_deadsprite = TRUE
|
||||
dogborg = TRUE
|
||||
cyborg_pixel_offset = -16
|
||||
|
||||
/obj/item/robot_module/medihound/be_transformed_to(obj/item/robot_module/old_module)
|
||||
var/mob/living/silicon/robot/R = loc
|
||||
var/list/medhoundmodels = list("Default", "Dark", "Vale")
|
||||
if(R.client && R.client.ckey in list("nezuli"))
|
||||
medhoundmodels += "Alina"
|
||||
var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in medhoundmodels
|
||||
if(!borg_icon)
|
||||
return FALSE
|
||||
switch(borg_icon)
|
||||
if("Default")
|
||||
if("Medihound")
|
||||
cyborg_base_icon = "medihound"
|
||||
if("Dark")
|
||||
cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
|
||||
moduleselect_icon = "medihound"
|
||||
moduleselect_alternate_icon = 'modular_citadel/icons/ui/screen_cyborg.dmi'
|
||||
has_snowflake_deadsprite = TRUE
|
||||
dogborg = TRUE
|
||||
cyborg_pixel_offset = -16
|
||||
hat_offset = INFINITY
|
||||
if("Medihound Dark")
|
||||
cyborg_base_icon = "medihounddark"
|
||||
cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
|
||||
sleeper_overlay = "mdsleeper"
|
||||
moduleselect_icon = "medihound"
|
||||
moduleselect_alternate_icon = 'modular_citadel/icons/ui/screen_cyborg.dmi'
|
||||
has_snowflake_deadsprite = TRUE
|
||||
dogborg = TRUE
|
||||
cyborg_pixel_offset = -16
|
||||
hat_offset = INFINITY
|
||||
if("Vale")
|
||||
cyborg_base_icon = "valemed"
|
||||
cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
|
||||
sleeper_overlay = "valemedsleeper"
|
||||
moduleselect_icon = "medihound"
|
||||
moduleselect_alternate_icon = 'modular_citadel/icons/ui/screen_cyborg.dmi'
|
||||
has_snowflake_deadsprite = TRUE
|
||||
dogborg = TRUE
|
||||
cyborg_pixel_offset = -16
|
||||
hat_offset = INFINITY
|
||||
if("Alina")
|
||||
cyborg_base_icon = "alina-med"
|
||||
cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
|
||||
special_light_key = "alina"
|
||||
sleeper_overlay = "alinasleeper"
|
||||
moduleselect_icon = "medihound"
|
||||
moduleselect_alternate_icon = 'modular_citadel/icons/ui/screen_cyborg.dmi'
|
||||
has_snowflake_deadsprite = TRUE
|
||||
dogborg = TRUE
|
||||
cyborg_pixel_offset = -16
|
||||
hat_offset = INFINITY
|
||||
return ..()
|
||||
|
||||
/obj/item/robot_module/engineering
|
||||
@@ -489,7 +478,6 @@
|
||||
cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
|
||||
if("Pup Dozer")
|
||||
cyborg_base_icon = "pupdozer"
|
||||
can_be_pushed = FALSE
|
||||
hat_offset = INFINITY
|
||||
cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
|
||||
has_snowflake_deadsprite = TRUE
|
||||
@@ -498,7 +486,6 @@
|
||||
sleeper_overlay = "dozersleeper"
|
||||
if("Vale")
|
||||
cyborg_base_icon = "valeeng"
|
||||
can_be_pushed = FALSE
|
||||
hat_offset = INFINITY
|
||||
cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
|
||||
has_snowflake_deadsprite = TRUE
|
||||
@@ -508,7 +495,6 @@
|
||||
if("Alina")
|
||||
cyborg_base_icon = "alina-eng"
|
||||
special_light_key = "alina"
|
||||
can_be_pushed = FALSE
|
||||
hat_offset = INFINITY
|
||||
cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
|
||||
has_snowflake_deadsprite = TRUE
|
||||
@@ -533,7 +519,6 @@
|
||||
/obj/item/clockwork/weapon/ratvarian_spear)
|
||||
cyborg_base_icon = "sec"
|
||||
moduleselect_icon = "security"
|
||||
can_be_pushed = FALSE
|
||||
hat_offset = 3
|
||||
|
||||
/obj/item/robot_module/security/do_transform_animation()
|
||||
@@ -589,7 +574,6 @@
|
||||
cyborg_base_icon = "k9"
|
||||
moduleselect_icon = "k9"
|
||||
moduleselect_alternate_icon = 'modular_citadel/icons/ui/screen_cyborg.dmi'
|
||||
can_be_pushed = FALSE
|
||||
hat_offset = INFINITY
|
||||
sleeper_overlay = "ksleeper"
|
||||
cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
|
||||
@@ -652,7 +636,6 @@
|
||||
/obj/item/clockwork/weapon/ratvarian_spear)
|
||||
cyborg_base_icon = "peace"
|
||||
moduleselect_icon = "standard"
|
||||
can_be_pushed = FALSE
|
||||
hat_offset = -2
|
||||
|
||||
/obj/item/robot_module/peacekeeper/do_transform_animation()
|
||||
@@ -947,7 +930,6 @@
|
||||
/obj/item/clockwork/weapon/ratvarian_spear)
|
||||
cyborg_base_icon = "synd_sec"
|
||||
moduleselect_icon = "malf"
|
||||
can_be_pushed = FALSE
|
||||
hat_offset = 3
|
||||
|
||||
/obj/item/robot_module/syndicate/rebuild_modules()
|
||||
@@ -987,7 +969,6 @@
|
||||
/obj/item/clockwork/weapon/ratvarian_spear)
|
||||
cyborg_base_icon = "synd_medical"
|
||||
moduleselect_icon = "malf"
|
||||
can_be_pushed = FALSE
|
||||
hat_offset = 3
|
||||
|
||||
/obj/item/robot_module/saboteur
|
||||
@@ -1026,7 +1007,6 @@
|
||||
|
||||
cyborg_base_icon = "synd_engi"
|
||||
moduleselect_icon = "malf"
|
||||
can_be_pushed = FALSE
|
||||
magpulsing = TRUE
|
||||
hat_offset = -4
|
||||
canDispose = TRUE
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
mob_biotypes = list(MOB_ROBOTIC)
|
||||
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
|
||||
speech_span = SPAN_ROBOT
|
||||
flags_1 = PREVENT_CONTENTS_EXPLOSION_1
|
||||
flags_1 = PREVENT_CONTENTS_EXPLOSION_1 | HEAR_1
|
||||
no_vore = TRUE
|
||||
|
||||
var/datum/ai_laws/laws = null//Now... THEY ALL CAN ALL HAVE LAWS
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
unsuitable_atmos_damage = 0
|
||||
minbodytemp = 0
|
||||
maxbodytemp = 100000
|
||||
blood_volume = 0
|
||||
|
||||
/mob/living/simple_animal/astral/death()
|
||||
icon_state = "shade_dead"
|
||||
|
||||
@@ -14,6 +14,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)
|
||||
maxbodytemp = INFINITY
|
||||
minbodytemp = 0
|
||||
blood_volume = 0
|
||||
has_unlimited_silicon_privilege = 1
|
||||
sentience_type = SENTIENCE_ARTIFICIAL
|
||||
status_flags = NONE //no default canpush
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
initial_language_holder = /datum/language_holder/construct
|
||||
deathmessage = "collapses in a shattered heap."
|
||||
hud_type = /datum/hud/constructs
|
||||
blood_volume = 0
|
||||
var/list/construct_spells = list()
|
||||
var/playstyle_string = "<span class='big bold'>You are a generic construct!</span><b> Your job is to not exist, and you should probably adminhelp this.</b>"
|
||||
var/master = null
|
||||
@@ -459,4 +460,3 @@
|
||||
hud_used.healths.icon_state = "[icon_state]_health5"
|
||||
else
|
||||
hud_used.healths.icon_state = "[icon_state]_health6"
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
desc = "This station is just crawling with bugs."
|
||||
icon_state = "cockroach"
|
||||
icon_dead = "cockroach"
|
||||
blood_volume = 50
|
||||
health = 1
|
||||
maxHealth = 1
|
||||
turns_per_move = 5
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
speak_emote = list("clicks")
|
||||
emote_hear = list("clicks.")
|
||||
emote_see = list("clacks.")
|
||||
blood_volume = 350
|
||||
speak_chance = 1
|
||||
turns_per_move = 5
|
||||
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 1)
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
dextrous_hud_type = /datum/hud/dextrous/drone
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
see_in_dark = 7
|
||||
blood_volume = 0
|
||||
can_be_held = TRUE
|
||||
held_items = list(null, null)
|
||||
var/staticChoice = "static"
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
emote_see = list("runs in a circle.", "shakes.")
|
||||
speak_chance = 1
|
||||
turns_per_move = 5
|
||||
blood_volume = 250
|
||||
see_in_dark = 6
|
||||
maxHealth = 5
|
||||
health = 5
|
||||
|
||||
@@ -20,6 +20,7 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
|
||||
icon_living = "magicOrange"
|
||||
icon_dead = "magicOrange"
|
||||
speed = 0
|
||||
blood_volume = 0
|
||||
a_intent = INTENT_HARM
|
||||
stop_automated_movement = 1
|
||||
movement_type = FLYING // Immunity to chasms and landmines, etc.
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/bomb/AltClickOn(atom/movable/A)
|
||||
if(!istype(A))
|
||||
altclick_listed_turf(A)
|
||||
return
|
||||
if(loc == summoner)
|
||||
to_chat(src, "<span class='danger'><B>You must be manifested to create bombs!</span></B>")
|
||||
|
||||
@@ -105,8 +105,9 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/guardian/healer/AltClickOn(atom/movable/A)
|
||||
if(!istype(A))
|
||||
altclick_listed_turf(A)
|
||||
return
|
||||
if(src.loc == summoner)
|
||||
if(loc == summoner)
|
||||
to_chat(src, "<span class='danger'><B>You must be manifested to warp a target!</span></B>")
|
||||
return
|
||||
if(!beacon)
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
spacewalk = TRUE
|
||||
stat_attack = UNCONSCIOUS
|
||||
robust_searching = 1
|
||||
blood_volume = 0
|
||||
|
||||
harm_intent_damage = 10
|
||||
obj_damage = 50
|
||||
@@ -42,4 +43,4 @@
|
||||
var/mob/living/carbon/C = target
|
||||
C.Knockdown(60)
|
||||
C.visible_message("<span class='danger'>\The [src] knocks down \the [C]!</span>", \
|
||||
"<span class='userdanger'>\The [src] knocks you down!</span>")
|
||||
"<span class='userdanger'>\The [src] knocks you down!</span>")
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
del_on_death = 1
|
||||
loot = list(/obj/effect/decal/cleanable/robot_debris)
|
||||
blood_volume = 0
|
||||
|
||||
do_footstep = TRUE
|
||||
|
||||
|
||||
@@ -427,7 +427,7 @@
|
||||
if(casingtype)
|
||||
var/obj/item/ammo_casing/casing = new casingtype(startloc)
|
||||
playsound(src, projectilesound, 100, 1)
|
||||
casing.fire_casing(targeted_atom, src, null, null, null, ran_zone(), src)
|
||||
casing.fire_casing(targeted_atom, src, null, null, null, ran_zone(), 0, src)
|
||||
else if(projectiletype)
|
||||
var/obj/item/projectile/P = new projectiletype(startloc)
|
||||
playsound(src, projectilesound, 100, 1)
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
robust_searching = TRUE
|
||||
stat_attack = UNCONSCIOUS
|
||||
anchored = TRUE
|
||||
blood_volume = 0
|
||||
var/combatant_state = SEEDLING_STATE_NEUTRAL
|
||||
var/obj/seedling_weakpoint/weak_point
|
||||
var/mob/living/beam_debuff_target
|
||||
|
||||
@@ -376,7 +376,7 @@ Difficulty: Very Hard
|
||||
. += observer_desc
|
||||
. += "It is activated by [activation_method]."
|
||||
|
||||
/obj/machinery/anomalous_crystal/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
|
||||
/obj/machinery/anomalous_crystal/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode, atom/movable/source)
|
||||
..()
|
||||
if(isliving(speaker))
|
||||
ActivationReaction(speaker, ACTIVATE_SPEECH)
|
||||
|
||||
@@ -267,6 +267,7 @@ Difficulty: Medium
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/AltClickOn(atom/movable/A)
|
||||
if(!istype(A))
|
||||
altclick_listed_turf(A)
|
||||
return
|
||||
if(swoop_cooldown >= world.time)
|
||||
to_chat(src, "<span class='warning'>You need to wait 20 seconds between swoop attacks!</span>")
|
||||
|
||||
@@ -50,6 +50,7 @@ Difficulty: Normal
|
||||
armour_penetration = 75
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 20
|
||||
blood_volume = 0
|
||||
speed = 1
|
||||
move_to_delay = 11
|
||||
ranged = 1
|
||||
@@ -441,7 +442,7 @@ Difficulty: Normal
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/AltClickOn(atom/A) //player control handler(don't give this to a player holy fuck)
|
||||
if(!istype(A) || get_dist(A, src) <= 2)
|
||||
return
|
||||
return altclick_listed_turf(A)
|
||||
blink(A)
|
||||
|
||||
//Hierophant overlays
|
||||
|
||||
@@ -116,8 +116,10 @@
|
||||
recovery_time = world.time + buffer_time
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/proc/grant_achievement(medaltype, scoretype, crusher_kill)
|
||||
if(!medal_type || (flags_1 & ADMIN_SPAWNED_1) || !SSmedals.hub_enabled) //Don't award medals if the medal type isn't set
|
||||
if(!medal_type || (flags_1 & ADMIN_SPAWNED_1)) //Don't award medals if the medal type isn't set
|
||||
return FALSE
|
||||
if(!SSmedals.hub_enabled) // This allows subtypes to carry on other special rewards not tied with medals. (such as bubblegum's arena shuttle)
|
||||
return TRUE
|
||||
|
||||
for(var/mob/living/L in view(7,src))
|
||||
if(L.stat || !L.client)
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
environment_smash = ENVIRONMENT_SMASH_NONE
|
||||
sentience_type = SENTIENCE_BOSS
|
||||
layer = LARGE_MOB_LAYER
|
||||
blood_volume = 0
|
||||
var/doing_move_loop = FALSE
|
||||
var/mob/living/set_target
|
||||
var/timerid
|
||||
|
||||
@@ -0,0 +1,366 @@
|
||||
#define TUMOR_INACTIVE 0
|
||||
#define TUMOR_ACTIVE 1
|
||||
#define TUMOR_PASSIVE 2
|
||||
|
||||
//Elite mining mobs
|
||||
/mob/living/simple_animal/hostile/asteroid/elite
|
||||
name = "elite"
|
||||
desc = "An elite monster, found in one of the strange tumors on lavaland."
|
||||
icon = 'icons/mob/lavaland/lavaland_elites.dmi'
|
||||
faction = list("boss")
|
||||
robust_searching = TRUE
|
||||
ranged_ignores_vision = TRUE
|
||||
ranged = TRUE
|
||||
obj_damage = 5
|
||||
vision_range = 6
|
||||
aggro_vision_range = 18
|
||||
environment_smash = ENVIRONMENT_SMASH_NONE //This is to prevent elites smashing up the mining station, we'll make sure they can smash minerals fine below.
|
||||
harm_intent_damage = 0 //Punching elites gets you nowhere
|
||||
stat_attack = UNCONSCIOUS
|
||||
layer = LARGE_MOB_LAYER
|
||||
sentience_type = SENTIENCE_BOSS
|
||||
hud_type = /datum/hud/lavaland_elite
|
||||
var/chosen_attack = 1
|
||||
var/list/attack_action_types = list()
|
||||
var/can_talk = FALSE
|
||||
var/obj/loot_drop = null
|
||||
|
||||
//Gives player-controlled variants the ability to swap attacks
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/Initialize(mapload)
|
||||
. = ..()
|
||||
for(var/action_type in attack_action_types)
|
||||
var/datum/action/innate/elite_attack/attack_action = new action_type()
|
||||
attack_action.Grant(src)
|
||||
|
||||
//Prevents elites from attacking members of their faction (can't hurt themselves either) and lets them mine rock with an attack despite not being able to smash walls.
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/AttackingTarget()
|
||||
if(istype(target, /mob/living/simple_animal/hostile))
|
||||
var/mob/living/simple_animal/hostile/M = target
|
||||
if(faction_check_mob(M))
|
||||
return FALSE
|
||||
if(istype(target, /obj/structure/elite_tumor))
|
||||
var/obj/structure/elite_tumor/T = target
|
||||
if(T.mychild == src && T.activity == TUMOR_PASSIVE)
|
||||
var/elite_remove = alert("Re-enter the tumor?", "Despawn yourself?", "Yes", "No")
|
||||
if(elite_remove == "No" || !src || QDELETED(src))
|
||||
return
|
||||
T.mychild = null
|
||||
T.activity = TUMOR_INACTIVE
|
||||
T.icon_state = "advanced_tumor"
|
||||
qdel(src)
|
||||
return FALSE
|
||||
. = ..()
|
||||
if(ismineralturf(target))
|
||||
var/turf/closed/mineral/M = target
|
||||
M.gets_drilled()
|
||||
|
||||
//Elites can't talk (normally)!
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
|
||||
if(can_talk)
|
||||
. = ..()
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/*Basic setup for elite attacks, based on Whoneedspace's megafauna attack setup.
|
||||
While using this makes the system rely on OnFire, it still gives options for timers not tied to OnFire, and it makes using attacks consistent accross the board for player-controlled elites.*/
|
||||
|
||||
/datum/action/innate/elite_attack
|
||||
name = "Elite Attack"
|
||||
icon_icon = 'icons/mob/actions/actions_elites.dmi'
|
||||
button_icon_state = ""
|
||||
background_icon_state = "bg_default"
|
||||
var/mob/living/simple_animal/hostile/asteroid/elite/M
|
||||
var/chosen_message
|
||||
var/chosen_attack_num = 0
|
||||
|
||||
/datum/action/innate/elite_attack/Grant(mob/living/L)
|
||||
if(istype(L, /mob/living/simple_animal/hostile/asteroid/elite))
|
||||
M = L
|
||||
return ..()
|
||||
return FALSE
|
||||
|
||||
/datum/action/innate/elite_attack/Activate()
|
||||
M.chosen_attack = chosen_attack_num
|
||||
to_chat(M, chosen_message)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/updatehealth()
|
||||
. = ..()
|
||||
update_health_hud()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/update_health_hud()
|
||||
if(hud_used)
|
||||
var/severity = 0
|
||||
var/healthpercent = (health/maxHealth) * 100
|
||||
switch(healthpercent)
|
||||
if(100 to INFINITY)
|
||||
hud_used.healths.icon_state = "elite_health0"
|
||||
if(80 to 100)
|
||||
severity = 1
|
||||
if(60 to 80)
|
||||
severity = 2
|
||||
if(40 to 60)
|
||||
severity = 3
|
||||
if(20 to 40)
|
||||
severity = 4
|
||||
if(10 to 20)
|
||||
severity = 5
|
||||
if(1 to 20)
|
||||
severity = 6
|
||||
else
|
||||
severity = 7
|
||||
hud_used.healths.icon_state = "elite_health[severity]"
|
||||
if(severity > 0)
|
||||
overlay_fullscreen("brute", /obj/screen/fullscreen/brute, severity)
|
||||
else
|
||||
clear_fullscreen("brute")
|
||||
|
||||
//The Pulsing Tumor, the actual "spawn-point" of elites, handles the spawning, arena, and procs for dealing with basic scenarios.
|
||||
|
||||
/obj/structure/elite_tumor
|
||||
name = "pulsing tumor"
|
||||
desc = "An odd, pulsing tumor sticking out of the ground. You feel compelled to reach out and touch it..."
|
||||
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 100, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
var/activity = TUMOR_INACTIVE
|
||||
var/boosted = FALSE
|
||||
var/times_won = 0
|
||||
var/mob/living/carbon/human/activator = null
|
||||
var/mob/living/simple_animal/hostile/asteroid/elite/mychild = null
|
||||
var/potentialspawns = list(/mob/living/simple_animal/hostile/asteroid/elite/broodmother,
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/pandora,
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/legionnaire,
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/herald)
|
||||
icon = 'icons/obj/lavaland/tumor.dmi'
|
||||
icon_state = "tumor"
|
||||
pixel_x = -16
|
||||
light_color = LIGHT_COLOR_RED
|
||||
light_range = 3
|
||||
anchored = TRUE
|
||||
density = FALSE
|
||||
var/obj/item/gps/internal = null
|
||||
|
||||
/obj/item/gps/internal/elite
|
||||
icon_state = null
|
||||
gpstag = "Menacing Signal"
|
||||
desc = "You're not quite sure how a signal can be menacing."
|
||||
invisibility = 100
|
||||
|
||||
/obj/structure/elite_tumor/attack_hand(mob/user)
|
||||
. = ..()
|
||||
if(ishuman(user))
|
||||
switch(activity)
|
||||
if(TUMOR_PASSIVE)
|
||||
activity = TUMOR_ACTIVE
|
||||
visible_message("<span class='boldwarning'>[src] convulses as your arm enters its radius. Your instincts tell you to step back.</span>")
|
||||
activator = user
|
||||
if(boosted)
|
||||
mychild.playsound_local(get_turf(mychild), 'sound/effects/magic.ogg', 40, 0)
|
||||
to_chat(mychild, "<b>Someone has activated your tumor. You will be returned to fight shortly, get ready!</b>")
|
||||
addtimer(CALLBACK(src, .proc/return_elite), 30)
|
||||
INVOKE_ASYNC(src, .proc/arena_checks)
|
||||
if(TUMOR_INACTIVE)
|
||||
activity = TUMOR_ACTIVE
|
||||
var/mob/dead/observer/elitemind = null
|
||||
visible_message("<span class='boldwarning'>[src] begins to convulse. Your instincts tell you to step back.</span>")
|
||||
activator = user
|
||||
if(!boosted)
|
||||
addtimer(CALLBACK(src, .proc/spawn_elite), 30)
|
||||
return
|
||||
visible_message("<span class='boldwarning'>Something within [src] stirs...</span>")
|
||||
var/list/candidates = pollCandidatesForMob("Do you want to play as a lavaland elite?", ROLE_SENTIENCE, null, ROLE_SENTIENCE, 50, src, POLL_IGNORE_SENTIENCE_POTION)
|
||||
if(candidates.len)
|
||||
audible_message("<span class='boldwarning'>The stirring sounds increase in volume!</span>")
|
||||
elitemind = pick(candidates)
|
||||
elitemind.playsound_local(get_turf(elitemind), 'sound/effects/magic.ogg', 40, 0)
|
||||
to_chat(elitemind, "<b>You have been chosen to play as a Lavaland Elite.\nIn a few seconds, you will be summoned on Lavaland as a monster to fight your activator, in a fight to the death.\nYour attacks can be switched using the buttons on the top left of the HUD, and used by clicking on targets or tiles similar to a gun.\nWhile the opponent might have an upper hand with powerful mining equipment and tools, you have great power normally limited by AI mobs.\nIf you want to win, you'll have to use your powers in creative ways to ensure the kill. It's suggested you try using them all as soon as possible.\nShould you win, you'll receive extra information regarding what to do after. Good luck!</b>")
|
||||
addtimer(CALLBACK(src, .proc/spawn_elite, elitemind), 100)
|
||||
else
|
||||
visible_message("<span class='boldwarning'>The stirring stops, and nothing emerges. Perhaps try again later.</span>")
|
||||
activity = TUMOR_INACTIVE
|
||||
activator = null
|
||||
|
||||
|
||||
obj/structure/elite_tumor/proc/spawn_elite(var/mob/dead/observer/elitemind)
|
||||
var/selectedspawn = pick(potentialspawns)
|
||||
mychild = new selectedspawn(loc)
|
||||
visible_message("<span class='boldwarning'>[mychild] emerges from [src]!</span>")
|
||||
playsound(loc,'sound/effects/phasein.ogg', 200, 0, 50, TRUE, TRUE)
|
||||
if(boosted)
|
||||
mychild.key = elitemind.key
|
||||
mychild.sentience_act()
|
||||
icon_state = "tumor_popped"
|
||||
INVOKE_ASYNC(src, .proc/arena_checks)
|
||||
|
||||
obj/structure/elite_tumor/proc/return_elite()
|
||||
mychild.forceMove(loc)
|
||||
visible_message("<span class='boldwarning'>[mychild] emerges from [src]!</span>")
|
||||
playsound(loc,'sound/effects/phasein.ogg', 200, 0, 50, TRUE, TRUE)
|
||||
mychild.revive(full_heal = TRUE, admin_revive = TRUE)
|
||||
if(boosted)
|
||||
mychild.maxHealth = mychild.maxHealth * 2
|
||||
mychild.health = mychild.maxHealth
|
||||
|
||||
/obj/structure/elite_tumor/Initialize(mapload)
|
||||
. = ..()
|
||||
internal = new/obj/item/gps/internal/elite(src)
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/structure/elite_tumor/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
mychild = null
|
||||
activator = null
|
||||
return ..()
|
||||
|
||||
/obj/structure/elite_tumor/process()
|
||||
if(isturf(loc))
|
||||
for(var/mob/living/simple_animal/hostile/asteroid/elite/elitehere in loc)
|
||||
if(elitehere == mychild && activity == TUMOR_PASSIVE)
|
||||
mychild.adjustHealth(-mychild.maxHealth*0.05)
|
||||
var/obj/effect/temp_visual/heal/H = new /obj/effect/temp_visual/heal(get_turf(mychild))
|
||||
H.color = "#FF0000"
|
||||
|
||||
/obj/structure/elite_tumor/attackby(obj/item/I, mob/user, params)
|
||||
. = ..()
|
||||
if(istype(I, /obj/item/organ/regenerative_core) && activity == TUMOR_INACTIVE && !boosted)
|
||||
var/obj/item/organ/regenerative_core/core = I
|
||||
if(!core.preserved)
|
||||
return
|
||||
visible_message("<span class='boldwarning'>As [user] drops the core into [src], [src] appears to swell.</span>")
|
||||
icon_state = "advanced_tumor"
|
||||
boosted = TRUE
|
||||
light_range = 6
|
||||
desc = "[desc] This one seems to glow with a strong intensity."
|
||||
qdel(core)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/elite_tumor/proc/arena_checks()
|
||||
if(activity != TUMOR_ACTIVE || QDELETED(src))
|
||||
return
|
||||
INVOKE_ASYNC(src, .proc/fighters_check) //Checks to see if our fighters died.
|
||||
INVOKE_ASYNC(src, .proc/arena_trap) //Gets another arena trap queued up for when this one runs out.
|
||||
INVOKE_ASYNC(src, .proc/border_check) //Checks to see if our fighters got out of the arena somehow.
|
||||
addtimer(CALLBACK(src, .proc/arena_checks), 50)
|
||||
|
||||
/obj/structure/elite_tumor/proc/fighters_check()
|
||||
if(activator != null && activator.stat == DEAD || activity == TUMOR_ACTIVE && QDELETED(activator))
|
||||
onEliteWon()
|
||||
if(mychild != null && mychild.stat == DEAD || activity == TUMOR_ACTIVE && QDELETED(mychild))
|
||||
onEliteLoss()
|
||||
|
||||
/obj/structure/elite_tumor/proc/arena_trap()
|
||||
var/turf/T = get_turf(src)
|
||||
if(loc == null)
|
||||
return
|
||||
for(var/t in RANGE_TURFS(12, T))
|
||||
if(get_dist(t, T) == 12)
|
||||
var/obj/effect/temp_visual/elite_tumor_wall/newwall
|
||||
newwall = new /obj/effect/temp_visual/elite_tumor_wall(t, src)
|
||||
newwall.activator = src.activator
|
||||
newwall.ourelite = src.mychild
|
||||
|
||||
/obj/structure/elite_tumor/proc/border_check()
|
||||
if(activator != null && get_dist(src, activator) >= 12)
|
||||
activator.forceMove(loc)
|
||||
visible_message("<span class='boldwarning'>[activator] suddenly reappears above [src]!</span>")
|
||||
playsound(loc,'sound/effects/phasein.ogg', 200, 0, 50, TRUE, TRUE)
|
||||
if(mychild != null && get_dist(src, mychild) >= 12)
|
||||
mychild.forceMove(loc)
|
||||
visible_message("<span class='boldwarning'>[mychild] suddenly reappears above [src]!</span>")
|
||||
playsound(loc,'sound/effects/phasein.ogg', 200, 0, 50, TRUE, TRUE)
|
||||
|
||||
obj/structure/elite_tumor/proc/onEliteLoss()
|
||||
playsound(loc,'sound/effects/tendril_destroyed.ogg', 200, 0, 50, TRUE, TRUE)
|
||||
visible_message("<span class='boldwarning'>[src] begins to convulse violently before beginning to dissipate.</span>")
|
||||
visible_message("<span class='boldwarning'>As [src] closes, something is forced up from down below.</span>")
|
||||
var/obj/structure/closet/crate/necropolis/tendril/lootbox = new /obj/structure/closet/crate/necropolis/tendril(loc)
|
||||
if(!boosted)
|
||||
mychild = null
|
||||
activator = null
|
||||
qdel(src)
|
||||
return
|
||||
var/lootpick = rand(1, 2)
|
||||
if(lootpick == 1 && mychild.loot_drop != null)
|
||||
new mychild.loot_drop(lootbox)
|
||||
else
|
||||
new /obj/item/tumor_shard(lootbox)
|
||||
mychild = null
|
||||
activator = null
|
||||
qdel(src)
|
||||
|
||||
obj/structure/elite_tumor/proc/onEliteWon()
|
||||
activity = TUMOR_PASSIVE
|
||||
activator = null
|
||||
mychild.revive(full_heal = TRUE, admin_revive = TRUE)
|
||||
if(boosted)
|
||||
times_won++
|
||||
mychild.maxHealth = mychild.maxHealth * 0.5
|
||||
mychild.health = mychild.maxHealth
|
||||
if(times_won == 1)
|
||||
mychild.playsound_local(get_turf(mychild), 'sound/effects/magic.ogg', 40, 0)
|
||||
to_chat(mychild, "<span class='boldwarning'>As the life in the activator's eyes fade, the forcefield around you dies out and you feel your power subside.\nDespite this inferno being your home, you feel as if you aren't welcome here anymore.\nWithout any guidance, your purpose is now for you to decide.</span>")
|
||||
to_chat(mychild, "<b>Your max health has been halved, but can now heal by standing on your tumor. Note, it's your only way to heal.\nBear in mind, if anyone interacts with your tumor, you'll be resummoned here to carry out another fight. In such a case, you will regain your full max health.\nAlso, be weary of your fellow inhabitants, they likely won't be happy to see you!</b>")
|
||||
to_chat(mychild, "<span class='big bold'>Note that you are a lavaland monster, and thus not allied to the station. You should not cooperate or act friendly with any station crew unless under extreme circumstances!</span>")
|
||||
|
||||
/obj/item/tumor_shard
|
||||
name = "tumor shard"
|
||||
desc = "A strange, sharp, crystal shard from an odd tumor on Lavaland. Stabbing the corpse of a lavaland elite with this will revive them, assuming their soul still lingers. Revived lavaland elites only have half their max health, but are completely loyal to their reviver."
|
||||
icon = 'icons/obj/lavaland/artefacts.dmi'
|
||||
icon_state = "crevice_shard"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
|
||||
item_state = "screwdriver_head"
|
||||
throwforce = 5
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
|
||||
/obj/item/tumor_shard/afterattack(atom/target, mob/user, proximity_flag)
|
||||
. = ..()
|
||||
if(istype(target, /mob/living/simple_animal/hostile/asteroid/elite) && proximity_flag)
|
||||
var/mob/living/simple_animal/hostile/asteroid/elite/E = target
|
||||
if(E.stat != DEAD || E.sentience_type != SENTIENCE_BOSS || !E.key)
|
||||
user.visible_message("<span class='notice'>It appears [E] is unable to be revived right now. Perhaps try again later.</span>")
|
||||
return
|
||||
E.faction = list("neutral")
|
||||
E.revive(full_heal = TRUE, admin_revive = TRUE)
|
||||
user.visible_message("<span class='notice'>[user] stabs [E] with [src], reviving it.</span>")
|
||||
E.playsound_local(get_turf(E), 'sound/effects/magic.ogg', 40, 0)
|
||||
to_chat(E, "<span class='userdanger'>You have been revived by [user]. While you can't speak to them, you owe [user] a great debt. Assist [user.p_them()] in achieving [user.p_their()] goals, regardless of risk.</span")
|
||||
to_chat(E, "<span class='big bold'>Note that you now share the loyalties of [user]. You are expected not to intentionally sabotage their faction unless commanded to!</span>")
|
||||
E.maxHealth = E.maxHealth * 0.5
|
||||
E.health = E.maxHealth
|
||||
E.desc = "[E.desc] However, this one appears appears less wild in nature, and calmer around people."
|
||||
E.sentience_type = SENTIENCE_ORGANIC
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='info'>[src] only works on the corpse of a sentient lavaland elite.</span>")
|
||||
|
||||
/obj/effect/temp_visual/elite_tumor_wall
|
||||
name = "magic wall"
|
||||
icon = 'icons/turf/walls/hierophant_wall_temp.dmi'
|
||||
icon_state = "wall"
|
||||
duration = 50
|
||||
smooth = SMOOTH_TRUE
|
||||
layer = BELOW_MOB_LAYER
|
||||
var/mob/living/carbon/human/activator = null
|
||||
var/mob/living/simple_animal/hostile/asteroid/elite/ourelite = null
|
||||
color = rgb(255,0,0)
|
||||
light_range = MINIMUM_USEFUL_LIGHT_RANGE
|
||||
light_color = LIGHT_COLOR_RED
|
||||
|
||||
/obj/effect/temp_visual/elite_tumor_wall/Initialize(mapload, new_caster)
|
||||
. = ..()
|
||||
queue_smooth_neighbors(src)
|
||||
queue_smooth(src)
|
||||
|
||||
/obj/effect/temp_visual/elite_tumor_wall/Destroy()
|
||||
queue_smooth_neighbors(src)
|
||||
activator = null
|
||||
ourelite = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/temp_visual/elite_tumor_wall/CanPass(atom/movable/mover, turf/target)
|
||||
if(mover == ourelite || mover == activator)
|
||||
return FALSE
|
||||
else
|
||||
return TRUE
|
||||
@@ -0,0 +1,247 @@
|
||||
#define TENTACLE_PATCH 1
|
||||
#define SPAWN_CHILDREN 2
|
||||
#define RAGE 3
|
||||
#define CALL_CHILDREN 4
|
||||
|
||||
/**
|
||||
* # Goliath Broodmother
|
||||
*
|
||||
* A stronger, faster variation of the goliath. Has the ability to spawn baby goliaths, which it can later detonate at will.
|
||||
* When it's health is below half, tendrils will spawn randomly around it. When it is below a quarter of health, this effect is doubled.
|
||||
* It's attacks are as follows:
|
||||
* - Spawns a 3x3/plus shape of tentacles on the target location
|
||||
* - Spawns 2 baby goliaths on its tile, up to a max of 8. Children blow up when they die.
|
||||
* - The broodmother lets out a noise, and is able to move faster for 6.5 seconds.
|
||||
* - Summons your children around you.
|
||||
* The broodmother is a fight revolving around stage control, as the activator has to manage the baby goliaths and the broodmother herself, along with all the tendrils.
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/broodmother
|
||||
name = "goliath broodmother"
|
||||
desc = "An example of sexual dimorphism, this female goliath looks much different than the males of her species. She is, however, just as dangerous, if not more."
|
||||
gender = FEMALE
|
||||
icon_state = "broodmother"
|
||||
icon_living = "broodmother"
|
||||
icon_aggro = "broodmother"
|
||||
icon_dead = "egg_sac"
|
||||
icon_gib = "syndicate_gib"
|
||||
maxHealth = 800
|
||||
health = 800
|
||||
melee_damage_lower = 30
|
||||
melee_damage_upper = 30
|
||||
armour_penetration = 30
|
||||
attacktext = "beats down on"
|
||||
/*attack_verb_continuous = "beats down on"
|
||||
attack_verb_simple = "beat down on"*/
|
||||
attack_sound = 'sound/weapons/punch1.ogg'
|
||||
throw_message = "does nothing to the rocky hide of the"
|
||||
speed = 2
|
||||
move_to_delay = 5
|
||||
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
deathmessage = "explodes into gore!"
|
||||
loot_drop = /obj/item/crusher_trophy/broodmother_tongue
|
||||
|
||||
attack_action_types = list(/datum/action/innate/elite_attack/tentacle_patch,
|
||||
/datum/action/innate/elite_attack/spawn_children,
|
||||
/datum/action/innate/elite_attack/rage,
|
||||
/datum/action/innate/elite_attack/call_children)
|
||||
|
||||
var/rand_tent = 0
|
||||
var/list/mob/living/simple_animal/hostile/asteroid/elite/broodmother_child/children_list = list()
|
||||
|
||||
/datum/action/innate/elite_attack/tentacle_patch
|
||||
name = "Tentacle Patch"
|
||||
button_icon_state = "tentacle_patch"
|
||||
chosen_message = "<span class='boldwarning'>You are now attacking with a patch of tentacles.</span>"
|
||||
chosen_attack_num = TENTACLE_PATCH
|
||||
|
||||
/datum/action/innate/elite_attack/spawn_children
|
||||
name = "Spawn Children"
|
||||
button_icon_state = "spawn_children"
|
||||
chosen_message = "<span class='boldwarning'>You will spawn two children at your location to assist you in combat. You can have up to 8.</span>"
|
||||
chosen_attack_num = SPAWN_CHILDREN
|
||||
|
||||
/datum/action/innate/elite_attack/rage
|
||||
name = "Rage"
|
||||
button_icon_state = "rage"
|
||||
chosen_message = "<span class='boldwarning'>You will temporarily increase your movement speed.</span>"
|
||||
chosen_attack_num = RAGE
|
||||
|
||||
/datum/action/innate/elite_attack/call_children
|
||||
name = "Call Children"
|
||||
button_icon_state = "call_children"
|
||||
chosen_message = "<span class='boldwarning'>You will summon your children to your location.</span>"
|
||||
chosen_attack_num = CALL_CHILDREN
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/broodmother/OpenFire()
|
||||
if(client)
|
||||
switch(chosen_attack)
|
||||
if(TENTACLE_PATCH)
|
||||
tentacle_patch(target)
|
||||
if(SPAWN_CHILDREN)
|
||||
spawn_children()
|
||||
if(RAGE)
|
||||
rage()
|
||||
if(CALL_CHILDREN)
|
||||
call_children()
|
||||
return
|
||||
var/aiattack = rand(1,4)
|
||||
switch(aiattack)
|
||||
if(TENTACLE_PATCH)
|
||||
tentacle_patch(target)
|
||||
if(SPAWN_CHILDREN)
|
||||
spawn_children()
|
||||
if(RAGE)
|
||||
rage()
|
||||
if(CALL_CHILDREN)
|
||||
call_children()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/broodmother/Life()
|
||||
. = ..()
|
||||
if(!.) //Checks if they are dead as a rock.
|
||||
return
|
||||
if(health < maxHealth * 0.5 && rand_tent < world.time)
|
||||
rand_tent = world.time + 30
|
||||
var/tentacle_amount = 5
|
||||
if(health < maxHealth * 0.25)
|
||||
tentacle_amount = 10
|
||||
var/tentacle_loc = spiral_range_turfs(5, get_turf(src))
|
||||
for(var/i in 1 to tentacle_amount)
|
||||
var/turf/t = pick_n_take(tentacle_loc)
|
||||
new /obj/effect/temp_visual/goliath_tentacle/broodmother(t, src)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/broodmother/proc/tentacle_patch(var/target)
|
||||
ranged_cooldown = world.time + 15
|
||||
var/tturf = get_turf(target)
|
||||
if(!isturf(tturf))
|
||||
return
|
||||
visible_message("<span class='warning'>[src] digs its tentacles under [target]!</span>")
|
||||
new /obj/effect/temp_visual/goliath_tentacle/broodmother/patch(tturf, src)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/broodmother/proc/spawn_children(var/target)
|
||||
ranged_cooldown = world.time + 40
|
||||
visible_message("<span class='boldwarning'>The ground churns behind [src]!</span>")
|
||||
for(var/i in 1 to 2)
|
||||
if(children_list.len >= 8)
|
||||
return
|
||||
var/mob/living/simple_animal/hostile/asteroid/elite/broodmother_child/newchild = new /mob/living/simple_animal/hostile/asteroid/elite/broodmother_child(loc)
|
||||
newchild.GiveTarget(target)
|
||||
newchild.faction = faction.Copy()
|
||||
visible_message("<span class='boldwarning'>[newchild] appears below [src]!</span>")
|
||||
newchild.mother = src
|
||||
children_list += newchild
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/broodmother/proc/rage()
|
||||
ranged_cooldown = world.time + 70
|
||||
playsound(src,'sound/spookoween/insane_low_laugh.ogg', 200, 1)
|
||||
visible_message("<span class='warning'>[src] starts picking up speed!</span>")
|
||||
color = "#FF0000"
|
||||
set_varspeed(0)
|
||||
move_to_delay = 3
|
||||
addtimer(CALLBACK(src, .proc/reset_rage), 65)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/broodmother/proc/reset_rage()
|
||||
color = "#FFFFFF"
|
||||
set_varspeed(2)
|
||||
move_to_delay = 5
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/broodmother/proc/call_children()
|
||||
ranged_cooldown = world.time + 60
|
||||
visible_message("<span class='warning'>The ground shakes near [src]!</span>")
|
||||
var/list/directions = GLOB.cardinals.Copy() + GLOB.diagonals.Copy()
|
||||
for(var/mob/child in children_list)
|
||||
var/spawndir = pick_n_take(directions)
|
||||
var/turf/T = get_step(src, spawndir)
|
||||
if(T)
|
||||
child.forceMove(T)
|
||||
playsound(src, 'sound/effects/bamf.ogg', 100, 1)
|
||||
|
||||
//The goliath's children. Pretty weak, simple mobs which are able to put a single tentacle under their target when at range.
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/broodmother_child
|
||||
name = "baby goliath"
|
||||
desc = "A young goliath recently born from it's mother. While they hatch from eggs, said eggs are incubated in the mother until they are ready to be born."
|
||||
icon = 'icons/mob/lavaland/lavaland_monsters.dmi'
|
||||
icon_state = "goliath_baby"
|
||||
icon_living = "goliath_baby"
|
||||
icon_aggro = "goliath_baby"
|
||||
icon_dead = "goliath_baby_dead"
|
||||
icon_gib = "syndicate_gib"
|
||||
maxHealth = 30
|
||||
health = 30
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 5
|
||||
attacktext = "bashes against"
|
||||
/*attack_verb_continuous = "bashes against"
|
||||
attack_verb_simple = "bash against"*/
|
||||
attack_sound = 'sound/weapons/punch1.ogg'
|
||||
throw_message = "does nothing to the rocky hide of the"
|
||||
speed = 2
|
||||
move_to_delay = 5
|
||||
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
butcher_results = list()
|
||||
guaranteed_butcher_results = list(/obj/item/stack/sheet/animalhide/goliath_hide = 1)
|
||||
deathmessage = "falls to the ground."
|
||||
status_flags = CANPUSH
|
||||
var/mob/living/simple_animal/hostile/asteroid/elite/broodmother/mother = null
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/broodmother_child/OpenFire(target)
|
||||
ranged_cooldown = world.time + 40
|
||||
var/tturf = get_turf(target)
|
||||
if(!isturf(tturf))
|
||||
return
|
||||
if(get_dist(src, target) <= 7)//Screen range check, so it can't attack people off-screen
|
||||
visible_message("<span class='warning'>[src] digs one of its tentacles under [target]!</span>")
|
||||
new /obj/effect/temp_visual/goliath_tentacle/broodmother(tturf, src)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/broodmother_child/death()
|
||||
. = ..()
|
||||
if(mother != null)
|
||||
mother.children_list -= src
|
||||
visible_message("<span class='warning'>[src] explodes!</span>")
|
||||
explosion(get_turf(loc),0,0,0,flame_range = 3, adminlog = FALSE)
|
||||
gib()
|
||||
|
||||
//Tentacles have less stun time compared to regular variant, to balance being able to use them much more often. Also, 10 more damage.
|
||||
/obj/effect/temp_visual/goliath_tentacle/broodmother/trip()
|
||||
var/latched = FALSE
|
||||
for(var/mob/living/L in loc)
|
||||
if((!QDELETED(spawner) && spawner.faction_check_mob(L)) || L.stat == DEAD)
|
||||
continue
|
||||
visible_message("<span class='danger'>[src] grabs hold of [L]!</span>")
|
||||
L.Stun(10)
|
||||
L.adjustBruteLoss(rand(30,35))
|
||||
latched = TRUE
|
||||
if(!latched)
|
||||
retract()
|
||||
else
|
||||
deltimer(timerid)
|
||||
timerid = addtimer(CALLBACK(src, .proc/retract), 10, TIMER_STOPPABLE)
|
||||
|
||||
/obj/effect/temp_visual/goliath_tentacle/broodmother/patch/Initialize(mapload, new_spawner)
|
||||
. = ..()
|
||||
var/tentacle_locs = spiral_range_turfs(1, get_turf(src))
|
||||
for(var/T in tentacle_locs)
|
||||
new /obj/effect/temp_visual/goliath_tentacle/broodmother(T, spawner)
|
||||
var/list/directions = GLOB.cardinals.Copy()
|
||||
for(var/i in directions)
|
||||
var/turf/T = get_step(get_turf(src), i)
|
||||
T = get_step(T, i)
|
||||
new /obj/effect/temp_visual/goliath_tentacle/broodmother(T, spawner)
|
||||
|
||||
// Broodmother's loot: Broodmother Tongue
|
||||
/obj/item/crusher_trophy/broodmother_tongue
|
||||
name = "broodmother tongue"
|
||||
desc = "The tongue of a broodmother. If attached a certain way, makes for a suitable crusher trophy."
|
||||
icon = 'icons/obj/lavaland/elite_trophies.dmi'
|
||||
icon_state = "broodmother_tongue"
|
||||
denied_type = /obj/item/crusher_trophy/broodmother_tongue
|
||||
bonus_value = 10
|
||||
|
||||
/obj/item/crusher_trophy/broodmother_tongue/effect_desc()
|
||||
return "mark detonation to have a <b>[bonus_value]%</b> chance to summon a patch of goliath tentacles at the target's location"
|
||||
|
||||
/obj/item/crusher_trophy/broodmother_tongue/on_mark_detonation(mob/living/target, mob/living/user)
|
||||
if(rand(1, 100) <= bonus_value && target.stat != DEAD)
|
||||
new /obj/effect/temp_visual/goliath_tentacle/broodmother/patch(get_turf(target), user)
|
||||
@@ -0,0 +1,275 @@
|
||||
#define HERALD_TRISHOT 1
|
||||
#define HERALD_DIRECTIONALSHOT 2
|
||||
#define HERALD_TELESHOT 3
|
||||
#define HERALD_MIRROR 4
|
||||
|
||||
/**
|
||||
* # Herald
|
||||
*
|
||||
* A slow-moving projectile user with a few tricks up it's sleeve. Less unga-bunga than Colossus, with more cleverness in it's fighting style.
|
||||
* As it's health gets lower, the amount of projectiles fired per-attack increases.
|
||||
* It's attacks are as follows:
|
||||
* - Fires three projectiles in a a given direction.
|
||||
* - Fires a spread in every cardinal and diagonal direction at once, then does it again after a bit.
|
||||
* - Shoots a single, golden bolt. Wherever it lands, the herald will be teleported to the location.
|
||||
* - Spawns a mirror which reflects projectiles directly at the target.
|
||||
* Herald is a more concentrated variation of the Colossus fight, having less projectiles overall, but more focused attacks.
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/herald
|
||||
name = "herald"
|
||||
desc = "A monstrous beast which fires deadly projectiles at threats and prey."
|
||||
icon_state = "herald"
|
||||
icon_living = "herald"
|
||||
icon_aggro = "herald"
|
||||
icon_dead = "herald_dying"
|
||||
icon_gib = "syndicate_gib"
|
||||
maxHealth = 800
|
||||
health = 800
|
||||
melee_damage_lower = 20
|
||||
melee_damage_upper = 20
|
||||
attacktext = "preaches to"
|
||||
/*attack_verb_continuous = "preaches to"
|
||||
attack_verb_simple = "preach to"*/
|
||||
attack_sound = 'sound/magic/clockwork/ratvar_attack.ogg'
|
||||
throw_message = "doesn't affect the purity of"
|
||||
speed = 4
|
||||
move_to_delay = 10
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
deathsound = 'sound/magic/demon_dies.ogg'
|
||||
deathmessage = "begins to shudder as it becomes transparent..."
|
||||
loot_drop = /obj/item/clothing/neck/cloak/herald_cloak
|
||||
|
||||
can_talk = 1
|
||||
|
||||
attack_action_types = list(/datum/action/innate/elite_attack/herald_trishot,
|
||||
/datum/action/innate/elite_attack/herald_directionalshot,
|
||||
/datum/action/innate/elite_attack/herald_teleshot,
|
||||
/datum/action/innate/elite_attack/herald_mirror)
|
||||
|
||||
var/mob/living/simple_animal/hostile/asteroid/elite/herald/mirror/my_mirror = null
|
||||
var/is_mirror = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/herald/death()
|
||||
. = ..()
|
||||
if(!is_mirror)
|
||||
addtimer(CALLBACK(src, .proc/become_ghost), 8)
|
||||
if(my_mirror != null)
|
||||
qdel(my_mirror)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/herald/proc/become_ghost()
|
||||
icon_state = "herald_ghost"
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/herald/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
|
||||
. = ..()
|
||||
playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE)
|
||||
|
||||
/datum/action/innate/elite_attack/herald_trishot
|
||||
name = "Triple Shot"
|
||||
button_icon_state = "herald_trishot"
|
||||
chosen_message = "<span class='boldwarning'>You are now firing three shots in your chosen direction.</span>"
|
||||
chosen_attack_num = HERALD_TRISHOT
|
||||
|
||||
/datum/action/innate/elite_attack/herald_directionalshot
|
||||
name = "Circular Shot"
|
||||
button_icon_state = "herald_directionalshot"
|
||||
chosen_message = "<span class='boldwarning'>You are firing projectiles in all directions.</span>"
|
||||
chosen_attack_num = HERALD_DIRECTIONALSHOT
|
||||
|
||||
/datum/action/innate/elite_attack/herald_teleshot
|
||||
name = "Teleport Shot"
|
||||
button_icon_state = "herald_teleshot"
|
||||
chosen_message = "<span class='boldwarning'>You will now fire a shot which teleports you where it lands.</span>"
|
||||
chosen_attack_num = HERALD_TELESHOT
|
||||
|
||||
/datum/action/innate/elite_attack/herald_mirror
|
||||
name = "Summon Mirror"
|
||||
button_icon_state = "herald_mirror"
|
||||
chosen_message = "<span class='boldwarning'>You will spawn a mirror which duplicates your attacks.</span>"
|
||||
chosen_attack_num = HERALD_MIRROR
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/herald/OpenFire()
|
||||
if(client)
|
||||
switch(chosen_attack)
|
||||
if(HERALD_TRISHOT)
|
||||
herald_trishot(target)
|
||||
if(my_mirror != null)
|
||||
my_mirror.herald_trishot(target)
|
||||
if(HERALD_DIRECTIONALSHOT)
|
||||
herald_directionalshot()
|
||||
if(my_mirror != null)
|
||||
my_mirror.herald_directionalshot()
|
||||
if(HERALD_TELESHOT)
|
||||
herald_teleshot(target)
|
||||
if(my_mirror != null)
|
||||
my_mirror.herald_teleshot(target)
|
||||
if(HERALD_MIRROR)
|
||||
herald_mirror()
|
||||
return
|
||||
var/aiattack = rand(1,4)
|
||||
switch(aiattack)
|
||||
if(HERALD_TRISHOT)
|
||||
herald_trishot(target)
|
||||
if(my_mirror != null)
|
||||
my_mirror.herald_trishot(target)
|
||||
if(HERALD_DIRECTIONALSHOT)
|
||||
herald_directionalshot()
|
||||
if(my_mirror != null)
|
||||
my_mirror.herald_directionalshot()
|
||||
if(HERALD_TELESHOT)
|
||||
herald_teleshot(target)
|
||||
if(my_mirror != null)
|
||||
my_mirror.herald_teleshot(target)
|
||||
if(HERALD_MIRROR)
|
||||
herald_mirror()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/herald/proc/shoot_projectile(turf/marker, set_angle, var/is_teleshot)
|
||||
var/turf/startloc = get_turf(src)
|
||||
var/obj/item/projectile/herald/H = null
|
||||
if(!is_teleshot)
|
||||
H = new /obj/item/projectile/herald(startloc)
|
||||
else
|
||||
H = new /obj/item/projectile/herald/teleshot(startloc)
|
||||
H.preparePixelProjectile(marker, startloc)
|
||||
H.firer = src
|
||||
if(target)
|
||||
H.original = target
|
||||
H.fire(set_angle)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/herald/proc/herald_trishot(target)
|
||||
ranged_cooldown = world.time + 30
|
||||
playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE)
|
||||
var/target_turf = get_turf(target)
|
||||
var/angle_to_target = Get_Angle(src, target_turf)
|
||||
shoot_projectile(target_turf, angle_to_target, FALSE)
|
||||
addtimer(CALLBACK(src, .proc/shoot_projectile, target_turf, angle_to_target, FALSE), 2)
|
||||
addtimer(CALLBACK(src, .proc/shoot_projectile, target_turf, angle_to_target, FALSE), 4)
|
||||
if(health < maxHealth * 0.5)
|
||||
playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE)
|
||||
addtimer(CALLBACK(src, .proc/shoot_projectile, target_turf, angle_to_target, FALSE), 10)
|
||||
addtimer(CALLBACK(src, .proc/shoot_projectile, target_turf, angle_to_target, FALSE), 12)
|
||||
addtimer(CALLBACK(src, .proc/shoot_projectile, target_turf, angle_to_target, FALSE), 14)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/herald/proc/herald_circleshot()
|
||||
var/static/list/directional_shot_angles = list(0, 45, 90, 135, 180, 225, 270, 315)
|
||||
for(var/i in directional_shot_angles)
|
||||
shoot_projectile(get_turf(src), i, FALSE)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/herald/proc/unenrage()
|
||||
if(stat == DEAD || is_mirror)
|
||||
return
|
||||
icon_state = "herald"
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/herald/proc/herald_directionalshot()
|
||||
ranged_cooldown = world.time + 50
|
||||
if(!is_mirror)
|
||||
icon_state = "herald_enraged"
|
||||
playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE)
|
||||
addtimer(CALLBACK(src, .proc/herald_circleshot), 5)
|
||||
if(health < maxHealth * 0.5)
|
||||
playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE)
|
||||
addtimer(CALLBACK(src, .proc/herald_circleshot), 15)
|
||||
addtimer(CALLBACK(src, .proc/unenrage), 20)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/herald/proc/herald_teleshot(target)
|
||||
ranged_cooldown = world.time + 30
|
||||
playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE)
|
||||
var/target_turf = get_turf(target)
|
||||
var/angle_to_target = Get_Angle(src, target_turf)
|
||||
shoot_projectile(target_turf, angle_to_target, TRUE)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/herald/proc/herald_mirror()
|
||||
ranged_cooldown = world.time + 40
|
||||
playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE)
|
||||
if(my_mirror != null)
|
||||
qdel(my_mirror)
|
||||
my_mirror = null
|
||||
var/mob/living/simple_animal/hostile/asteroid/elite/herald/mirror/new_mirror = new /mob/living/simple_animal/hostile/asteroid/elite/herald/mirror(loc)
|
||||
my_mirror = new_mirror
|
||||
my_mirror.my_master = src
|
||||
my_mirror.faction = faction.Copy()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/herald/mirror
|
||||
name = "herald's mirror"
|
||||
desc = "This fiendish work of magic copies the herald's attacks. Seems logical to smash it."
|
||||
health = 60
|
||||
maxHealth = 60
|
||||
icon_state = "herald_mirror"
|
||||
deathmessage = "shatters violently!"
|
||||
deathsound = 'sound/effects/glassbr1.ogg'
|
||||
movement_type = FLYING
|
||||
del_on_death = TRUE
|
||||
is_mirror = TRUE
|
||||
var/mob/living/simple_animal/hostile/asteroid/elite/herald/my_master = null
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/herald/mirror/Initialize()
|
||||
..()
|
||||
toggle_ai(AI_OFF)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/herald/mirror/Destroy()
|
||||
if(my_master != null)
|
||||
my_master.my_mirror = null
|
||||
. = ..()
|
||||
|
||||
/obj/item/projectile/herald
|
||||
name ="death bolt"
|
||||
icon_state= "chronobolt"
|
||||
damage = 15
|
||||
armour_penetration = 60
|
||||
speed = 2
|
||||
eyeblur = 0
|
||||
damage_type = BRUTE
|
||||
pass_flags = PASSTABLE
|
||||
|
||||
/obj/item/projectile/herald/teleshot
|
||||
name ="golden bolt"
|
||||
damage = 0
|
||||
color = rgb(255,255,102)
|
||||
|
||||
/obj/item/projectile/herald/on_hit(atom/target, blocked = FALSE)
|
||||
. = ..()
|
||||
if(ismineralturf(target))
|
||||
var/turf/closed/mineral/M = target
|
||||
M.gets_drilled()
|
||||
return
|
||||
else if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
var/mob/living/F = firer
|
||||
if(F != null && istype(F, /mob/living/simple_animal/hostile/asteroid/elite) && F.faction_check_mob(L))
|
||||
L.heal_overall_damage(damage)
|
||||
|
||||
/obj/item/projectile/herald/teleshot/on_hit(atom/target, blocked = FALSE)
|
||||
. = ..()
|
||||
firer.forceMove(get_turf(src))
|
||||
|
||||
//Herald's loot: Cloak of the Prophet
|
||||
|
||||
/obj/item/clothing/neck/cloak/herald_cloak
|
||||
name = "cloak of the prophet"
|
||||
desc = "A cloak which protects you from the heresy of the world."
|
||||
icon = 'icons/obj/lavaland/elite_trophies.dmi'
|
||||
icon_state = "herald_cloak"
|
||||
body_parts_covered = CHEST|GROIN|ARMS
|
||||
hit_reaction_chance = 10
|
||||
|
||||
/obj/item/clothing/neck/cloak/herald_cloak/proc/reactionshot(mob/living/carbon/owner)
|
||||
var/static/list/directional_shot_angles = list(0, 45, 90, 135, 180, 225, 270, 315)
|
||||
for(var/i in directional_shot_angles)
|
||||
shoot_projectile(get_turf(owner), i, owner)
|
||||
|
||||
/obj/item/clothing/neck/cloak/herald_cloak/proc/shoot_projectile(turf/marker, set_angle, mob/living/carbon/owner)
|
||||
var/turf/startloc = get_turf(owner)
|
||||
var/obj/item/projectile/herald/H = null
|
||||
H = new /obj/item/projectile/herald(startloc)
|
||||
H.preparePixelProjectile(marker, startloc)
|
||||
H.firer = owner
|
||||
H.fire(set_angle)
|
||||
|
||||
/obj/item/clothing/neck/cloak/herald_cloak/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
|
||||
. = ..()
|
||||
if(rand(1,100) > hit_reaction_chance)
|
||||
return
|
||||
owner.visible_message("<span class='danger'>[owner]'s [src] emits a loud noise as [owner] is struck!</span>")
|
||||
var/static/list/directional_shot_angles = list(0, 45, 90, 135, 180, 225, 270, 315)
|
||||
playsound(get_turf(owner), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE)
|
||||
addtimer(CALLBACK(src, .proc/reactionshot, owner), 10)
|
||||
@@ -0,0 +1,303 @@
|
||||
#define LEGIONNAIRE_CHARGE 1
|
||||
#define HEAD_DETACH 2
|
||||
#define BONFIRE_TELEPORT 3
|
||||
#define SPEW_SMOKE 4
|
||||
|
||||
/**
|
||||
* # Legionnaire
|
||||
*
|
||||
* A towering skeleton, embodying the power of Legion.
|
||||
* As it's health gets lower, the head does more damage.
|
||||
* It's attacks are as follows:
|
||||
* - Charges at the target after a telegraph, throwing them across the arena should it connect.
|
||||
* - Legionnaire's head detaches, attacking as it's own entity. Has abilities of it's own later into the fight. Once dead, regenerates after a brief period. If the skill is used while the head is off, it will be killed.
|
||||
* - Leaves a pile of bones at your location. Upon using this skill again, you'll swap locations with the bone pile.
|
||||
* - Spews a cloud of smoke from it's maw, wherever said maw is.
|
||||
* A unique fight incorporating the head mechanic of legion into a whole new beast. Combatants will need to make sure the tag-team of head and body don't lure them into a deadly trap.
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/legionnaire
|
||||
name = "legionnaire"
|
||||
desc = "A towering skeleton, embodying the terrifying power of Legion."
|
||||
icon_state = "legionnaire"
|
||||
icon_living = "legionnaire"
|
||||
icon_aggro = "legionnaire"
|
||||
icon_dead = "legionnaire_dead"
|
||||
icon_gib = "syndicate_gib"
|
||||
maxHealth = 800
|
||||
health = 800
|
||||
melee_damage_lower = 30
|
||||
melee_damage_upper = 30
|
||||
attacktext = "slashes its arms at"
|
||||
/*attack_verb_continuous = "slashes its arms at"
|
||||
attack_verb_simple = "slash your arms at"*/
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
throw_message = "doesn't affect the sturdiness of"
|
||||
speed = 1
|
||||
move_to_delay = 3
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
deathsound = 'sound/magic/curse.ogg'
|
||||
deathmessage = "'s arms reach out before it falls apart onto the floor, lifeless."
|
||||
loot_drop = /obj/item/crusher_trophy/legionnaire_spine
|
||||
|
||||
attack_action_types = list(/datum/action/innate/elite_attack/legionnaire_charge,
|
||||
/datum/action/innate/elite_attack/head_detach,
|
||||
/datum/action/innate/elite_attack/bonfire_teleport,
|
||||
/datum/action/innate/elite_attack/spew_smoke)
|
||||
|
||||
var/mob/living/simple_animal/hostile/asteroid/elite/legionnairehead/myhead = null
|
||||
var/obj/structure/legionnaire_bonfire/mypile = null
|
||||
var/has_head = TRUE
|
||||
|
||||
/datum/action/innate/elite_attack/legionnaire_charge
|
||||
name = "Legionnaire Charge"
|
||||
button_icon_state = "legionnaire_charge"
|
||||
chosen_message = "<span class='boldwarning'>You will attempt to grab your opponent and throw them.</span>"
|
||||
chosen_attack_num = LEGIONNAIRE_CHARGE
|
||||
|
||||
/datum/action/innate/elite_attack/head_detach
|
||||
name = "Release Head"
|
||||
button_icon_state = "head_detach"
|
||||
chosen_message = "<span class='boldwarning'>You will now detach your head or kill it if it is already released.</span>"
|
||||
chosen_attack_num = HEAD_DETACH
|
||||
|
||||
/datum/action/innate/elite_attack/bonfire_teleport
|
||||
name = "Bonfire Teleport"
|
||||
button_icon_state = "bonfire_teleport"
|
||||
chosen_message = "<span class='boldwarning'>You will leave a bonfire. Second use will let you swap positions with it indefintiely. Using this move on the same tile as your active bonfire removes it.</span>"
|
||||
chosen_attack_num = BONFIRE_TELEPORT
|
||||
|
||||
/datum/action/innate/elite_attack/spew_smoke
|
||||
name = "Spew Smoke"
|
||||
button_icon_state = "spew_smoke"
|
||||
chosen_message = "<span class='boldwarning'>Your head will spew smoke in an area, wherever it may be.</span>"
|
||||
chosen_attack_num = SPEW_SMOKE
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/legionnaire/OpenFire()
|
||||
if(client)
|
||||
switch(chosen_attack)
|
||||
if(LEGIONNAIRE_CHARGE)
|
||||
legionnaire_charge(target)
|
||||
if(HEAD_DETACH)
|
||||
head_detach(target)
|
||||
if(BONFIRE_TELEPORT)
|
||||
bonfire_teleport()
|
||||
if(SPEW_SMOKE)
|
||||
spew_smoke()
|
||||
return
|
||||
var/aiattack = rand(1,4)
|
||||
switch(aiattack)
|
||||
if(LEGIONNAIRE_CHARGE)
|
||||
legionnaire_charge(target)
|
||||
if(HEAD_DETACH)
|
||||
head_detach(target)
|
||||
if(BONFIRE_TELEPORT)
|
||||
bonfire_teleport()
|
||||
if(SPEW_SMOKE)
|
||||
spew_smoke()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/legionnaire/proc/legionnaire_charge(target)
|
||||
ranged_cooldown = world.time + 50
|
||||
var/dir_to_target = get_dir(get_turf(src), get_turf(target))
|
||||
var/turf/T = get_step(get_turf(src), dir_to_target)
|
||||
for(var/i in 1 to 4)
|
||||
new /obj/effect/temp_visual/dragon_swoop/legionnaire(T)
|
||||
T = get_step(T, dir_to_target)
|
||||
playsound(src,'sound/magic/demon_attack1.ogg', 200, 1)
|
||||
visible_message("<span class='boldwarning'>[src] prepares to charge!</span>")
|
||||
addtimer(CALLBACK(src, .proc/legionnaire_charge_2, dir_to_target, 0), 5)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/legionnaire/proc/legionnaire_charge_2(var/move_dir, var/times_ran)
|
||||
if(times_ran >= 4)
|
||||
return
|
||||
var/turf/T = get_step(get_turf(src), move_dir)
|
||||
if(ismineralturf(T))
|
||||
var/turf/closed/mineral/M = T
|
||||
M.gets_drilled()
|
||||
if(T.density)
|
||||
return
|
||||
for(var/obj/structure/window/W in T.contents)
|
||||
return
|
||||
for(var/obj/machinery/door/D in T.contents)
|
||||
return
|
||||
forceMove(T)
|
||||
playsound(src,'sound/effects/bang.ogg', 200, 1)
|
||||
var/list/hit_things = list()
|
||||
var/throwtarget = get_edge_target_turf(src, move_dir)
|
||||
for(var/mob/living/L in T.contents - hit_things - src)
|
||||
if(faction_check_mob(L))
|
||||
return
|
||||
hit_things += L
|
||||
visible_message("<span class='boldwarning'>[src] attacks [L] with much force!</span>")
|
||||
to_chat(L, "<span class='userdanger'>[src] grabs you and throws you with much force!</span>")
|
||||
L.safe_throw_at(throwtarget, 10, 1, src)
|
||||
//L.Paralyze(20)
|
||||
L.Stun(20) //substituting this for the Paralyze from the line above, because we don't have tg paralysis stuff
|
||||
L.adjustBruteLoss(50)
|
||||
addtimer(CALLBACK(src, .proc/legionnaire_charge_2, move_dir, (times_ran + 1)), 2)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/legionnaire/proc/head_detach(target)
|
||||
ranged_cooldown = world.time + 10
|
||||
if(myhead != null)
|
||||
myhead.adjustBruteLoss(600)
|
||||
return
|
||||
if(has_head)
|
||||
has_head = FALSE
|
||||
icon_state = "legionnaire_headless"
|
||||
icon_living = "legionnaire_headless"
|
||||
icon_aggro = "legionnaire_headless"
|
||||
visible_message("<span class='boldwarning'>[src]'s head flies off!</span>")
|
||||
var/mob/living/simple_animal/hostile/asteroid/elite/legionnairehead/newhead = new /mob/living/simple_animal/hostile/asteroid/elite/legionnairehead(loc)
|
||||
newhead.flags_1 |= (flags_1 & ADMIN_SPAWNED_1)
|
||||
newhead.GiveTarget(target)
|
||||
newhead.faction = faction.Copy()
|
||||
myhead = newhead
|
||||
myhead.body = src
|
||||
if(health < maxHealth * 0.25)
|
||||
myhead.melee_damage_lower = 30
|
||||
myhead.melee_damage_upper = 30
|
||||
else if(health < maxHealth * 0.5)
|
||||
myhead.melee_damage_lower = 20
|
||||
myhead.melee_damage_upper = 20
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/legionnaire/proc/onHeadDeath()
|
||||
myhead = null
|
||||
addtimer(CALLBACK(src, .proc/regain_head), 50)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/legionnaire/proc/regain_head()
|
||||
has_head = TRUE
|
||||
if(stat == DEAD)
|
||||
return
|
||||
icon_state = "legionnaire"
|
||||
icon_living = "legionnaire"
|
||||
icon_aggro = "legionnaire"
|
||||
visible_message("<span class='boldwarning'>The top of [src]'s spine leaks a black liquid, forming into a skull!</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/legionnaire/proc/bonfire_teleport()
|
||||
ranged_cooldown = world.time + 5
|
||||
if(mypile == null)
|
||||
var/obj/structure/legionnaire_bonfire/newpile = new /obj/structure/legionnaire_bonfire(loc)
|
||||
mypile = newpile
|
||||
mypile.myowner = src
|
||||
playsound(get_turf(src),'sound/items/fulext_deploy.wav', 200, 1)
|
||||
visible_message("<span class='boldwarning'>[src] summons a bonfire on [get_turf(src)]!</span>")
|
||||
return
|
||||
else
|
||||
var/turf/legionturf = get_turf(src)
|
||||
var/turf/pileturf = get_turf(mypile)
|
||||
if(legionturf == pileturf)
|
||||
mypile.take_damage(100)
|
||||
mypile = null
|
||||
return
|
||||
playsound(pileturf,'sound/items/fulext_deploy.wav', 200, 1)
|
||||
playsound(legionturf,'sound/items/fulext_deploy.wav', 200, 1)
|
||||
visible_message("<span class='boldwarning'>[src] melts down into a burning pile of bones!</span>")
|
||||
forceMove(pileturf)
|
||||
visible_message("<span class='boldwarning'>[src] forms from the bonfire!</span>")
|
||||
mypile.forceMove(legionturf)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/legionnaire/proc/spew_smoke()
|
||||
ranged_cooldown = world.time + 60
|
||||
var/turf/T = null
|
||||
if(myhead != null)
|
||||
T = get_turf(myhead)
|
||||
else
|
||||
T = get_turf(src)
|
||||
if(myhead != null)
|
||||
myhead.visible_message("<span class='boldwarning'>[myhead] spews smoke from its maw!</span>")
|
||||
else if(!has_head)
|
||||
visible_message("<span class='boldwarning'>[src] spews smoke from the tip of their spine!</span>")
|
||||
else
|
||||
visible_message("<span class='boldwarning'>[src] spews smoke from its maw!</span>")
|
||||
var/datum/effect_system/smoke_spread/smoke = new
|
||||
smoke.set_up(2, T)
|
||||
smoke.start()
|
||||
|
||||
//The legionnaire's head. Basically the same as any legion head, but we have to tell our creator when we die so they can generate another head.
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/legionnairehead
|
||||
name = "legionnaire head"
|
||||
desc = "The legionnaire's head floating by itself. One shouldn't get too close, though once it sees you, you really don't have a choice."
|
||||
icon_state = "legionnaire_head"
|
||||
icon_living = "legionnaire_head"
|
||||
icon_aggro = "legionnaire_head"
|
||||
icon_dead = "legionnaire_dead"
|
||||
icon_gib = "syndicate_gib"
|
||||
maxHealth = 80
|
||||
health = 80
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 10
|
||||
attacktext = "bites at"
|
||||
/*attack_verb_continuous = "bites at"
|
||||
attack_verb_simple = "bite at"*/
|
||||
attack_sound = 'sound/effects/curse1.ogg'
|
||||
throw_message = "simply misses"
|
||||
speed = 0
|
||||
move_to_delay = 2
|
||||
del_on_death = 1
|
||||
deathmessage = "crumbles away!"
|
||||
faction = list()
|
||||
ranged = FALSE
|
||||
var/mob/living/simple_animal/hostile/asteroid/elite/legionnaire/body = null
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/legionnairehead/death()
|
||||
. = ..()
|
||||
if(body)
|
||||
body.onHeadDeath()
|
||||
|
||||
//The legionnaire's bonfire, which can be swapped positions with. Also sets flammable living beings on fire when they walk over it.
|
||||
/obj/structure/legionnaire_bonfire
|
||||
name = "bone pile"
|
||||
desc = "A pile of bones which seems to occasionally move a little. It's probably a good idea to smash them."
|
||||
icon = 'icons/obj/lavaland/legionnaire_bonfire.dmi'
|
||||
icon_state = "bonfire"
|
||||
max_integrity = 100
|
||||
//move_resist = MOVE_FORCE_EXTREMELY_STRONG
|
||||
anchored = TRUE
|
||||
density = FALSE
|
||||
light_range = 4
|
||||
light_color = LIGHT_COLOR_RED
|
||||
var/mob/living/simple_animal/hostile/asteroid/elite/legionnaire/myowner = null
|
||||
|
||||
|
||||
/obj/structure/legionnaire_bonfire/Entered(atom/movable/mover, turf/target)
|
||||
if(isliving(mover))
|
||||
var/mob/living/L = mover
|
||||
L.adjust_fire_stacks(3)
|
||||
L.IgniteMob()
|
||||
. = ..()
|
||||
|
||||
/obj/structure/legionnaire_bonfire/Destroy()
|
||||
if(myowner != null)
|
||||
myowner.mypile = null
|
||||
. = ..()
|
||||
|
||||
//The visual effect which appears in front of legionnaire when he goes to charge.
|
||||
/obj/effect/temp_visual/dragon_swoop/legionnaire
|
||||
duration = 10
|
||||
color = rgb(0,0,0)
|
||||
|
||||
/obj/effect/temp_visual/dragon_swoop/legionnaire/Initialize()
|
||||
. = ..()
|
||||
transform *= 0.33
|
||||
|
||||
// Legionnaire's loot: Legionnaire Spine
|
||||
|
||||
/obj/item/crusher_trophy/legionnaire_spine
|
||||
name = "legionnaire spine"
|
||||
desc = "The spine of a legionnaire. It almost feels like it's moving..."
|
||||
icon = 'icons/obj/lavaland/elite_trophies.dmi'
|
||||
icon_state = "legionnaire_spine"
|
||||
denied_type = /obj/item/crusher_trophy/legionnaire_spine
|
||||
bonus_value = 20
|
||||
|
||||
/obj/item/crusher_trophy/legionnaire_spine/effect_desc()
|
||||
return "mark detonation to have a <b>[bonus_value]%</b> chance to summon a loyal legion skull"
|
||||
|
||||
/obj/item/crusher_trophy/legionnaire_spine/on_mark_detonation(mob/living/target, mob/living/user)
|
||||
if(!rand(1, 100) <= bonus_value || target.stat == DEAD)
|
||||
return
|
||||
var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/A = new /mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion(user.loc)
|
||||
A.flags_1 |= (flags_1 & ADMIN_SPAWNED_1)
|
||||
A.GiveTarget(target)
|
||||
A.friends = user
|
||||
A.faction = user.faction.Copy()
|
||||
@@ -0,0 +1,193 @@
|
||||
#define SINGULAR_SHOT 1
|
||||
#define MAGIC_BOX 2
|
||||
#define PANDORA_TELEPORT 3
|
||||
#define AOE_SQUARES 4
|
||||
|
||||
/**
|
||||
* # Pandora
|
||||
*
|
||||
* A box with a similar design to the Hierophant which trades large, single attacks for more frequent smaller ones.
|
||||
* As it's health gets lower, the time between it's attacks decrease.
|
||||
* It's attacks are as follows:
|
||||
* - Fires hierophant blasts in a straight line. Can only fire in a straight line in 8 directions, being the diagonals and cardinals.
|
||||
* - Creates a box of hierophant blasts around the target. If they try to run away to avoid it, they'll very likely get hit.
|
||||
* - Teleports the pandora from one location to another, almost identical to Hierophant.
|
||||
* - Spawns a 5x5 AOE at the location of choice, spreading out from the center.
|
||||
* Pandora's fight mirrors Hierophant's closely, but has stark differences in attack effects. Instead of long-winded dodge times and long cooldowns, Pandora constantly attacks the opponent, but leaves itself open for attack.
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/pandora
|
||||
name = "pandora"
|
||||
desc = "A large magic box with similar power and design to the Hierophant. Once it opens, it's not easy to close it."
|
||||
icon_state = "pandora"
|
||||
icon_living = "pandora"
|
||||
icon_aggro = "pandora"
|
||||
icon_dead = "pandora_dead"
|
||||
icon_gib = "syndicate_gib"
|
||||
maxHealth = 800
|
||||
health = 800
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 15
|
||||
attacktext = "smashes into the side of"
|
||||
/*attack_verb_continuous = "smashes into the side of"
|
||||
attack_verb_simple = "smash into the side of"*/
|
||||
attack_sound = 'sound/weapons/sonic_jackhammer.ogg'
|
||||
throw_message = "merely dinks off of the"
|
||||
speed = 4
|
||||
move_to_delay = 10
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
deathsound = 'sound/magic/repulse.ogg'
|
||||
deathmessage = "'s lights flicker, before its top part falls down."
|
||||
loot_drop = /obj/item/clothing/accessory/pandora_hope
|
||||
|
||||
attack_action_types = list(/datum/action/innate/elite_attack/singular_shot,
|
||||
/datum/action/innate/elite_attack/magic_box,
|
||||
/datum/action/innate/elite_attack/pandora_teleport,
|
||||
/datum/action/innate/elite_attack/aoe_squares)
|
||||
|
||||
var/sing_shot_length = 8
|
||||
var/cooldown_time = 20
|
||||
|
||||
/datum/action/innate/elite_attack/singular_shot
|
||||
name = "Singular Shot"
|
||||
button_icon_state = "singular_shot"
|
||||
chosen_message = "<span class='boldwarning'>You are now creating a single linear magic square.</span>"
|
||||
chosen_attack_num = SINGULAR_SHOT
|
||||
|
||||
/datum/action/innate/elite_attack/magic_box
|
||||
name = "Magic Box"
|
||||
button_icon_state = "magic_box"
|
||||
chosen_message = "<span class='boldwarning'>You are now attacking with a box of magic squares.</span>"
|
||||
chosen_attack_num = MAGIC_BOX
|
||||
|
||||
/datum/action/innate/elite_attack/pandora_teleport
|
||||
name = "Line Teleport"
|
||||
button_icon_state = "pandora_teleport"
|
||||
chosen_message = "<span class='boldwarning'>You will now teleport to your target.</span>"
|
||||
chosen_attack_num = PANDORA_TELEPORT
|
||||
|
||||
/datum/action/innate/elite_attack/aoe_squares
|
||||
name = "AOE Blast"
|
||||
button_icon_state = "aoe_squares"
|
||||
chosen_message = "<span class='boldwarning'>Your attacks will spawn an AOE blast at your target location.</span>"
|
||||
chosen_attack_num = AOE_SQUARES
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/pandora/OpenFire()
|
||||
if(client)
|
||||
switch(chosen_attack)
|
||||
if(SINGULAR_SHOT)
|
||||
singular_shot(target)
|
||||
if(MAGIC_BOX)
|
||||
magic_box(target)
|
||||
if(PANDORA_TELEPORT)
|
||||
pandora_teleport(target)
|
||||
if(AOE_SQUARES)
|
||||
aoe_squares(target)
|
||||
return
|
||||
var/aiattack = rand(1,4)
|
||||
switch(aiattack)
|
||||
if(SINGULAR_SHOT)
|
||||
singular_shot(target)
|
||||
if(MAGIC_BOX)
|
||||
magic_box(target)
|
||||
if(PANDORA_TELEPORT)
|
||||
pandora_teleport(target)
|
||||
if(AOE_SQUARES)
|
||||
aoe_squares(target)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/pandora/Life()
|
||||
. = ..()
|
||||
if(health >= maxHealth * 0.5)
|
||||
cooldown_time = 20
|
||||
return
|
||||
if(health < maxHealth * 0.5 && health > maxHealth * 0.25)
|
||||
cooldown_time = 15
|
||||
return
|
||||
else
|
||||
cooldown_time = 10
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/pandora/proc/singular_shot(target)
|
||||
ranged_cooldown = world.time + (cooldown_time * 0.5)
|
||||
var/dir_to_target = get_dir(get_turf(src), get_turf(target))
|
||||
var/turf/T = get_step(get_turf(src), dir_to_target)
|
||||
singular_shot_line(sing_shot_length, dir_to_target, T)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/pandora/proc/singular_shot_line(var/procsleft, var/angleused, var/turf/T)
|
||||
if(procsleft <= 0)
|
||||
return
|
||||
new /obj/effect/temp_visual/hierophant/blast/pandora(T, src)
|
||||
T = get_step(T, angleused)
|
||||
procsleft = procsleft - 1
|
||||
addtimer(CALLBACK(src, .proc/singular_shot_line, procsleft, angleused, T), 2)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/pandora/proc/magic_box(target)
|
||||
ranged_cooldown = world.time + cooldown_time
|
||||
var/turf/T = get_turf(target)
|
||||
for(var/t in spiral_range_turfs(3, T))
|
||||
if(get_dist(t, T) > 1)
|
||||
new /obj/effect/temp_visual/hierophant/blast/pandora(t, src)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/pandora/proc/pandora_teleport(target)
|
||||
ranged_cooldown = world.time + cooldown_time
|
||||
var/turf/T = get_turf(target)
|
||||
var/turf/source = get_turf(src)
|
||||
new /obj/effect/temp_visual/hierophant/telegraph(T, src)
|
||||
new /obj/effect/temp_visual/hierophant/telegraph(source, src)
|
||||
playsound(source,'sound/machines/airlockopen.ogg', 200, 1)
|
||||
addtimer(CALLBACK(src, .proc/pandora_teleport_2, T, source), 2)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/pandora/proc/pandora_teleport_2(var/turf/T, var/turf/source)
|
||||
new /obj/effect/temp_visual/hierophant/telegraph/teleport(T, src)
|
||||
new /obj/effect/temp_visual/hierophant/telegraph/teleport(source, src)
|
||||
for(var/t in RANGE_TURFS(1, T))
|
||||
new /obj/effect/temp_visual/hierophant/blast/pandora(t, src)
|
||||
for(var/t in RANGE_TURFS(1, source))
|
||||
new /obj/effect/temp_visual/hierophant/blast/pandora(t, src)
|
||||
animate(src, alpha = 0, time = 2, easing = EASE_OUT) //fade out
|
||||
visible_message("<span class='hierophant_warning'>[src] fades out!</span>")
|
||||
density = FALSE
|
||||
addtimer(CALLBACK(src, .proc/pandora_teleport_3, T), 2)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/pandora/proc/pandora_teleport_3(var/turf/T)
|
||||
forceMove(T)
|
||||
animate(src, alpha = 255, time = 2, easing = EASE_IN) //fade IN
|
||||
density = TRUE
|
||||
visible_message("<span class='hierophant_warning'>[src] fades in!</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/pandora/proc/aoe_squares(target)
|
||||
ranged_cooldown = world.time + cooldown_time
|
||||
var/turf/T = get_turf(target)
|
||||
new /obj/effect/temp_visual/hierophant/blast/pandora(T, src)
|
||||
var/max_size = 2
|
||||
addtimer(CALLBACK(src, .proc/aoe_squares_2, T, 0, max_size), 2)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/pandora/proc/aoe_squares_2(var/turf/T, var/ring, var/max_size)
|
||||
if(ring > max_size)
|
||||
return
|
||||
for(var/t in spiral_range_turfs(ring, T))
|
||||
if(get_dist(t, T) == ring)
|
||||
new /obj/effect/temp_visual/hierophant/blast/pandora(t, src)
|
||||
addtimer(CALLBACK(src, .proc/aoe_squares_2, T, (ring + 1), max_size), 2)
|
||||
|
||||
//The specific version of hiero's squares pandora uses
|
||||
/obj/effect/temp_visual/hierophant/blast/pandora
|
||||
damage = 20
|
||||
monster_damage_boost = FALSE
|
||||
|
||||
//Pandora's loot: Hope
|
||||
/obj/item/clothing/accessory/pandora_hope
|
||||
name = "Hope"
|
||||
desc = "Found at the bottom of Pandora. After all the evil was released, this was the only thing left inside."
|
||||
icon = 'icons/obj/lavaland/elite_trophies.dmi'
|
||||
icon_state = "hope"
|
||||
resistance_flags = FIRE_PROOF
|
||||
|
||||
/obj/item/clothing/accessory/pandora_hope/on_uniform_equip(obj/item/clothing/under/U, user)
|
||||
var/mob/living/L = user
|
||||
if(L && L.mind)
|
||||
SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "hope_lavaland", /datum/mood_event/hope_lavaland)
|
||||
|
||||
/obj/item/clothing/accessory/pandora_hope/on_uniform_dropped(obj/item/clothing/under/U, user)
|
||||
var/mob/living/L = user
|
||||
if(L && L.mind)
|
||||
SEND_SIGNAL(L, COMSIG_CLEAR_MOOD_EVENT, "hope_lavaland")
|
||||
@@ -6,6 +6,7 @@
|
||||
icon_dead = "bat_dead"
|
||||
icon_gib = "bat_dead"
|
||||
turns_per_move = 1
|
||||
blood_volume = 250
|
||||
response_help = "brushes aside"
|
||||
response_disarm = "flails at"
|
||||
response_harm = "hits"
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
movement_type = FLYING
|
||||
pressure_resistance = 300
|
||||
gold_core_spawnable = NO_SPAWN //too spooky for science
|
||||
blood_volume = 0
|
||||
var/ghost_hair_style
|
||||
var/ghost_hair_color
|
||||
var/mutable_appearance/ghost_hair
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
emote_see = list("rattles")
|
||||
a_intent = INTENT_HARM
|
||||
maxHealth = 40
|
||||
blood_volume = 0
|
||||
health = 40
|
||||
speed = 1
|
||||
harm_intent_damage = 5
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
maxHealth = 50000
|
||||
health = 50000
|
||||
healable = 0
|
||||
blood_volume = 0
|
||||
|
||||
harm_intent_damage = 10
|
||||
obj_damage = 100
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
response_disarm = "shoves"
|
||||
response_harm = "hits"
|
||||
speed = 0
|
||||
blood_volume = 0
|
||||
stat_attack = UNCONSCIOUS
|
||||
robust_searching = 1
|
||||
environment_smash = ENVIRONMENT_SMASH_NONE
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
stat("Held Item", held_item)
|
||||
stat("Mode",a_intent)
|
||||
|
||||
/mob/living/simple_animal/parrot/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans, message_mode)
|
||||
/mob/living/simple_animal/parrot/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
|
||||
. = ..()
|
||||
if(speaker != src && prob(50)) //Dont imitate ourselves
|
||||
if(!radio_freq || prob(10))
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
loot = list(/obj/item/ectoplasm)
|
||||
del_on_death = TRUE
|
||||
initial_language_holder = /datum/language_holder/construct
|
||||
blood_volume = 0
|
||||
|
||||
/mob/living/simple_animal/shade/death()
|
||||
deathmessage = "lets out a contented sigh as [p_their()] form unwinds."
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
health = 20
|
||||
maxHealth = 20
|
||||
gender = PLURAL //placeholder
|
||||
blood_volume = 550 //How much blud it has for bloodsucking
|
||||
|
||||
status_flags = CANPUSH
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/mob/living/simple_animal/slime/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
|
||||
/mob/living/simple_animal/slime/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode, atom/movable/source)
|
||||
. = ..()
|
||||
if(speaker != src && !radio_freq && !stat)
|
||||
if (speaker in Friends)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
health = 150
|
||||
healable = 0
|
||||
gender = NEUTER
|
||||
blood_volume = 0 //Until someome reworks for them to have slime jelly
|
||||
|
||||
see_in_dark = 8
|
||||
|
||||
|
||||
@@ -140,24 +140,28 @@
|
||||
|
||||
/////////////////////////////////// DISABILITIES ////////////////////////////////////
|
||||
|
||||
/mob/living/proc/add_quirk(quirk, spawn_effects) //separate proc due to the way these ones are handled
|
||||
if(HAS_TRAIT(src, quirk))
|
||||
/mob/living/proc/add_quirk(quirktype, spawn_effects) //separate proc due to the way these ones are handled
|
||||
if(has_quirk(quirktype))
|
||||
return
|
||||
if(!SSquirks || !SSquirks.quirks[quirk])
|
||||
var/datum/quirk/T = quirktype
|
||||
var/qname = initial(T.name)
|
||||
if(!SSquirks || !SSquirks.quirks[qname])
|
||||
return
|
||||
var/datum/quirk/T = SSquirks.quirks[quirk]
|
||||
new T (src, spawn_effects)
|
||||
new quirktype (src, spawn_effects)
|
||||
return TRUE
|
||||
|
||||
/mob/living/proc/remove_quirk(quirk)
|
||||
var/datum/quirk/T = roundstart_quirks[quirk]
|
||||
if(T)
|
||||
qdel(T)
|
||||
return TRUE
|
||||
|
||||
/mob/living/proc/has_quirk(quirk)
|
||||
return roundstart_quirks[quirk]
|
||||
/mob/living/proc/remove_quirk(quirktype)
|
||||
for(var/datum/quirk/Q in roundstart_quirks)
|
||||
if(Q.type == quirktype)
|
||||
qdel(Q)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/proc/has_quirk(quirktype)
|
||||
for(var/datum/quirk/Q in roundstart_quirks)
|
||||
if(Q.type == quirktype)
|
||||
return TRUE
|
||||
return FALSE
|
||||
/////////////////////////////////// TRAIT PROCS ////////////////////////////////////
|
||||
|
||||
/mob/living/proc/cure_blind(list/sources)
|
||||
|
||||
@@ -8,6 +8,7 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, typecacheof(list(
|
||||
/mob/living/proc/handle_ventcrawl(atom/A)
|
||||
if(!ventcrawler || !Adjacent(A))
|
||||
return
|
||||
. = TRUE //return value to stop the client from being shown the turf contents stat tab on alt-click.
|
||||
if(stat)
|
||||
to_chat(src, "You must be conscious to do this!")
|
||||
return
|
||||
|
||||
@@ -465,9 +465,10 @@ mob/visible_message(message, self_message, blind_message, vision_distance = DEFA
|
||||
/mob/proc/transfer_ckey(mob/new_mob, send_signal = TRUE)
|
||||
if(!ckey || !new_mob)
|
||||
CRASH("transfer_ckey() called [ckey ? "" : "on a ckey-less mob[new_mob ? "" : " and "]"][new_mob ? "" : "without a valid mob target"]!")
|
||||
SEND_SIGNAL(new_mob, COMSIG_MOB_PRE_PLAYER_CHANGE, new_mob, src)
|
||||
new_mob.ckey = ckey
|
||||
if(send_signal)
|
||||
SEND_SIGNAL(src, COMSIG_MOB_KEY_CHANGE, new_mob, src)
|
||||
new_mob.ckey = ckey
|
||||
return TRUE
|
||||
|
||||
/mob/verb/cancel_camera()
|
||||
|
||||
@@ -99,6 +99,12 @@
|
||||
var/obj/control_object //Used by admins to possess objects. All mobs should have this var
|
||||
var/atom/movable/remote_control //Calls relaymove() to whatever it is
|
||||
|
||||
/**
|
||||
* The sound made on death
|
||||
*
|
||||
* leave null for no sound. used for *deathgasp
|
||||
*/
|
||||
var/deathsound = null
|
||||
|
||||
var/turf/listed_turf = null //the current turf being examined in the stat panel
|
||||
|
||||
|
||||
@@ -366,6 +366,9 @@
|
||||
if(m_intent == MOVE_INTENT_RUN)
|
||||
m_intent = MOVE_INTENT_WALK
|
||||
else
|
||||
if (HAS_TRAIT(src,TRAIT_NORUNNING)) // FULPSTATION 7/10/19 So you can't run during fortitude.
|
||||
to_chat(src, "You find yourself unable to run.")
|
||||
return FALSE
|
||||
m_intent = MOVE_INTENT_RUN
|
||||
if(hud_used && hud_used.static_inventory)
|
||||
for(var/obj/screen/mov_intent/selector in hud_used.static_inventory)
|
||||
@@ -401,4 +404,4 @@
|
||||
return TRUE
|
||||
|
||||
/mob/proc/canZMove(direction, turf/target)
|
||||
return FALSE
|
||||
return FALSE
|
||||
|
||||
@@ -134,17 +134,6 @@
|
||||
/mob/proc/Dizzy(amount)
|
||||
dizziness = max(dizziness,amount,0)
|
||||
|
||||
/////////////////////////////////// EYE DAMAGE ////////////////////////////////////
|
||||
|
||||
/mob/proc/damage_eyes(amount)
|
||||
return
|
||||
|
||||
/mob/proc/adjust_eye_damage(amount)
|
||||
return
|
||||
|
||||
/mob/proc/set_eye_damage(amount)
|
||||
return
|
||||
|
||||
/////////////////////////////////// EYE_BLIND ////////////////////////////////////
|
||||
|
||||
/mob/proc/blind_eyes(amount)
|
||||
|
||||
Reference in New Issue
Block a user