conflict resolution

This commit is contained in:
KasparoVy
2017-02-05 17:13:34 -05:00
619 changed files with 18580 additions and 11660 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ var/global/list/boo_phrases=list(
invocation_type = "none"
range = 1 // Or maybe 3?
/obj/effect/proc_holder/spell/aoe_turf/boo/cast(list/targets)
/obj/effect/proc_holder/spell/aoe_turf/boo/cast(list/targets, mob/user = usr)
for(var/turf/T in targets)
for(var/atom/A in T.contents)
@@ -10,6 +10,7 @@
/mob/living/carbon/brain/New()
create_reagents(330)
add_language("Galactic Common")
..()
/mob/living/carbon/brain/Destroy()
+5 -5
View File
@@ -914,14 +914,14 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump,
/mob/living/carbon/proc/slip(var/description, var/stun, var/weaken, var/tilesSlipped, var/walkSafely, var/slipAny)
if(flying || buckled || (walkSafely && m_intent == "walk"))
return
return 0
if((lying) && (!(tilesSlipped)))
return
return 0
if(!(slipAny))
if(istype(src, /mob/living/carbon/human))
var/mob/living/carbon/human/H = src
if((isobj(H.shoes) && H.shoes.flags & NOSLIP) || H.species.bodyflags & FEET_NOSLIP)
return
return 0
if(tilesSlipped)
for(var/t = 0, t<=tilesSlipped, t++)
spawn (t) step(src, src.dir)
@@ -995,8 +995,8 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump,
return 1
/mob/living/carbon/proc/forceFedAttackLog(var/obj/item/weapon/reagent_containers/food/toEat, mob/user)
attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been fed [toEat.name] by [user.name] ([user.ckey]) Reagents: [toEat.reagentlist(toEat)]</font>")
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Fed [toEat.name] to [name] ([ckey]) Reagents: [toEat.reagentlist(toEat)]</font>")
create_attack_log("<font color='orange'>Has been fed [toEat.name] by [user.name] ([user.ckey]) Reagents: [toEat.reagentlist(toEat)]</font>")
user.create_attack_log("<font color='red'>Fed [toEat.name] to [name] ([ckey]) Reagents: [toEat.reagentlist(toEat)]</font>")
log_attack("[user.name] ([user.ckey]) fed [name] ([ckey]) with [toEat.name] Reagents: [toEat.reagentlist(toEat)] (INTENT: [uppertext(user.a_intent)])")
if(!iscarbon(user))
LAssailant = null
@@ -36,4 +36,4 @@
for(var/datum/disease/D in user.viruses)
if(D.IsSpreadByTouch())
ContractDisease(D)
return 0
return 0
+50 -40
View File
@@ -83,12 +83,12 @@
message = "<B>[src]</B> pings at [param]."
else
message = "<B>[src]</B> pings."
playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
playsound(loc, 'sound/machines/ping.ogg', 50, 0)
m_type = 2
if("buzz2")
message = "<B>[src]</B> emits an irritated buzzing sound."
playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0)
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
m_type = 2
if("buzz", "buzzes")
@@ -105,7 +105,7 @@
message = "<B>[src]</B> buzzes at [param]."
else
message = "<B>[src]</B> buzzes."
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
m_type = 2
if("beep", "beeps")
@@ -122,7 +122,7 @@
message = "<B>[src]</B> beeps at [param]."
else
message = "<B>[src]</B> beeps."
playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
playsound(loc, 'sound/machines/twobeep.ogg', 50, 0)
m_type = 2
if("drone", "drones", "hum", "hums", "rumble", "rumbles")
@@ -139,7 +139,7 @@
message = "<B>[src]</B> drones at [param]."
else
message = "<B>[src]</B> rumbles."
playsound(src.loc, 'sound/voice/DraskTalk.ogg', 50, 0)
playsound(loc, 'sound/voice/DraskTalk.ogg', 50, 0)
m_type = 2
if("squish", "squishes")
@@ -156,7 +156,7 @@
message = "<B>[src]</B> squishes at [param]."
else
message = "<B>[src]</B> squishes."
playsound(src.loc, 'sound/effects/slime_squish.ogg', 50, 0) //Credit to DrMinky (freesound.org) for the sound.
playsound(loc, 'sound/effects/slime_squish.ogg', 50, 0) //Credit to DrMinky (freesound.org) for the sound.
m_type = 2
if("yes")
@@ -173,7 +173,7 @@
message = "<B>[src]</B> emits an affirmative blip at [param]."
else
message = "<B>[src]</B> emits an affirmative blip."
playsound(src.loc, 'sound/machines/synth_yes.ogg', 50, 0)
playsound(loc, 'sound/machines/synth_yes.ogg', 50, 0)
m_type = 2
if("no")
@@ -190,7 +190,7 @@
message = "<B>[src]</B> emits a negative blip at [param]."
else
message = "<B>[src]</B> emits a negative blip."
playsound(src.loc, 'sound/machines/synth_no.ogg', 50, 0)
playsound(loc, 'sound/machines/synth_no.ogg', 50, 0)
m_type = 2
if("wag", "wags")
@@ -202,7 +202,7 @@
else if(species.bodyflags & TAIL_WAGGING)
if(!wear_suit || !(wear_suit.flags_inv & HIDETAIL) && !istype(wear_suit, /obj/item/clothing/suit/space))
message = "<B>[src]</B> starts wagging \his tail."
src.start_tail_wagging(1)
start_tail_wagging(1)
else
return
else
@@ -212,15 +212,25 @@
if("swag", "swags")
if(species.bodyflags & TAIL_WAGGING || body_accessory)
message = "<B>[src]</B> stops wagging \his tail."
src.stop_tail_wagging(1)
stop_tail_wagging(1)
else
return
m_type = 1
if("airguitar")
if(!src.restrained())
if(!restrained())
message = "<B>[src]</B> is strumming the air and headbanging like a safari chimp."
m_type = 1
if("dance")
if(!restrained())
message = "<B>[src]</B> dances around happily."
m_type = 1
if("jump")
if(!restrained())
message = "<B>[src]</B> jumps!"
m_type = 1
if("blink", "blinks")
message = "<B>[src]</B> blinks."
@@ -231,7 +241,7 @@
m_type = 1
if("bow", "bows")
if(!src.buckled)
if(!buckled)
var/M = null
if(param)
for(var/mob/A in view(null, null))
@@ -248,7 +258,7 @@
m_type = 1
if("salute", "salutes")
if(!src.buckled)
if(!buckled)
var/M = null
if(param)
for(var/mob/A in view(null, null))
@@ -288,13 +298,13 @@
message = "<B>[src]</B> makes a peculiar noise."
m_type = 2
if("clap", "claps")
if(!src.restrained())
if(!restrained())
message = "<B>[src]</B> claps."
m_type = 2
if(miming)
m_type = 1
if("flap", "flaps")
if(!src.restrained())
if(!restrained())
message = "<B>[src]</B> flaps \his wings."
m_type = 2
if(miming)
@@ -302,7 +312,7 @@
if("flip", "flips")
m_type = 1
if(!src.restrained())
if(!restrained())
var/M = null
if(param)
for(var/mob/A in view(1, null))
@@ -340,7 +350,7 @@
SpinAnimation(5,1)
if("aflap", "aflaps")
if(!src.restrained())
if(!restrained())
message = "<B>[src]</B> flaps \his wings ANGRILY!"
m_type = 2
if(miming)
@@ -376,7 +386,7 @@
if("faint", "faints")
message = "<B>[src]</B> faints."
if(src.sleeping)
if(sleeping)
return //Can't faint while asleep
AdjustSleeping(2)
m_type = 1
@@ -578,11 +588,11 @@
message = "<B>[src]</B> takes a drag from a cigarette and blows \"[M]\" out in smoke."
m_type = 1
else
message = "<B>[src]</B> says, \"[M], please. They had a family.\" [src.name] takes a drag from a cigarette and blows their name out in smoke."
message = "<B>[src]</B> says, \"[M], please. They had a family.\" [name] takes a drag from a cigarette and blows their name out in smoke."
m_type = 2
if("point", "points")
if(!src.restrained())
if(!restrained())
var/atom/M = null
if(param)
for(var/atom/A as mob|obj|turf in view())
@@ -597,7 +607,7 @@
m_type = 1
if("raise", "raises")
if(!src.restrained())
if(!restrained())
message = "<B>[src]</B> raises a hand."
m_type = 1
@@ -610,12 +620,12 @@
m_type = 1
if("signal", "signals")
if(!src.restrained())
if(!restrained())
var/t1 = round(text2num(param))
if(isnum(t1))
if(t1 <= 5 && (!src.r_hand || !src.l_hand))
if(t1 <= 5 && (!r_hand || !l_hand))
message = "<B>[src]</B> raises [t1] finger\s."
else if(t1 <= 10 && (!src.r_hand && !src.l_hand))
else if(t1 <= 10 && (!r_hand && !l_hand))
message = "<B>[src]</B> raises [t1] finger\s."
m_type = 1
@@ -699,7 +709,7 @@
if("hug", "hugs")
m_type = 1
if(!src.restrained())
if(!restrained())
var/M = null
if(param)
for(var/mob/A in view(1, null))
@@ -716,7 +726,7 @@
if("handshake")
m_type = 1
if(!src.restrained() && !src.r_hand)
if(!restrained() && !r_hand)
var/mob/M = null
if(param)
for(var/mob/A in view(1, null))
@@ -734,7 +744,7 @@
if("dap", "daps")
m_type = 1
if(!src.restrained())
if(!restrained())
var/M = null
if(param)
for(var/mob/A in view(1, null))
@@ -748,7 +758,7 @@
if("slap", "slaps")
m_type = 1
if(!src.restrained())
if(!restrained())
var/M = null
if(param)
for(var/mob/A in view(1, null))
@@ -757,11 +767,11 @@
break
if(M)
message = "<span class='danger'>[src] slaps [M] across the face. Ouch!</span>"
playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
playsound(loc, 'sound/effects/snap.ogg', 50, 1)
else
message = "<span class='danger'>[src] slaps \himself!</span>"
playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
src.adjustFireLoss(4)
playsound(loc, 'sound/effects/snap.ogg', 50, 1)
adjustFireLoss(4)
if("scream", "screams")
if(miming)
@@ -772,9 +782,9 @@
message = "<B>[src]</B> [species.scream_verb]!"
m_type = 2
if(gender == FEMALE)
playsound(src.loc, "[species.female_scream_sound]", 80, 1, 0, pitch = get_age_pitch())
playsound(loc, "[species.female_scream_sound]", 80, 1, 0, pitch = get_age_pitch())
else
playsound(src.loc, "[species.male_scream_sound]", 80, 1, 0, pitch = get_age_pitch()) //default to male screams if no gender is present.
playsound(loc, "[species.male_scream_sound]", 80, 1, 0, pitch = get_age_pitch()) //default to male screams if no gender is present.
else
message = "<B>[src]</B> makes a very loud noise."
@@ -799,24 +809,24 @@
return
message = "<b>[src]</b> snaps \his fingers."
playsound(src.loc, 'sound/effects/fingersnap.ogg', 50, 1, -3)
playsound(loc, 'sound/effects/fingersnap.ogg', 50, 1, -3)
else
message = "<span class='danger'><b>[src]</b> snaps \his fingers right off!</span>"
playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
playsound(loc, 'sound/effects/snap.ogg', 50, 1)
// Needed for M_TOXIC_FART
if("fart", "farts")
if(reagents.has_reagent("simethicone"))
return
// playsound(src.loc, 'sound/effects/fart.ogg', 50, 1, -3) //Admins still vote no to fun
// playsound(loc, 'sound/effects/fart.ogg', 50, 1, -3) //Admins still vote no to fun
if(locate(/obj/item/weapon/storage/bible) in get_turf(src))
to_chat(viewers(src), "<span class='warning'><b>[src] farts on the Bible!</b></span>")
to_chat(viewers(src), "<span class='notice'><b>A mysterious force smites [src]!</b></span>")
var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
src.gib()
gib()
else if(TOXIC_FARTS in mutations)
message = "<b>[src]</b> unleashes a [pick("horrible","terrible","foul","disgusting","awful")] fart."
else if(SUPER_FART in mutations)
@@ -841,9 +851,9 @@
M.reagents.add_reagent("jenkem", 1)
if("help")
var/emotelist = "aflap(s), airguitar, blink(s), blink(s)_r, blush(es), bow(s)-(none)/mob, burp(s), choke(s), chuckle(s), clap(s), collapse(s), cough(s),cry, cries, custom, dap(s)(none)/mob," \
+ " deathgasp(s), drool(s), eyebrow,fart(s), faint(s), flap(s), flip(s), frown(s), gasp(s), giggle(s), glare(s)-(none)/mob, grin(s), groan(s), grumble(s), handshake-mob, hug(s)-(none)/mob," \
+ " glare(s)-(none)/mob, grin(s), johnny, laugh(s), look(s)-(none)/mob, moan(s), mumble(s), nod(s), pale(s), point(s)-atom, quiver(s), raise(s), salute(s)-(none)/mob, scream(s), shake(s)," \
var/emotelist = "aflap(s), airguitar, blink(s), blink(s)_r, blush(es), bow(s)-(none)/mob, burp(s), choke(s), chuckle(s), clap(s), collapse(s), cough(s),cry, cries, custom, dance, dap(s)(none)/mob," \
+ " deathgasp(s), drool(s), eyebrow, fart(s), faint(s), flap(s), flip(s), frown(s), gasp(s), giggle(s), glare(s)-(none)/mob, grin(s), groan(s), grumble(s), grin(s)," \
+ " handshake-mob, hug(s)-(none)/mob, johnny, jump, laugh(s), look(s)-(none)/mob, moan(s), mumble(s), nod(s), pale(s), point(s)-atom, quiver(s), raise(s), salute(s)-(none)/mob, scream(s), shake(s)," \
+ " shiver(s), shrug(s), sigh(s), signal(s)-#1-10,slap(s)-(none)/mob, smile(s),snap(s), sneeze(s), sniff(s), snore(s), stare(s)-(none)/mob, swag(s), tremble(s), twitch(es), twitch(es)_s," \
+ " wag(s), wave(s), whimper(s), wink(s), yawn(s)"
if(species.name == "Machine")
@@ -182,8 +182,8 @@
apply_effect(2, WEAKEN, run_armor_check(affecting, "melee"))
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
visible_message("<span class='danger'>[M] has pushed [src]!</span>")
M.attack_log += text("\[[time_stamp()]\] <font color='red'>Pushed [src.name] ([src.ckey])</font>")
src.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been pushed by [M.name] ([M.ckey])</font>")
M.create_attack_log("<font color='red'>Pushed [src.name] ([src.ckey])</font>")
src.create_attack_log("<font color='orange'>Has been pushed by [M.name] ([M.ckey])</font>")
if(!iscarbon(M))
LAssailant = null
else
@@ -38,6 +38,7 @@ emp_act
var/obj/item/organ/external/organ = get_organ(check_zone(def_zone))
if(isnull(organ))
. = bullet_act(P, "chest") //act on chest instead
return
//Shrapnel
@@ -56,6 +57,18 @@ emp_act
organ.add_autopsy_data(P.name, P.damage) // Add the bullet's name to the autopsy data
return (..(P , def_zone))
/mob/living/carbon/human/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
var/obj/item/organ/external/affecting = get_organ(check_zone(def_zone))
if(affecting && !affecting.cannot_amputate && affecting.get_damage() >= (affecting.max_damage - P.dismemberment))
var/damtype = DROPLIMB_EDGE
switch(P.damage_type)
if(BRUTE)
damtype = DROPLIMB_BLUNT
if(BURN)
damtype = DROPLIMB_BURN
affecting.droplimb(FALSE, damtype)
/mob/living/carbon/human/getarmor(var/def_zone, var/type)
var/armorval = 0
@@ -187,8 +200,8 @@ emp_act
--src.meatleft
to_chat(user, "\red You hack off a chunk of meat from [src.name]")
if(!src.meatleft)
src.attack_log += "\[[time_stamp()]\] Was chopped up into meat by <b>[key_name(user)]</b>"
user.attack_log += "\[[time_stamp()]\] Chopped up <b>[key_name(src)]</b> into meat</b>"
src.create_attack_log("Was chopped up into meat by <b>[key_name(user)]</b>")
user.create_attack_log("Chopped up <b>[key_name(src)]</b> into meat</b>")
msg_admin_attack("[key_name_admin(user)] chopped up [key_name_admin(src)] into meat")
if(!iscarbon(user))
LAssailant = null
@@ -436,8 +449,8 @@ emp_act
visible_message("<span class='danger'>[src] has been hit by [M.name].</span>", \
"<span class='userdanger'>[src] has been hit by [M.name].</span>")
attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been attacked by \the [M] controlled by [key_name(M.occupant)] (INTENT: [uppertext(M.occupant.a_intent)])</font>")
M.occupant.attack_log += text("\[[time_stamp()]\] <font color='red'>Attacked [src] with \the [M] (INTENT: [uppertext(M.occupant.a_intent)])</font>")
create_attack_log("<font color='orange'>Has been attacked by \the [M] controlled by [key_name(M.occupant)] (INTENT: [uppertext(M.occupant.a_intent)])</font>")
M.occupant.create_attack_log("<font color='red'>Attacked [src] with \the [M] (INTENT: [uppertext(M.occupant.a_intent)])</font>")
msg_admin_attack("[key_name_admin(M.occupant)] attacked [key_name_admin(src)] with \the [M] (INTENT: [uppertext(M.occupant.a_intent)])")
else
@@ -119,15 +119,15 @@
internalBeaker.name = "Grow-U-All Super Spray"
if(internalBeaker && internalBag)
var/obj/machinery/portable_atmospherics/hydroponics/HP
var/obj/machinery/hydroponics/HP
//consider the appropriate target
var/list/considered = list()
for(var/obj/machinery/portable_atmospherics/hydroponics/tester in view(12,src))
for(var/obj/machinery/hydroponics/tester in view(12,src))
considered[tester] = 1
if(!tester.seed)
if(!tester.myseed)
considered[tester] += 50
if(tester.weedlevel > 0)
considered[tester] += 5
@@ -154,7 +154,7 @@
else
if(HP.harvest || HP.dead)
HP.attack_hand(src)
else if(!HP.seed)
else if(!HP.myseed)
var/obj/item/seeds/SEED = new /obj/item/seeds/random(src)
custom_emote(1, "[pick("gibbers","drools","slobbers","claps wildly","spits")] towards [TARGET], producing a [SEED]!")
HP.attackby(SEED, src)
@@ -170,8 +170,8 @@
internalBeaker.reagents.add_reagent("diethylamine", 10)
if(HP.nutrilevel < HP.maxnutri)
change = 1
if(!internalBeaker.reagents.has_reagent("eznutrient", 15))
internalBeaker.reagents.add_reagent("eznutrient", 15)
if(!internalBeaker.reagents.has_reagent("eznutriment", 15))
internalBeaker.reagents.add_reagent("eznutriment", 15)
if(!internalBeaker.reagents.has_reagent("diethylamine", 15))
internalBeaker.reagents.add_reagent("diethylamine", 15)
if(HP.waterlevel < HP.maxwater)
@@ -261,7 +261,7 @@
var/pranksNearby = 100
for(var/turf/simulated/T in orange(1, C))
for(var/obj/item/A in T)
if(istype(A,/obj/item/weapon/soap) || istype(A,/obj/item/weapon/reagent_containers/food/snacks/grown/banana) || istype(A,/obj/item/weapon/bananapeel))
if(istype(A,/obj/item/weapon/soap) || istype(A,/obj/item/weapon/reagent_containers/food/snacks/grown/banana) || istype(A,/obj/item/weapon/grown/bananapeel))
pranksNearby--
if(T.wet)
pranksNearby -= 10
@@ -287,7 +287,7 @@
if(istype(A,/obj/item/weapon/reagent_containers/food/snacks/grown/banana))
var/obj/item/weapon/reagent_containers/food/snacks/B = A
B.attack(src, src)
if(istype(A,/obj/item/weapon/bananapeel))
if(istype(A,/obj/item/weapon/grown/bananapeel))
npcDrop(A)
hasPranked = 1
if(!hasPranked)
@@ -403,26 +403,6 @@
ingredients += I
I.forceMove(null)
for(var/P in R.fruit)
for(var/i = 1 to R.fruit[P])
var/obj/item/I = locate(P) in allContents
if(I)
ingredients += I
I.forceMove(null)
continue
I = locate(P) in rangeCheck
TARGET = I
if(I && !Adjacent(I))
tryWalk(get_turf(I))
sleep(get_dist(src, I))
if(!I || !(I in rangeCheck))
refundrecipe(ingredients)
return 0
custom_emote(1, "[pick("gibbers","drools","slobbers","claps wildly","spits")], picking up [I].")
ingredients += I
I.forceMove(null)
// cheaply cook the ingredients into result
sleep(R.time)
for(var/obj/I in ingredients)
@@ -579,8 +559,8 @@
var/highest_count = 0
var/datum/recipe/winner = null
for(var/datum/recipe/R in available_recipes)
if(R.check_items(ingredientZone) >= 0 && R.check_fruit(ingredientZone) >= 0)
var/count = (R.items ? R.items.len : 0) + (R.fruit ? R.fruit.len : 0)
if(R.check_items(ingredientZone) >= 0)
var/count = (R.items ? R.items.len : 0)
if(count > highest_count)
highest_count = count
winner = R
@@ -349,10 +349,10 @@
favoured_types = list(/obj/item/weapon/mop, /obj/item/weapon/reagent_containers/glass/bucket, /obj/item/weapon/reagent_containers/spray/cleaner, /obj/effect/decal/cleanable)
functions += "dojanitor"
if("Clown")
favoured_types = list(/obj/item/weapon/soap, /obj/item/weapon/reagent_containers/food/snacks/grown/banana, /obj/item/weapon/bananapeel)
favoured_types = list(/obj/item/weapon/soap, /obj/item/weapon/reagent_containers/food/snacks/grown/banana, /obj/item/weapon/grown/bananapeel)
functions += "clowning"
if("Botanist")
favoured_types = list(/obj/machinery/portable_atmospherics/hydroponics, /obj/item/weapon/reagent_containers, /obj/item/weapon)
favoured_types = list(/obj/machinery/hydroponics, /obj/item/weapon/reagent_containers, /obj/item/weapon)
functions += "botany"
restrictedJob = 1
else
+2 -2
View File
@@ -1,10 +1,10 @@
/mob/living/carbon/human/say(var/message)
/mob/living/carbon/human/say(var/message, var/sanitize = TRUE, var/ignore_speech_problems = FALSE, var/ignore_atmospherics = FALSE)
var/alt_name = ""
if(name != GetVoice())
alt_name = " (as [get_id_name("Unknown")])"
..(message, alt_name = alt_name) //ohgod we should really be passing a datum here.
..(message, alt_name = alt_name, sanitize = sanitize, ignore_speech_problems = ignore_speech_problems, ignore_atmospherics = ignore_atmospherics) //ohgod we should really be passing a datum here.
/mob/living/carbon/human/proc/forcesay(list/append)
if(stat == CONSCIOUS)
@@ -78,8 +78,8 @@
head_organ.h_style = "Bald"
H.update_hair()
M.attack_log += text("\[[time_stamp()]\] <font color='red'>removed antennae [H.name] ([H.ckey])</font>")
H.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has had their antennae removed by [M.name] ([M.ckey])</font>")
M.create_attack_log("<font color='red'>removed antennae [H.name] ([H.ckey])</font>")
H.create_attack_log("<font color='orange'>Has had their antennae removed by [M.name] ([M.ckey])</font>")
msg_admin_attack("[key_name(M)] removed [key_name(H)]'s antennae")
return 0
@@ -8,6 +8,8 @@
default_language = "Galactic Common"
unarmed_type = /datum/unarmed_attack/claws
ignored_by = list(/mob/living/simple_animal/hostile/faithless)
blood_color = "#CCCCCC"
flesh_color = "#AAAAAA"
has_organ = list(
@@ -20,6 +22,7 @@
oxy_mod = 0
virus_immune = 1
dietflags = DIET_OMNI //the mutation process allowed you to now digest all foods regardless of initial race
reagent_tag = PROCESS_ORG
suicide_messages = list(
@@ -28,13 +31,45 @@
"is twisting their own neck!",
"is staring into the closest light source!")
var/grant_vision_toggle = 1
var/datum/action/innate/shadow/darkvision/vision_toggle
/datum/action/innate/shadow/darkvision //Darkvision toggle so shadowpeople can actually see where darkness is
name = "Toggle Darkvision"
check_flags = AB_CHECK_CONSCIOUS
background_icon_state = "bg_default"
button_icon_state = "blind"
/datum/action/innate/shadow/darkvision/Activate()
var/mob/living/carbon/human/H = owner
if(!H.vision_type)
H.vision_type = new /datum/vision_override/nightvision
to_chat(H, "<span class='notice'>You adjust your vision to pierce the darkness.</span>")
else
H.vision_type = null
to_chat(H, "<span class='notice'>You adjust your vision to recognize the shadows.</span>")
/datum/species/shadow/grant_abilities(var/mob/living/carbon/human/H)
. = ..()
if(grant_vision_toggle)
vision_toggle = new
vision_toggle.Grant(H)
/datum/species/shadow/remove_abilities(var/mob/living/carbon/human/H)
. = ..()
if(grant_vision_toggle && vision_toggle)
H.vision_type = null
vision_toggle.Remove(H)
/datum/species/shadow/handle_life(var/mob/living/carbon/human/H)
var/light_amount = 0
if(isturf(H.loc))
var/turf/T = H.loc
light_amount = T.get_lumcount()*10
light_amount = T.get_lumcount() * 10
if(light_amount > 2) //if there's enough light, start dying
H.take_overall_damage(1,1)
H.throw_alert("lightexposure", /obj/screen/alert/lightexposure)
else if(light_amount < 2) //heal in the dark
H.heal_overall_damage(1,1)
H.heal_overall_damage(1,1)
H.clear_alert("lightexposure")
@@ -49,6 +49,7 @@
var/siemens_coeff = 1 //base electrocution coefficient
var/invis_sight = SEE_INVISIBLE_LIVING
var/hazard_high_pressure = HAZARD_HIGH_PRESSURE // Dangerously high pressure.
var/warning_high_pressure = WARNING_HIGH_PRESSURE // High pressure warning.
var/warning_low_pressure = WARNING_LOW_PRESSURE // Low pressure warning.
@@ -84,6 +85,8 @@
var/ventcrawler = 0 //Determines if the mob can go through the vents.
var/has_fine_manipulation = 1 // Can use small items.
var/mob/living/list/ignored_by = list() // list of mobs that will ignore this species
var/list/allowed_consumed_mobs = list() //If a species can consume mobs, put the type of mobs it can consume here.
var/flags = 0 // Various specific features.
@@ -161,7 +164,6 @@
"l_foot" = list("path" = /obj/item/organ/external/foot),
"r_foot" = list("path" = /obj/item/organ/external/foot/right)
)
var/cyborg_type = "Cyborg"
var/list/proc/species_abilities = list()
/datum/species/New()
@@ -806,8 +806,8 @@
return ..()
/datum/species/diona/handle_life(var/mob/living/carbon/human/H)
var/rads = H.radiation/25
H.radiation = Clamp(H.radiation - rads, 0, 100)
var/rads = H.radiation / 25
H.apply_effect(-rads,IRRADIATE,0)
H.nutrition += rads
H.adjustBruteLoss(-(rads))
H.adjustOxyLoss(-(rads))
@@ -816,18 +816,23 @@
var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing
if(isturf(H.loc)) //else, there's considered to be no light
var/turf/T = H.loc
light_amount = min(T.get_lumcount()*10, 5) //hardcapped so it's not abused by having a ton of flashlights
light_amount = min(T.get_lumcount() * 10, 5) //hardcapped so it's not abused by having a ton of flashlights
H.nutrition += light_amount
H.traumatic_shock -= light_amount
if(H.nutrition > NUTRITION_LEVEL_WELL_FED)
H.nutrition = NUTRITION_LEVEL_WELL_FED
if(light_amount > 0)
H.clear_alert("nolight")
else
H.throw_alert("nolight", /obj/screen/alert/nolight)
if((light_amount >= 5) && !H.suiciding) //if there's enough light, heal
H.adjustBruteLoss(-(light_amount/2))
H.adjustFireLoss(-(light_amount/4))
H.adjustOxyLoss(-(light_amount))
if(H.nutrition < 200)
H.take_overall_damage(10,0)
H.traumatic_shock++
@@ -264,8 +264,8 @@
playsound(loc, M.attack_sound, 50, 1, 1)
visible_message("<span class='danger'>[M] [M.attacktext] [src]!</span>", \
"<span class='userdanger'>[M] [M.attacktext] [src]!</span>")
M.attack_log += text("\[[time_stamp()]\] <font color='red'>attacked [src.name] ([src.ckey])</font>")
src.attack_log += text("\[[time_stamp()]\] <font color='orange'>was attacked by [M.name] ([M.ckey])</font>")
M.create_attack_log("<font color='red'>attacked [src.name] ([src.ckey])</font>")
src.create_attack_log("<font color='orange'>was attacked by [M.name] ([M.ckey])</font>")
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
attacked += 10
adjustBruteLoss(damage)
+28 -28
View File
@@ -147,69 +147,69 @@
action_icon_state = "spell_greytide"
var/recruiting = 0
/obj/effect/proc_holder/spell/targeted/recruit/cast(list/targets)
/obj/effect/proc_holder/spell/targeted/recruit/cast(list/targets,mob/living/user = usr)
for(var/mob/living/carbon/human/target in targets)
var/obj/item/organ/external/head/head_organ = target.get_organ("head")
if(ticker.mode.greyshirts.len >= 3)
to_chat(usr, "<span class='warning'>You have already recruited the maximum number of henchmen.</span>")
if(!in_range(usr, target))
to_chat(usr, "<span class='warning'>You need to be closer to enthrall [target].</span>")
to_chat(user, "<span class='warning'>You have already recruited the maximum number of henchmen.</span>")
if(!in_range(user, target))
to_chat(user, "<span class='warning'>You need to be closer to enthrall [target].</span>")
charge_counter = charge_max
return
if(!target.ckey)
to_chat(usr, "<span class='warning'>The target has no mind.</span>")
to_chat(user, "<span class='warning'>The target has no mind.</span>")
charge_counter = charge_max
return
if(target.stat)
to_chat(usr, "<span class='warning'>The target must be conscious.</span>")
to_chat(user, "<span class='warning'>The target must be conscious.</span>")
charge_counter = charge_max
return
if(!ishuman(target))
to_chat(usr, "<span class='warning'>You can only recruit humans.</span>")
to_chat(user, "<span class='warning'>You can only recruit humans.</span>")
charge_counter = charge_max
return
if(target.mind.assigned_role != "Civilian")
to_chat(usr, "<span class='warning'>You can only recruit Civilians.</span>")
to_chat(user, "<span class='warning'>You can only recruit Civilians.</span>")
if(recruiting)
to_chat(usr, "<span class='danger'>You are already recruiting!</span>")
to_chat(user, "<span class='danger'>You are already recruiting!</span>")
charge_counter = charge_max
return
recruiting = 1
to_chat(usr, "<span class='danger'>This target is valid. You begin the recruiting process.</span>")
to_chat(target, "<span class='userdanger'>[usr] focuses in concentration. Your head begins to ache.</span>")
to_chat(user, "<span class='danger'>This target is valid. You begin the recruiting process.</span>")
to_chat(target, "<span class='userdanger'>[user] focuses in concentration. Your head begins to ache.</span>")
for(var/progress = 0, progress <= 3, progress++)
switch(progress)
if(1)
to_chat(usr, "<span class='notice'>You begin by introducing yourself and explaining what you're about.</span>")
usr.visible_message("<span class='danger'>[usr]'s introduces himself and explains his plans.</span>")
to_chat(user, "<span class='notice'>You begin by introducing yourself and explaining what you're about.</span>")
user.visible_message("<span class='danger'>[user]'s introduces himself and explains his plans.</span>")
if(2)
to_chat(usr, "<span class='notice'>You begin the recruitment of [target].</span>")
usr.visible_message("<span class='danger'>[usr] leans over towards [target], whispering excitedly as he gives a speech.</span>")
to_chat(target, "<span class='danger'>You feel yourself agreeing with [usr], and a surge of loyalty begins building.</span>")
to_chat(user, "<span class='notice'>You begin the recruitment of [target].</span>")
user.visible_message("<span class='danger'>[user] leans over towards [target], whispering excitedly as he gives a speech.</span>")
to_chat(target, "<span class='danger'>You feel yourself agreeing with [user], and a surge of loyalty begins building.</span>")
target.Weaken(12)
sleep(20)
if(isloyal(target))
to_chat(usr, "<span class='notice'>They are enslaved by Nanotrasen. You feel their interest in your cause wane and disappear.</span>")
usr.visible_message("<span class='danger'>[usr] stops talking for a moment, then moves back away from [target].</span>")
to_chat(user, "<span class='notice'>They are enslaved by Nanotrasen. You feel their interest in your cause wane and disappear.</span>")
user.visible_message("<span class='danger'>[user] stops talking for a moment, then moves back away from [target].</span>")
to_chat(target, "<span class='danger'>Your mindshield implant activates, protecting you from conversion.</span>")
return
if(3)
to_chat(usr, "<span class='notice'>You begin filling out the application form with [target].</span>")
usr.visible_message("<span class='danger'>[usr] pulls out a pen and paper and begins filling an application form with [target].</span>")
to_chat(target, "<span class='danger'>You are being convinced by [usr] to fill out an application form to become a henchman.</span>")//Ow the edge
to_chat(user, "<span class='notice'>You begin filling out the application form with [target].</span>")
user.visible_message("<span class='danger'>[user] pulls out a pen and paper and begins filling an application form with [target].</span>")
to_chat(target, "<span class='danger'>You are being convinced by [user] to fill out an application form to become a henchman.</span>")//Ow the edge
if(!do_mob(usr, target, 100)) //around 30 seconds total for enthralling, 45 for someone with a mindshield implant
to_chat(usr, "<span class='danger'>The enrollment process has been interrupted - you have lost the attention of [target].</span>")
to_chat(target, "<span class='warning'>You move away and are no longer under the charm of [usr]. The application form is null and void.</span>")
if(!do_mob(user, target, 100)) //around 30 seconds total for enthralling, 45 for someone with a mindshield implant
to_chat(user, "<span class='danger'>The enrollment process has been interrupted - you have lost the attention of [target].</span>")
to_chat(target, "<span class='warning'>You move away and are no longer under the charm of [user]. The application form is null and void.</span>")
recruiting = 0
return
recruiting = 0
to_chat(usr, "<span class='notice'>You have recruited <b>[target]</b> as your henchman!</span>")
to_chat(target, "<span class='deadsay'><b>You have decided to enroll as a henchman for [usr]. You are now part of the feared 'Greyshirts'.</b></span>")
to_chat(target, "<span class='deadsay'><b>You must follow the orders of [usr], and help him succeed in his dastardly schemes.</span>")
to_chat(target, "<span class='deadsay'>You may not harm other Greyshirt or [usr]. However, you do not need to obey other Greyshirts.</span>")
to_chat(user, "<span class='notice'>You have recruited <b>[target]</b> as your henchman!</span>")
to_chat(target, "<span class='deadsay'><b>You have decided to enroll as a henchman for [user]. You are now part of the feared 'Greyshirts'.</b></span>")
to_chat(target, "<span class='deadsay'><b>You must follow the orders of [user], and help him succeed in his dastardly schemes.</span>")
to_chat(target, "<span class='deadsay'>You may not harm other Greyshirt or [user]. However, you do not need to obey other Greyshirts.</span>")
ticker.mode.greyshirts += target.mind
target.set_species("Human")
head_organ.h_style = "Bald"
+8
View File
@@ -1,7 +1,15 @@
/mob/living/Destroy()
if(ranged_ability)
ranged_ability.remove_ranged_ability(src)
..()
return QDEL_HINT_HARDDEL_NOW
/mob/living/ghostize(can_reenter_corpse = 1)
var/prev_client = client
if(..())
if(ranged_ability && prev_client)
ranged_ability.remove_mousepointer(prev_client)
/mob/living/proc/OpenCraftingMenu()
return
+9 -4
View File
@@ -49,7 +49,12 @@
if(!P.nodamage)
apply_damage(P.damage, P.damage_type, def_zone, armor)
if(P.dismemberment)
check_projectile_dismemberment(P, def_zone)
return P.on_hit(src, armor, def_zone)
/mob/living/proc/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
return 0
/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0)
return 0 //only carbon liveforms have this proc
@@ -86,8 +91,8 @@
if(ismob(I.thrower))
var/mob/M = I.thrower
if(M)
attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been hit with a [I], thrown by [key_name(M)]</font>")
M.attack_log += text("\[[time_stamp()]\] <font color='red'>Hit [key_name(src)] with a thrown [I]</font>")
create_attack_log("<font color='orange'>Has been hit with a [I], thrown by [key_name(M)]</font>")
M.create_attack_log("<font color='red'>Hit [key_name(src)] with a thrown [I]</font>")
if(!istype(src,/mob/living/simple_animal/mouse))
msg_admin_attack("[key_name_admin(src)] was hit by a [I], thrown by [key_name_admin(M)]")
@@ -135,8 +140,8 @@
M.occupant_message("<span class='danger'>You hit [src].</span>")
visible_message("<span class='danger'>[src] has been hit by [M.name].</span>", \
"<span class='userdanger'>[src] has been hit by [M.name].</span>")
attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been attacked by \the [M] controlled by [key_name(M.occupant)] (INTENT: [uppertext(M.occupant.a_intent)])</font>")
M.occupant.attack_log += text("\[[time_stamp()]\] <font color='red'>Attacked [src] with \the [M] (INTENT: [uppertext(M.occupant.a_intent)])</font>")
create_attack_log("<font color='orange'>Has been attacked by \the [M] controlled by [key_name(M.occupant)] (INTENT: [uppertext(M.occupant.a_intent)])</font>")
M.occupant.create_attack_log("<font color='red'>Attacked [src] with \the [M] (INTENT: [uppertext(M.occupant.a_intent)])</font>")
msg_admin_attack("[key_name_admin(M.occupant)] attacked [key_name_admin(src)] with \the [M] (INTENT: [uppertext(M.occupant.a_intent)])")
else
@@ -52,3 +52,5 @@
var/list/surgeries = list() //a list of surgery datums. generally empty, they're added when the player wants them.
var/gene_stability = DEFAULT_GENE_STABILITY
var/obj/effect/proc_holder/ranged_ability //Any ranged ability the mob has, as a click override
+4
View File
@@ -9,6 +9,10 @@
//Vents
if(ventcrawler)
to_chat(src, "<span class='notice'>You can ventcrawl! Use alt+click on vents to quickly travel about the station.</span>")
if(ranged_ability)
ranged_ability.add_ranged_ability(src, "<span class='notice'>You currently have <b>[ranged_ability]</b> active!</span>")
//Should update regardless of if we can ventcrawl, since we can end up in pipes in other ways.
update_pipe_vision()
+2
View File
@@ -1,4 +1,6 @@
/mob/living/Logout()
if(ranged_ability && client)
ranged_ability.remove_mousepointer(client)
..()
if(mind)
if(!key) //key and mind have become seperated. I believe this is for when a staff member aghosts.
+22 -9
View File
@@ -14,6 +14,7 @@ var/list/department_radio_keys = list(
":u" = "Supply", "#u" = "Supply", ".u" = "Supply",
":z" = "Service", "#z" = "Service", ".z" = "Service",
":p" = "AI Private", "#p" = "AI Private", ".p" = "AI Private",
":x" = "cords", "#x" = "cords", ".x" = "cords",
":R" = "right ear", "#R" = "right ear", ".R" = "right ear",
":L" = "left ear", "#L" = "left ear", ".L" = "left ear",
@@ -30,7 +31,8 @@ var/list/department_radio_keys = list(
":Z" = "Service", "#Z" = "Service", ".Z" = "Service",
":P" = "AI Private", "#P" = "AI Private", ".P" = "AI Private",
":-" = "Special Ops", "#-" = "Special Ops", ".-" = "Special Ops",
":_" = "SyndTeam", "#_" = "SyndTeam", "._" = "SyndTeam"
":_" = "SyndTeam", "#_" = "SyndTeam", "._" = "SyndTeam",
":X" = "cords", "#X" = "cords", ".X" = "cords"
)
@@ -106,13 +108,14 @@ proc/get_radio_key_from_channel(var/channel)
return returns
/mob/living/say(var/message, var/datum/language/speaking = null, var/verb = "says", var/alt_name="")
/mob/living/say(var/message, var/datum/language/speaking = null, var/verb = "says", var/alt_name = "", var/sanitize = TRUE, var/ignore_speech_problems = FALSE, var/ignore_atmospherics = FALSE)
if(client)
if(client.prefs.muted & MUTE_IC)
to_chat(src, "<span class='danger'>You cannot speak in IC (Muted).</span>")
return
message = trim_strip_html_properly(message)
if(sanitize)
message = trim_strip_html_properly(message)
if(stat)
if(stat == DEAD)
@@ -146,6 +149,15 @@ proc/get_radio_key_from_channel(var/channel)
if(speaking && (speaking.flags & HIVEMIND))
speaking.broadcast(src,trim(message))
return 1
if(message_mode == "cords")
if(iscarbon(src))
var/mob/living/carbon/C = src
var/obj/item/organ/internal/vocal_cords/V = C.get_int_organ(/obj/item/organ/internal/vocal_cords)
if(V && V.can_speak_with())
C.say(V.handle_speech(message), sanitize = FALSE, ignore_speech_problems = TRUE, ignore_atmospherics = TRUE)
V.speak_with(message) //words come before actions
return 1
verb = say_quote(message, speaking)
@@ -162,7 +174,7 @@ proc/get_radio_key_from_channel(var/channel)
message = handle_autohiss(message, speaking)
if(speaking && !(speaking.flags & NO_STUTTER))
if(!ignore_speech_problems && (speaking && !(speaking.flags & NO_STUTTER)))
var/list/handle_s = handle_speech_problems(message, verb)
message = handle_s[1]
verb = handle_s[2]
@@ -217,12 +229,13 @@ proc/get_radio_key_from_channel(var/channel)
//make sure the air can transmit speech - speaker's side
var/datum/gas_mixture/environment = T.return_air()
var/pressure = environment ? environment.return_pressure() : 0
if(pressure < SOUND_MINIMUM_PRESSURE)
message_range = 1
if(!ignore_atmospherics)
if(pressure < SOUND_MINIMUM_PRESSURE)
message_range = 1
if(pressure < ONE_ATMOSPHERE * 0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet
italics = 1
sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact
if(pressure < ONE_ATMOSPHERE * 0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet
italics = 1
sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact
var/list/hear = hear(message_range, T)
var/list/hearturfs = list()
+2 -2
View File
@@ -219,8 +219,8 @@
playsound(loc, M.attack_sound, 50, 1, 1)
for(var/mob/O in viewers(src, null))
O.show_message("<span class='danger'>[M]</span> [M.attacktext] [src]!", 1)
M.attack_log += text("\[[time_stamp()]\] <font color='red'>attacked [src.name] ([src.ckey])</font>")
src.attack_log += text("\[[time_stamp()]\] <font color='orange'>was attacked by [M.name] ([M.ckey])</font>")
M.create_attack_log("<font color='red'>attacked [src.name] ([src.ckey])</font>")
src.create_attack_log("<font color='orange'>was attacked by [M.name] ([M.ckey])</font>")
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
adjustBruteLoss(damage)
updatehealth()
@@ -204,7 +204,7 @@
modules += new /obj/item/weapon/gripper(src)
modules += new /obj/item/weapon/matter_decompiler(src)
modules += new /obj/item/device/floor_painter(src)
modules += new /obj/item/areaeditor/blueprints/cyborg(src)
emag = new /obj/item/borg/stun(src)
for(var/G in stacktypes) //Attempt to unify Engi-Borg material stacks into fewer lines. See Line 492 for example. Variables changed out of paranoia.
@@ -788,6 +788,7 @@ Pass a positive integer as an argument to override a bot's default speed.
frustration = 0
/mob/living/simple_animal/bot/show_inv()
return
/mob/living/simple_animal/bot/proc/show_controls(mob/M)
users |= M
@@ -143,7 +143,7 @@
target_types += /obj/effect/decal/cleanable/blood/gibs/robot
target_types += /obj/effect/decal/cleanable/crayon
target_types += /obj/effect/decal/cleanable/liquid_fuel
target_types += /obj/effect/decal/cleanable/molten_item
target_types += /obj/effect/decal/cleanable/molten_object
target_types += /obj/effect/decal/cleanable/tomato_smudge
target_types += /obj/effect/decal/cleanable/egg_smudge
target_types += /obj/effect/decal/cleanable/pie_smudge
@@ -0,0 +1,51 @@
/mob/living/simple_animal/cockroach
name = "cockroach"
desc = "This station is just crawling with bugs."
icon_state = "cockroach"
icon_dead = "cockroach"
health = 1
maxHealth = 1
turns_per_move = 5
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 270
maxbodytemp = INFINITY
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
mob_size = MOB_SIZE_TINY
response_help = "pokes"
response_disarm = "shoos"
response_harm = "splats"
density = 0
ventcrawler = 2
gold_core_spawnable = 2
var/squish_chance = 50
loot = list(/obj/effect/decal/cleanable/deadcockroach)
del_on_death = 1
/mob/living/simple_animal/cockroach/death(gibbed)
if(ticker.cinematic) //If the nuke is going off, then cockroaches are invincible. Keeps the nuke from killing them, cause cockroaches are immune to nukes.
return
..()
/mob/living/simple_animal/cockroach/Crossed(var/atom/movable/AM)
if(isliving(AM))
var/mob/living/A = AM
if(A.mob_size > MOB_SIZE_SMALL)
if(prob(squish_chance))
A.visible_message("<span class='notice'>\The [A] squashed \the [name].</span>", "<span class='notice'>You squashed \the [name].</span>")
death()
else
visible_message("<span class='notice'>\The [name] avoids getting crushed.</span>")
else if(istype(AM, /obj/structure))
visible_message("<span class='notice'>As \the [AM] moved over \the [name], it was crushed.</span>")
death()
/mob/living/simple_animal/cockroach/ex_act() //Explosions are a terrible way to handle a cockroach.
return
/obj/effect/decal/cleanable/deadcockroach
name = "cockroach guts"
desc = "One bug squashed. Four more will rise in its place."
icon = 'icons/effects/blood.dmi'
icon_state = "xfloor1"
random_icon_states = list("xfloor1", "xfloor2", "xfloor3", "xfloor4", "xfloor5", "xfloor6", "xfloor7")
anchored = 1
@@ -58,7 +58,7 @@
dat += "<tr><td><B>Back:</B></td><td><A href='?src=[UID()];[inventory_back?"remove_inv":"add_inv"]=back'>[(inventory_back && !(inventory_back.flags&ABSTRACT)) ? inventory_back : "<font color=grey>Empty</font>"]</A></td></tr>"
if(can_collar)
dat += "<tr><td>&nbsp;</td></tr>"
dat += "<tr><td><B>Collar:</B></td><td><A href='?src=[UID()];[collar?"remove_inv":"add_inv"]=collar'>[(collar && !(collar.flags&ABSTRACT)) ? collar : "<font color=grey>Empty</font>"]</A></td></tr>"
dat += "<tr><td><B>Collar:</B></td><td><A href='?src=[UID()];item=[slot_collar]'>[(collar && !(collar.flags&ABSTRACT)) ? collar : "<font color=grey>Empty</font>"]</A></td></tr>"
dat += {"</table>
<A href='?src=[user.UID()];mach_close=mob\ref[src]'>Close</A>
@@ -127,16 +127,16 @@
set desc = "Turn your food into nutrients for plants."
var/list/trays = list()
for(var/obj/machinery/portable_atmospherics/hydroponics/tray in range(1))
for(var/obj/machinery/hydroponics/tray in range(1))
if(tray.nutrilevel < 10)
trays += tray
var/obj/machinery/portable_atmospherics/hydroponics/target = input("Select a tray:") as null|anything in trays
var/obj/machinery/hydroponics/target = input("Select a tray:") as null|anything in trays
if(!src || !target || target.nutrilevel == 10) return //Sanity check.
src.nutrition -= ((10-target.nutrilevel)*5)
target.nutrilevel = 10
target.adjustNutri(10)
src.visible_message("<span class='danger'>[src] secretes a trickle of green liquid from its tail, refilling [target]'s nutrient tray.","\red You secrete a trickle of green liquid from your tail, refilling [target]'s nutrient tray.</span>")
/mob/living/simple_animal/diona/verb/eat_weeds()
@@ -145,16 +145,16 @@
set desc = "Clean the weeds out of soil or a hydroponics tray."
var/list/trays = list()
for(var/obj/machinery/portable_atmospherics/hydroponics/tray in range(1))
for(var/obj/machinery/hydroponics/tray in range(1))
if(tray.weedlevel > 0)
trays += tray
var/obj/machinery/portable_atmospherics/hydroponics/target = input("Select a tray:") as null|anything in trays
var/obj/machinery/hydroponics/target = input("Select a tray:") as null|anything in trays
if(!src || !target || target.weedlevel == 0) return //Sanity check.
src.nutrition += target.weedlevel * 15
target.weedlevel = 0
target.adjustWeeds(-10)
src.visible_message("<span class='danger'>[src] begins rooting through [target], ripping out weeds and eating them noisily.</span>","<span class='danger'>You begin rooting through [target], ripping out weeds and eating them noisily.</span>")
/mob/living/simple_animal/diona/verb/evolve()
@@ -34,7 +34,7 @@
for(var/direction in shuffle(list(1,2,4,8,5,6,9,10)))
var/step = get_step(src, direction)
if(step)
if(locate(/obj/effect/plant) in step)
if(locate(/obj/effect/spacevine) in step)
Move(step, get_dir(src, step))
/mob/living/simple_animal/hostile/retaliate/goat/handle_automated_action()
@@ -47,11 +47,9 @@
LoseTarget()
src.visible_message("\blue [src] calms down.")
if(locate(/obj/effect/plant) in loc)
var/obj/effect/plant/SV = locate(/obj/effect/plant) in loc
qdel(SV)
if(prob(10))
say("Nom")
var/obj/effect/spacevine/SV = locate(/obj/effect/spacevine) in loc
if(SV)
SV.eat(src)
/mob/living/simple_animal/hostile/retaliate/goat/Life()
. = ..()
@@ -66,11 +64,9 @@
/mob/living/simple_animal/hostile/retaliate/goat/Move()
..()
if(!stat)
if(locate(/obj/effect/plant) in loc)
var/obj/effect/plant/SV = locate(/obj/effect/plant) in loc
qdel(SV)
if(prob(10))
say("Nom")
var/obj/effect/spacevine/SV = locate(/obj/effect/spacevine) in loc
if(SV)
SV.eat(src)
/mob/living/simple_animal/hostile/retaliate/goat/attackby(var/obj/item/O as obj, var/mob/user as mob, params)
if(stat == CONSCIOUS && istype(O, /obj/item/weapon/reagent_containers/glass))
@@ -162,6 +158,7 @@
icon_living = "chick"
icon_dead = "chick_dead"
icon_gib = "chick_gib"
gender = FEMALE
speak = list("Cherp.","Cherp?","Chirrup.","Cheep!")
speak_emote = list("cheeps")
emote_hear = list("cheeps")
@@ -205,9 +202,10 @@ var/global/chicken_count = 0
/mob/living/simple_animal/chicken
name = "\improper chicken"
desc = "Hopefully the eggs are good this season."
icon_state = "chicken"
icon_living = "chicken"
icon_dead = "chicken_dead"
gender = FEMALE
icon_state = "chicken_brown"
icon_living = "chicken_brown"
icon_dead = "chicken_brown_dead"
speak = list("Cluck!","BWAAAAARK BWAK BWAK BWAK!","Bwaak bwak.")
speak_emote = list("clucks","croons")
emote_hear = list("clucks")
@@ -216,62 +214,68 @@ var/global/chicken_count = 0
speak_chance = 2
turns_per_move = 3
butcher_results = list(/obj/item/weapon/reagent_containers/food/snacks/meat = 2)
var/egg_type = /obj/item/weapon/reagent_containers/food/snacks/egg
var/food_type = /obj/item/weapon/reagent_containers/food/snacks/grown/wheat
response_help = "pets the"
response_disarm = "gently pushes aside the"
response_harm = "kicks the"
attacktext = "kicks"
health = 10
maxHealth = 10
health = 15
maxHealth = 15
ventcrawler = 2
var/eggsleft = 0
var/chicken_color
var/eggsFertile = TRUE
var/body_color
var/icon_prefix = "chicken"
pass_flags = PASSTABLE | PASSMOB
mob_size = MOB_SIZE_SMALL
can_hide = 1
can_collar = 1
var/list/feedMessages = list("It clucks happily.","It clucks happily.")
var/list/layMessage = list("lays an egg.","squats down and croons.","begins making a huge racket.","begins clucking raucously.")
var/list/validColors = list("brown","black","white")
gold_core_spawnable = CHEM_MOB_SPAWN_FRIENDLY
/mob/living/simple_animal/chicken/New()
..()
if(!chicken_color)
chicken_color = pick( list("brown","black","white") )
icon_state = "chicken_[chicken_color]"
icon_living = "chicken_[chicken_color]"
icon_dead = "chicken_[chicken_color]_dead"
if(!body_color)
body_color = pick(validColors)
icon_state = "[icon_prefix]_[body_color]"
icon_living = "[icon_prefix]_[body_color]"
icon_dead = "[icon_prefix]_[body_color]_dead"
pixel_x = rand(-6, 6)
pixel_y = rand(0, 10)
chicken_count += 1
/mob/living/simple_animal/chicken/death(gibbed)
..()
..(gibbed)
chicken_count -= 1
/mob/living/simple_animal/chicken/attackby(var/obj/item/O as obj, var/mob/user as mob, params)
if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/grown)) //feedin' dem chickens
var/obj/item/weapon/reagent_containers/food/snacks/grown/G = O
if(G.seed.kitchen_tag == "wheat")
if(!stat && eggsleft < 8)
user.visible_message("\blue [user] feeds [O] to [name]! It clucks happily.","\blue You feed [O] to [name]! It clucks happily.")
user.drop_item()
qdel(O)
eggsleft += rand(1, 4)
// to_chat(world, eggsleft)
else
to_chat(user, "\blue [name] doesn't seem hungry!")
/mob/living/simple_animal/chicken/attackby(obj/item/O, mob/user, params)
if(istype(O, food_type)) //feedin' dem chickens
if(!stat && eggsleft < 8)
var/feedmsg = "[user] feeds [O] to [name]! [pick(feedMessages)]"
user.visible_message(feedmsg)
user.drop_item()
qdel(O)
eggsleft += rand(1, 4)
//world << eggsleft
else
to_chat(user, "\blue [name] doesn't seem interested in [O]!")
to_chat(user, "<span class='warning'>[name] doesn't seem hungry!</span>")
else
..()
/mob/living/simple_animal/chicken/Life()
. = ..()
if(. && prob(3) && eggsleft > 0)
visible_message("[src] [pick("lays an egg.","squats down and croons.","begins making a huge racket.","begins clucking raucously.")]")
if((. && prob(3) && eggsleft > 0) && egg_type)
visible_message("[src] [pick(layMessage)]")
eggsleft--
var/obj/item/weapon/reagent_containers/food/snacks/egg/E = new(get_turf(src))
var/obj/item/E = new egg_type(get_turf(src))
E.pixel_x = rand(-6,6)
E.pixel_y = rand(-6,6)
if(chicken_count < MAX_CHICKENS && prob(10))
processing_objects.Add(E)
if(eggsFertile)
if(chicken_count < MAX_CHICKENS && prob(25))
processing_objects.Add(E)
/obj/item/weapon/reagent_containers/food/snacks/egg/var/amount_grown = 0
/obj/item/weapon/reagent_containers/food/snacks/egg/process()
@@ -5,9 +5,9 @@
#define BEE_TRAY_RECENT_VISIT 200 //How long in deciseconds until a tray can be visited by a bee again
#define BEE_DEFAULT_COLOUR "#e5e500" //the colour we make the stripes of the bee if our reagent has no colour (or we have no reagent)
#define BEE_POLLINATE_YIELD_CHANCE 10
#define BEE_POLLINATE_YIELD_CHANCE 33
#define BEE_POLLINATE_PEST_CHANCE 33
#define BEE_POLLINATE_POTENTCY_CHANCE 50
#define BEE_POLLINATE_POTENCY_CHANCE 50
/mob/living/simple_animal/hostile/poison/bees
name = "bee"
@@ -15,6 +15,7 @@
icon_state = ""
icon_living = ""
icon = 'icons/mob/bees.dmi'
gender = FEMALE
speak_emote = list("buzzes")
emote_hear = list("buzzes")
turns_per_move = 0
@@ -142,7 +143,7 @@
if(beehome.bees)
beehome.bees.Remove(src)
beehome = null
..()
return ..()
/mob/living/simple_animal/hostile/poison/bees/worker/death(gibbed)
if(beehome)
@@ -158,10 +159,10 @@
to_chat(user, "<span class='warning'>This bee is homeless!</span>")
/mob/living/simple_animal/hostile/poison/bees/worker/Found(atom/A)
if(istype(A, /obj/machinery/portable_atmospherics/hydroponics))
var/obj/machinery/portable_atmospherics/hydroponics/Hydro = A
if(Hydro.seed && !Hydro.dead && !Hydro.recent_bee_visit && !Hydro.closed_system)
wanted_objects |= /obj/machinery/portable_atmospherics/hydroponics //so we only hunt them while they're alive/seeded/not visisted and uncovered
if(istype(A, /obj/machinery/hydroponics))
var/obj/machinery/hydroponics/Hydro = A
if(Hydro.myseed && !Hydro.dead && !Hydro.recent_bee_visit)
wanted_objects |= /obj/machinery/hydroponics //so we only hunt them while they're alive/seeded/not visisted
return 1
..()
@@ -175,24 +176,24 @@
/mob/living/simple_animal/hostile/poison/bees/worker/AttackingTarget()
//Pollinate
if(istype(target, /obj/machinery/portable_atmospherics/hydroponics))
var/obj/machinery/portable_atmospherics/hydroponics/Hydro = target
if(istype(target, /obj/machinery/hydroponics))
var/obj/machinery/hydroponics/Hydro = target
pollinate(Hydro)
else if(target == beehome)
var/obj/structure/beebox/BB = target
forceMove(BB)
target = null
wanted_objects.Remove(/obj/structure/beebox) //so we don't attack beeboxes when not going home
wanted_objects -= /obj/structure/beebox //so we don't attack beeboxes when not going home
else
..()
/mob/living/simple_animal/hostile/poison/bees/worker/proc/pollinate(obj/machinery/portable_atmospherics/hydroponics/Hydro)
if(!istype(Hydro) || !Hydro.seed || Hydro.dead || Hydro.recent_bee_visit || Hydro.closed_system)
/mob/living/simple_animal/hostile/poison/bees/worker/proc/pollinate(obj/machinery/hydroponics/Hydro)
if(!istype(Hydro) || !Hydro.myseed || Hydro.dead || Hydro.recent_bee_visit)
target = null
return
target = null //so we pick a new hydro tray next FindTarget(), instead of loving the same plant for eternity
wanted_objects.Remove(/obj/machinery/portable_atmospherics/hydroponics) //so we only hunt them while they're alive/seeded/not visisted
wanted_objects -= /obj/machinery/hydroponics //so we only hunt them while they're alive/seeded/not visisted
Hydro.recent_bee_visit = TRUE
spawn(BEE_TRAY_RECENT_VISIT)
if(Hydro)
@@ -200,23 +201,14 @@
var/growth = health //Health also means how many bees are in the swarm, roughly.
//better healthier plants!
Hydro.health += round(growth*0.5)
Hydro.adjustHealth(growth*0.5)
if(prob(BEE_POLLINATE_PEST_CHANCE))
Hydro.pestlevel = max(0, --Hydro.pestlevel)
if(prob(BEE_POLLINATE_YIELD_CHANCE)) //Yield mod is HELLA powerful, but quite rare
if(!isnull(plant_controller.seeds[Hydro.seed.name]))
Hydro.seed = Hydro.seed.diverge()
else
Hydro.seed.update_name_prefixes()
var/seed_yield = Hydro.seed.get_trait(TRAIT_YIELD)
Hydro.seed.set_trait(TRAIT_YIELD, seed_yield + 1, 10, 0)
if(prob(BEE_POLLINATE_POTENTCY_CHANCE))
if(!isnull(plant_controller.seeds[Hydro.seed.name]))
Hydro.seed = Hydro.seed.diverge()
else
Hydro.seed.update_name_prefixes()
var/seed_potency = Hydro.seed.get_trait(TRAIT_POTENCY)
Hydro.seed.set_trait(TRAIT_POTENCY, seed_potency + 1, 200, 0)
Hydro.adjustPests(-10)
if(prob(BEE_POLLINATE_YIELD_CHANCE))
Hydro.myseed.adjust_yield(1)
Hydro.yieldmod = 2
if(prob(BEE_POLLINATE_POTENCY_CHANCE))
Hydro.myseed.adjust_potency(1)
if(beehome)
beehome.bee_resources = min(beehome.bee_resources + growth, 100)
@@ -234,7 +226,7 @@
idle = max(0, --idle)
if(idle <= BEE_IDLE_GOHOME && prob(BEE_PROB_GOHOME))
if(!FindTarget())
wanted_objects.Add(/obj/structure/beebox) //so we don't attack beeboxes when not going home
wanted_objects += /obj/structure/beebox //so we don't attack beeboxes when not going home
target = beehome
if(!beehome) //add outselves to a beebox (of the same reagent) if we have no home
for(var/obj/structure/beebox/BB in view(vision_range, src))
@@ -304,6 +296,7 @@
/obj/item/queen_bee/Destroy()
qdel(queen)
queen = null
return ..()
@@ -1,6 +1,5 @@
/mob/living/simple_animal/hostile
faction = list("hostile")
mouse_opacity = 2 //This makes it easier to hit hostile mobs, you only need to click on their tile, and is set back to 1 when they die
stop_automated_movement_when_pulled = 0
environment_smash = 1 //Set to 1 to break closets,tables,racks, etc; 2 for walls; 3 for rwalls
var/atom/target
@@ -13,7 +12,8 @@
var/list/friends = list()
var/ranged_message = "fires" //Fluff text for ranged mobs
var/ranged_cooldown = 0 //What the starting cooldown is on ranged attacks
var/ranged_cooldown_cap = 3 //What ranged attacks, after being used are set to, to go back on cooldown, defaults to 3 life() ticks
var/ranged_cooldown_time = 30 //How long, in deciseconds, the cooldown of ranged attacks is
var/ranged_ignores_vision = FALSE //if it'll fire ranged attacks even if it lacks vision on its target, only works with environment smash
var/check_friendly_fire = 0 // Should the ranged mob check for friendlies when shooting
var/retreat_distance = null //If our mob runs from players when they're too close, set in tile distance. By default, mobs do not retreat.
var/minimum_distance = 1 //Minimum approach distance, so ranged mobs chase targets down, but still keep their distance set in tiles to the target, set higher to make mobs keep distance
@@ -30,11 +30,33 @@
var/attack_same = 0 //Set us to 1 to allow us to attack our own faction, or 2, to only ever attack our own faction
var/AIStatus = AI_ON //The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever)
//typecache of things this mob will attack in DestroySurroundings() if it has environment_smash
var/list/environment_target_typecache = list(
/obj/machinery/door/window,
/obj/structure/window,
/obj/structure/closet,
/obj/structure/table,
/obj/structure/grille,
/obj/structure/girder,
/obj/structure/rack,
/obj/structure/barricade) //turned into a typecache in New()
var/atom/targets_from = null //all range/attack/etc. calculations should be done from this atom, defaults to the mob itself, useful for Vehicles and such
var/list/emote_taunt = list()
var/taunt_chance = 0
/mob/living/simple_animal/hostile/New()
..()
if(!targets_from)
targets_from = src
environment_target_typecache = typecacheof(environment_target_typecache)
/mob/living/simple_animal/hostile/Destroy()
targets_from = null
return ..()
/mob/living/simple_animal/hostile/Life()
. = ..()
if(ranged)
ranged_cooldown--
if(!.)
walk(src, 0)
return 0
@@ -58,76 +80,89 @@
if(AIShouldSleep(possible_targets)) // we try to acquire a new one
AIStatus = AI_IDLE // otherwise we go idle
return 1
/mob/living/simple_animal/hostile/attacked_by(obj/item/I, mob/living/user)
if(stat == CONSCIOUS && !target && AIStatus != AI_OFF && !client && user)
FindTarget(list(user), 1)
return ..()
/mob/living/simple_animal/hostile/bullet_act(obj/item/projectile/P)
if(stat == CONSCIOUS && !target && AIStatus != AI_OFF && !client)
if(P.firer && get_dist(src, P.firer) <= aggro_vision_range)
FindTarget(list(P.firer), 1)
Goto(P.starting, move_to_delay, 3)
return ..()
//////////////HOSTILE MOB TARGETTING AND AGGRESSION////////////
/mob/living/simple_animal/hostile/proc/ListTargets()//Step 1, find out what we can see
var/list/L = list()
. = list()
if(!search_objects)
var/list/Mobs = hearers(vision_range, src) - src //Remove self, so we don't suicide
L += Mobs
for(var/obj/mecha/M in mechas_list)
if(get_dist(M, src) <= vision_range && can_see(src, M, vision_range))
L += M
for(var/obj/spacepod/S in spacepods_list)
if(get_dist(S, src) <= vision_range && can_see(src, S, vision_range))
L += S
var/list/Mobs = hearers(vision_range, targets_from) - src //Remove self, so we don't suicide
. += Mobs
var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha, /obj/spacepod))
for(var/HM in typecache_filter_list(range(vision_range, targets_from), hostile_machines))
if(can_see(targets_from, HM, vision_range))
. += HM
else
var/list/Objects = oview(vision_range, src)
L += Objects
return L
var/list/Objects = oview(vision_range, targets_from)
. += Objects
/mob/living/simple_animal/hostile/proc/FindTarget(var/list/possible_targets, var/HasTargetsList = 0)//Step 2, filter down possible targets to things we actually care about
var/list/Targets = list()
. = list()
if(!HasTargetsList)
possible_targets = ListTargets()
for(var/atom/A in possible_targets)
for(var/pos_targ in possible_targets)
var/atom/A = pos_targ
if(Found(A))//Just in case people want to override targetting
Targets = list(A)
. = list(A)
break
if(CanAttack(A))//Can we attack it?
Targets += A
. += A
continue
var/Target = PickTarget(Targets)
var/Target = PickTarget(.)
GiveTarget(Target)
return Target //We now have a target
/mob/living/simple_animal/hostile/proc/PossibleThreats()
. = list()
for(var/pos_targ in ListTargets())
var/atom/A = pos_targ
if(Found(A))
. = list(A)
break
if(CanAttack(A))
. += A
continue
/mob/living/simple_animal/hostile/proc/Found(var/atom/A)//This is here as a potential override to pick a specific target if available
return
/mob/living/simple_animal/hostile/proc/PickTarget(var/list/Targets)//Step 3, pick amongst the possible, attackable targets
if(!Targets.len)//We didnt find nothin!
return
/mob/living/simple_animal/hostile/proc/PickTarget(list/Targets)//Step 3, pick amongst the possible, attackable targets
if(target != null)//If we already have a target, but are told to pick again, calculate the lowest distance between all possible, and pick from the lowest distance targets
for(var/atom/A in Targets)
var/target_dist = get_dist(src, target)
var/possible_target_distance = get_dist(src, A)
for(var/pos_targ in Targets)
var/atom/A = pos_targ
var/target_dist = get_dist(targets_from, target)
var/possible_target_distance = get_dist(targets_from, A)
if(target_dist < possible_target_distance)
Targets -= A
var/chosen_target = safepick(Targets)//Pick the remaining targets (if any) at random
if(!Targets.len)//We didnt find nothin!
return
var/chosen_target = pick(Targets)//Pick the remaining targets (if any) at random
return chosen_target
/mob/living/simple_animal/hostile/CanAttack(var/atom/the_target)//Can we actually attack a possible target?
if(!the_target)
return 0
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
return 0
if(search_objects < 2)
if(istype(the_target, /obj/mecha))
var/obj/mecha/M = the_target
if(M.occupant)//Just so we don't attack empty mechs
if(CanAttack(M.occupant))
return 1
if(istype(the_target, /obj/spacepod))
var/obj/spacepod/S = the_target
if(S.pilot) //Just so we don't attack empty pods
if(CanAttack(S.pilot))
return 1
if(isliving(the_target))
var/mob/living/L = the_target
var/faction_check = 0
for(var/F in faction)
if(F in L.faction)
faction_check = 1
break
var/faction_check = faction_check(L)
if(robust_searching)
if(L.stat > stat_attack || L.stat != stat_attack && stat_exclusive == 1)
return 0
@@ -141,14 +176,42 @@
if(faction_check && !attack_same)
return 0
return 1
if(ishuman(the_target))
var/mob/living/carbon/human/H = the_target
if(is_type_in_list(src, H.species.ignored_by))
return 0
if(istype(the_target, /obj/mecha))
var/obj/mecha/M = the_target
if(M.occupant)//Just so we don't attack empty mechs
if(CanAttack(M.occupant))
return 1
if(istype(the_target, /obj/spacepod))
var/obj/spacepod/S = the_target
if(S.pilot) //Just so we don't attack empty pods
if(CanAttack(S.pilot))
return 1
if(istype(the_target, /obj/machinery/porta_turret))
var/obj/machinery/porta_turret/P = the_target
if(P.faction in faction)
return 0
if(!P.raised) //Don't attack invincible turrets
return 0
if(P.stat & BROKEN) //Or turrets that are already broken
return 0
return 1
if(isobj(the_target))
if(is_type_in_list(the_target, wanted_objects))
return 1
return 0
/mob/living/simple_animal/hostile/proc/GiveTarget(var/new_target)//Step 4, give us our selected target
/mob/living/simple_animal/hostile/proc/GiveTarget(new_target)//Step 4, give us our selected target
target = new_target
if(target != null)
Aggro()
return 1
/mob/living/simple_animal/hostile/proc/MoveToTarget(var/list/possible_targets)//Step 5, handle movement between us and our target
@@ -157,38 +220,45 @@
LoseTarget()
return 0
if(target in possible_targets)
var/target_distance = get_dist(src,target)
if(ranged)//We ranged? Shoot at em
if(target_distance >= 2 && ranged_cooldown <= 0)//But make sure they're a tile away at least, and our range attack is off cooldown
if(target.z != z)
LoseTarget()
return 0
var/target_distance = get_dist(targets_from,target)
if(ranged) //We ranged? Shoot at em
if(!target.Adjacent(targets_from) && ranged_cooldown <= world.time) //But make sure they're not in range for a melee attack and our range attack is off cooldown
OpenFire(target)
if(retreat_distance != null)//If we have a retreat distance, check if we need to run from our target
if(target_distance <= retreat_distance)//If target's closer than our retreat distance, run
if(retreat_distance != null) //If we have a retreat distance, check if we need to run from our target
if(target_distance <= retreat_distance) //If target's closer than our retreat distance, run
walk_away(src,target,retreat_distance,move_to_delay)
else
Goto(target,move_to_delay,minimum_distance)//Otherwise, get to our minimum distance so we chase them
Goto(target,move_to_delay,minimum_distance) //Otherwise, get to our minimum distance so we chase them
else
Goto(target,move_to_delay,minimum_distance)
if(isturf(loc) && target.Adjacent(src)) //If they're next to us, attack
AttackingTarget()
return 1
if(target)
if(targets_from && isturf(targets_from.loc) && target.Adjacent(targets_from)) //If they're next to us, attack
AttackingTarget()
return 1
return 0
if(environment_smash)
if(target.loc != null && get_dist(src, target.loc) <= vision_range)//We can't see our target, but he's in our vision range still
if(environment_smash >= 2)//If we're capable of smashing through walls, forget about vision completely after finding our target
if(target.loc != null && get_dist(targets_from, target.loc) <= vision_range) //We can't see our target, but he's in our vision range still
if(ranged_ignores_vision && ranged_cooldown <= world.time) //we can't see our target... but we can fire at them!
OpenFire(target)
if(environment_smash >= 2) //If we're capable of smashing through walls, forget about vision completely after finding our target
Goto(target,move_to_delay,minimum_distance)
FindHidden()
return 1
else
if(FindHidden())
return 1
LostTarget()
LoseTarget()
return 0
/mob/living/simple_animal/hostile/proc/Goto(var/target, var/delay, var/minimum_distance)
/mob/living/simple_animal/hostile/proc/Goto(target, delay, minimum_distance)
walk_to(src, target, minimum_distance, delay)
/mob/living/simple_animal/hostile/adjustHealth(damage)
..(damage)
if(!stat && search_objects < 3)//Not unconscious, and we don't ignore mobs
. = ..()
if(!ckey && !stat && search_objects < 3 && damage > 0)//Not unconscious, and we don't ignore mobs
if(search_objects)//Turn off item searching and ignore whatever item we were looking at, we're more concerned with fight or flight
search_objects = 0
target = null
@@ -203,101 +273,102 @@
/mob/living/simple_animal/hostile/proc/Aggro()
vision_range = aggro_vision_range
if(target && emote_taunt.len && prob(taunt_chance))
emote("me", 1, "[pick(emote_taunt)] at [target].")
taunt_chance = max(taunt_chance-7,2)
/mob/living/simple_animal/hostile/proc/LoseAggro()
stop_automated_movement = 0
vision_range = idle_vision_range
taunt_chance = initial(taunt_chance)
/mob/living/simple_animal/hostile/proc/LoseTarget()
target = null
walk(src, 0)
LoseAggro()
/mob/living/simple_animal/hostile/proc/LostTarget()
walk(src, 0)
LoseAggro()
//////////////END HOSTILE MOB TARGETTING AND AGGRESSION////////////
/mob/living/simple_animal/hostile/death(gibbed)
LoseAggro()
mouse_opacity = 1
..()
walk(src, 0)
LoseTarget()
..(gibbed)
/mob/living/simple_animal/hostile/proc/summon_backup(distance)
do_alert_animation(src)
playsound(loc, 'sound/machines/chime.ogg', 50, 1, -1)
for(var/mob/living/simple_animal/hostile/M in oview(distance, targets_from))
var/list/L = M.faction&faction
if(L.len)
if(M.AIStatus == AI_OFF)
return
else
M.Goto(src,M.move_to_delay,M.minimum_distance)
/mob/living/simple_animal/hostile/proc/OpenFire(var/the_target)
var/target = the_target
/mob/living/simple_animal/hostile/proc/OpenFire(atom/A)
if(check_friendly_fire)
for(var/turf/T in getline(src, target)) // Not 100% reliable but this is faster than simulating actual trajectory
for(var/turf/T in getline(src,A)) // Not 100% reliable but this is faster than simulating actual trajectory
for(var/mob/living/L in T)
if(L == src || L == target)
if(L == src || L == A)
continue
if(faction_check(L) && !attack_same)
return
visible_message("<span class='danger'><b>[src]</b> [ranged_message] at [target]!</span>")
visible_message("<span class='danger'><b>[src]</b> [ranged_message] at [A]!</span>")
if(rapid)
spawn(1)
Shoot(target, src.loc, src)
if(casingtype)
new casingtype(get_turf(src))
Shoot(A)
spawn(4)
Shoot(target, src.loc, src)
if(casingtype)
new casingtype(get_turf(src))
Shoot(A)
spawn(6)
Shoot(target, src.loc, src)
if(casingtype)
new casingtype(get_turf(src))
Shoot(A)
else
Shoot(target, src.loc, src)
if(casingtype)
new casingtype
ranged_cooldown = ranged_cooldown_cap
return
Shoot(A)
ranged_cooldown = world.time + ranged_cooldown_time
/mob/living/simple_animal/hostile/proc/Shoot(var/target, var/start, var/user, var/bullet = 0)
if(target == start)
/mob/living/simple_animal/hostile/proc/Shoot(atom/targeted_atom)
if(targeted_atom == targets_from.loc || targeted_atom == targets_from)
return
var/turf/startloc = get_turf(targets_from)
if(casingtype)
var/obj/item/ammo_casing/casing = new casingtype
var/obj/item/ammo_casing/casing = new casingtype(startloc)
playsound(src, projectilesound, 100, 1)
casing.fire(target, src, zone_override = ran_zone())
casing.loc = loc
else
var/obj/item/projectile/A = new projectiletype(loc)
playsound(user, projectilesound, 100, 1)
A.current = target
A.firer = src
A.yo = target:y - start:y
A.xo = target:x - start:x
if(AIStatus == AI_OFF)//Don't want mindless mobs to have their movement screwed up firing in space
newtonian_move(get_dir(target, user))
A.original = target
A.fire()
return A
casing.fire(targeted_atom, src, zone_override = ran_zone())
else if(projectiletype)
var/obj/item/projectile/P = new projectiletype(startloc)
playsound(src, projectilesound, 100, 1)
P.current = startloc
P.starting = startloc
P.firer = src
P.yo = targeted_atom.y - startloc.y
P.xo = targeted_atom.x - startloc.x
if(AIStatus != AI_ON)//Don't want mindless mobs to have their movement screwed up firing in space
newtonian_move(get_dir(targeted_atom, targets_from))
P.original = targeted_atom
P.fire()
return P
/mob/living/simple_animal/hostile/proc/DestroySurroundings()
if(environment_smash)
EscapeConfinement()
for(var/dir in cardinal)
var/turf/T = get_step(src, dir)
if(istype(T, /turf/simulated/wall) || istype(T, /turf/simulated/mineral))
if(T.Adjacent(src))
var/turf/T = get_step(targets_from, dir)
if(iswallturf(T) || ismineralturf(T))
if(T.Adjacent(targets_from))
T.attack_animal(src)
for(var/atom/A in T)
if(!A.Adjacent(src))
for(var/a in T)
var/atom/A = a
if(!A.Adjacent(targets_from))
continue
if(istype(A, /obj/structure/window) || istype(A, /obj/structure/closet) || istype(A, /obj/structure/table) || istype(A, /obj/structure/grille) || istype(A, /obj/structure/rack))
if(is_type_in_typecache(A, environment_target_typecache))
A.attack_animal(src)
return
/mob/living/simple_animal/hostile/proc/EscapeConfinement()
if(buckled)
buckled.attack_animal(src)
if(!isturf(src.loc) && src.loc != null)//Did someone put us in something?
var/atom/A = src.loc
if(!isturf(targets_from.loc) && targets_from.loc != null)//Did someone put us in something?
var/atom/A = get_turf(targets_from)
A.attack_animal(src)//Bang on it till we get out
return
@@ -305,12 +376,12 @@
if(istype(target.loc, /obj/structure/closet) || istype(target.loc, /obj/machinery/disposal) || istype(target.loc, /obj/machinery/sleeper) || istype(target.loc, /obj/machinery/bodyscanner) || istype(target.loc, /obj/machinery/recharge_station))
var/atom/A = target.loc
Goto(A,move_to_delay,minimum_distance)
if(A.Adjacent(src))
if(A.Adjacent(targets_from))
A.attack_animal(src)
return 1
/mob/living/simple_animal/hostile/RangedAttack(var/atom/A, var/params) //Player firing
if(ranged && ranged_cooldown <= 0)
/mob/living/simple_animal/hostile/RangedAttack(atom/A, params) //Player firing
if(ranged && ranged_cooldown <= world.time)
target = A
OpenFire(A)
..()
@@ -0,0 +1,393 @@
#define MEDAL_PREFIX "Bubblegum"
/*
BUBBLEGUM
Bubblegum spawns randomly wherever a lavaland creature is able to spawn. It is the most powerful slaughter demon in existence.
Bubblegum's footsteps are heralded by shaking booms, proving its tremendous size.
It acts as a melee creature, chasing down and attacking its target while also using different attacks to augment its power that increase as it takes damage.
It tries to strike at its target through any bloodpools under them; if it fails to do that, it will spray blood and then attempt to warp to a bloodpool near the target.
If it fails to warp to a target, it may summon up to 6 slaughterlings from the blood around it.
If it does not summon all 6 slaughterlings, it will instead charge at its target, dealing massive damage to anything it hits and spraying a stream of blood.
At half health, it will either charge three times or warp, then charge, instead of doing a single charge.
When Bubblegum dies, it leaves behind a chest that can contain three things:
1. A bottle that, when activated, drives everyone nearby into a frenzy
2. A contract that marks for death the chosen target
3. A spellblade that can slice off limbs at range
Difficulty: Hard
*/
/mob/living/simple_animal/hostile/megafauna/bubblegum
name = "bubblegum"
desc = "In what passes for a heirarchy among slaughter demons, this one is king."
health = 2500
maxHealth = 2500
attacktext = "rends"
attack_sound = 'sound/misc/demon_attack1.ogg'
icon_state = "bubblegum"
icon_living = "bubblegum"
icon_dead = ""
friendly = "stares down"
icon = 'icons/mob/lavaland/96x96megafauna.dmi'
speak_emote = list("gurgles")
armour_penetration = 40
melee_damage_lower = 40
melee_damage_upper = 40
speed = 1
move_to_delay = 10
ranged = 1
pixel_x = -32
del_on_death = 1
loot = list(/obj/structure/closet/crate/necropolis/bubblegum)
var/charging = 0
medal_type = MEDAL_PREFIX
score_type = BUBBLEGUM_SCORE
deathmessage = "sinks into a pool of blood, fleeing the battle. You've won, for now... "
death_sound = 'sound/misc/enter_blood.ogg'
/obj/item/device/gps/internal/bubblegum
icon_state = null
gpstag = "Bloody Signal"
desc = "You're not quite sure how a signal can be bloody."
invisibility = 100
/mob/living/simple_animal/hostile/megafauna/bubblegum/adjustBruteLoss(amount)
if(amount > 0 && prob(25))
var/obj/effect/decal/cleanable/blood/gibs/bubblegum/B = new /obj/effect/decal/cleanable/blood/gibs/bubblegum(loc)
if(prob(40))
step(B, pick(cardinal))
else
B.dir = pick(cardinal)
. = ..()
/obj/effect/decal/cleanable/blood/gibs/bubblegum
name = "thick blood"
desc = "Thick, splattered blood."
random_icon_states = list("gib3", "gib5", "gib6")
amount = 20
/obj/effect/decal/cleanable/blood/gibs/bubblegum/can_bloodcrawl_in()
return TRUE
/mob/living/simple_animal/hostile/megafauna/bubblegum/Life()
..()
move_to_delay = Clamp((health/maxHealth) * 10, 5, 10)
/mob/living/simple_animal/hostile/megafauna/bubblegum/OpenFire()
anger_modifier = Clamp(((maxHealth - health)/60),0,20)
if(charging)
return
ranged_cooldown = world.time + ranged_cooldown_time
var/warped = FALSE
if(!try_bloodattack())
spawn(0)
blood_spray()
warped = blood_warp()
if(warped && prob(100 - anger_modifier))
return
if(prob(90 - anger_modifier) || slaughterlings())
if(health > maxHealth * 0.5)
spawn(0)
charge()
else
if(prob(70) || warped)
spawn(0)
triple_charge()
else
spawn(0)
warp_charge()
/mob/living/simple_animal/hostile/megafauna/bubblegum/New()
..()
for(var/mob/living/simple_animal/hostile/megafauna/bubblegum/B in mob_list)
if(B != src)
qdel(src) //There can be only one
break
var/obj/effect/proc_holder/spell/bloodcrawl/bloodspell = new
AddSpell(bloodspell)
if(istype(loc, /obj/effect/dummy/slaughter))
bloodspell.phased = 1
internal_gps = new/obj/item/device/gps/internal/bubblegum(src)
/mob/living/simple_animal/hostile/megafauna/bubblegum/do_attack_animation(atom/A, visual_effect_icon)
if(!charging)
..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/AttackingTarget()
if(!charging)
..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/Goto(target, delay, minimum_distance)
if(!charging)
..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/Move()
if(charging)
new /obj/effect/overlay/temp/decoy/fading(loc, src)
DestroySurroundings()
. = ..()
if(!stat && .)
playsound(src, 'sound/effects/meteorimpact.ogg', 200, 1, 2, 1)
if(charging)
DestroySurroundings()
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/warp_charge()
blood_warp()
charge()
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/triple_charge()
charge()
charge()
charge()
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge()
var/turf/T = get_turf(target)
if(!T || T == loc)
return
new /obj/effect/overlay/temp/dragon_swoop(T)
charging = 1
DestroySurroundings()
walk(src, 0)
dir = get_dir(src, T)
var/obj/effect/overlay/temp/decoy/D = new /obj/effect/overlay/temp/decoy(loc, src)
animate(D, alpha = 0, color = "#FF0000", transform = matrix()*2, time = 5)
sleep(5)
throw_at(T, get_dist(src, T), 1, src, 0)
charging = 0
try_bloodattack()
if(target)
Goto(target, move_to_delay, minimum_distance)
/mob/living/simple_animal/hostile/megafauna/bubblegum/Bump(atom/A)
if(charging)
if(isturf(A) || isobj(A) && A.density)
A.ex_act(2)
DestroySurroundings()
..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/throw_impact(atom/A)
if(!charging)
return ..()
else if(isliving(A))
var/mob/living/L = A
L.visible_message("<span class='danger'>[src] slams into [L]!</span>", "<span class='userdanger'>[src] slams into you!</span>")
L.apply_damage(40, BRUTE)
playsound(get_turf(L), 'sound/effects/meteorimpact.ogg', 100, 1)
shake_camera(L, 4, 3)
shake_camera(src, 2, 3)
var/throwtarget = get_edge_target_turf(src, get_dir(src, get_step_away(L, src)))
L.throw_at_fast(throwtarget, 3)
charging = 0
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_mobs_on_blood()
var/list/targets = ListTargets()
. = list()
for(var/mob/living/L in targets)
var/list/bloodpool = get_pools(get_turf(L), 0)
if(bloodpool.len && (!faction_check(L) || L.stat == DEAD))
. += L
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/try_bloodattack()
var/list/targets = get_mobs_on_blood()
if(targets.len)
spawn(0)
bloodattack(targets, prob(50))
return TRUE
return FALSE
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodattack(list/targets, handedness)
var/mob/living/target_one = pick_n_take(targets)
var/turf/target_one_turf = get_turf(target_one)
var/mob/living/target_two
if(targets.len)
target_two = pick_n_take(targets)
var/turf/target_two_turf = get_turf(target_two)
if(target_two.stat != CONSCIOUS || prob(10))
bloodgrab(target_two_turf, handedness)
else
bloodsmack(target_two_turf, handedness)
if(target_one)
var/list/pools = get_pools(get_turf(target_one), 0)
if(pools.len)
target_one_turf = get_turf(target_one)
if(target_one_turf)
if(target_one.stat != CONSCIOUS || prob(10))
bloodgrab(target_one_turf, !handedness)
else
bloodsmack(target_one_turf, !handedness)
if(!target_two && target_one)
var/list/poolstwo = get_pools(get_turf(target_one), 0)
if(poolstwo.len)
target_one_turf = get_turf(target_one)
if(target_one_turf)
if(target_one.stat != CONSCIOUS || prob(10))
bloodgrab(target_one_turf, handedness)
else
bloodsmack(target_one_turf, handedness)
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodsmack(turf/T, handedness)
if(handedness)
new /obj/effect/overlay/temp/bubblegum_hands/rightsmack(T)
else
new /obj/effect/overlay/temp/bubblegum_hands/leftsmack(T)
sleep(2.5)
for(var/mob/living/L in T)
if(!faction_check(L))
to_chat(L, "<span class='userdanger'>[src] rends you!</span>")
playsound(T, attack_sound, 100, 1, -1)
var/limb_to_hit = pick("head", "chest", "r_arm", "l_arm", "r_leg", "l_leg")
L.apply_damage(25, BRUTE, limb_to_hit, L.run_armor_check(limb_to_hit, "melee", null, null, armour_penetration))
sleep(3)
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodgrab(turf/T, handedness)
if(handedness)
new /obj/effect/overlay/temp/bubblegum_hands/rightpaw(T)
new /obj/effect/overlay/temp/bubblegum_hands/rightthumb(T)
else
new /obj/effect/overlay/temp/bubblegum_hands/leftpaw(T)
new /obj/effect/overlay/temp/bubblegum_hands/leftthumb(T)
sleep(6)
for(var/mob/living/L in T)
if(!faction_check(L))
to_chat(L, "<span class='userdanger'>[src] drags you through the blood!</span>")
playsound(T, 'sound/misc/enter_blood.ogg', 100, 1, -1)
var/turf/targetturf = get_step(src, dir)
L.forceMove(targetturf)
playsound(targetturf, 'sound/misc/exit_blood.ogg', 100, 1, -1)
if(L.stat != CONSCIOUS)
spawn(2)
devour(L)
sleep(1)
/obj/effect/overlay/temp/bubblegum_hands
icon = 'icons/effects/bubblegum.dmi'
duration = 9
/obj/effect/overlay/temp/bubblegum_hands/rightthumb
icon_state = "rightthumbgrab"
/obj/effect/overlay/temp/bubblegum_hands/leftthumb
icon_state = "leftthumbgrab"
/obj/effect/overlay/temp/bubblegum_hands/rightpaw
icon_state = "rightpawgrab"
layer = MOB_LAYER - 0.1
/obj/effect/overlay/temp/bubblegum_hands/leftpaw
icon_state = "leftpawgrab"
layer = MOB_LAYER - 0.1
/obj/effect/overlay/temp/bubblegum_hands/rightsmack
icon_state = "rightsmack"
/obj/effect/overlay/temp/bubblegum_hands/leftsmack
icon_state = "leftsmack"
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_warp()
if(Adjacent(target))
return FALSE
var/list/can_jaunt = get_pools(get_turf(src), 1)
if(!can_jaunt.len)
return FALSE
var/list/pools = get_pools(get_turf(target), 2)
var/list/pools_to_remove = get_pools(get_turf(target), 1)
pools -= pools_to_remove
if(!pools.len)
return FALSE
var/obj/effect/overlay/temp/decoy/DA = new /obj/effect/overlay/temp/decoy(loc, src)
DA.color = "#FF0000"
var/oldtransform = DA.transform
DA.transform = matrix()*2
animate(DA, alpha = 255, color = initial(DA.color), transform = oldtransform, time = 5)
sleep(5)
qdel(DA)
var/obj/effect/decal/cleanable/blood/found_bloodpool
pools = get_pools(get_turf(target), 2)
pools_to_remove = get_pools(get_turf(target), 1)
pools -= pools_to_remove
if(pools.len)
shuffle(pools)
found_bloodpool = pick(pools)
if(found_bloodpool)
visible_message("<span class='danger'>[src] sinks into the blood...</span>")
playsound(get_turf(src), 'sound/misc/enter_blood.ogg', 100, 1, -1)
forceMove(get_turf(found_bloodpool))
playsound(get_turf(src), 'sound/misc/exit_blood.ogg', 100, 1, -1)
visible_message("<span class='danger'>And springs back out!</span>")
return TRUE
return FALSE
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_pools(turf/T, range)
. = list()
for(var/obj/effect/decal/cleanable/nearby in view(T, range))
if(nearby.can_bloodcrawl_in())
. += nearby
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_spray()
visible_message("<span class='danger'>[src] sprays a stream of gore!</span>")
var/range = 6 + round(anger_modifier * 0.4)
var/turf/previousturf = get_turf(src)
var/turf/J = previousturf
var/targetdir = get_dir(src, target)
if(target.loc == loc)
targetdir = dir
face_atom(target)
new /obj/effect/decal/cleanable/blood/bubblegum(J)
for(var/i in 1 to range)
J = get_step(previousturf, targetdir)
new /obj/effect/overlay/temp/dir_setting/bloodsplatter(previousturf, get_dir(previousturf, J))
playsound(previousturf,'sound/effects/splat.ogg', 100, 1, -1)
if(!J || !previousturf.CanAtmosPass(J))
break
new /obj/effect/decal/cleanable/blood/bubblegum(J)
previousturf = J
sleep(1)
/obj/effect/decal/cleanable/blood/bubblegum
amount = 0
/obj/effect/decal/cleanable/blood/bubblegum/can_bloodcrawl_in()
return TRUE
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/slaughterlings()
visible_message("<span class='danger'>[src] summons a shoal of slaughterlings!</span>")
var/max_amount = 6
for(var/H in get_pools(get_turf(src), 1))
if(!max_amount)
break
max_amount--
var/obj/effect/decal/cleanable/blood/B = H
new /mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/slaughter(B.loc)
return max_amount
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/slaughter
name = "slaughterling"
desc = "Though not yet strong enough to create a true physical form, it's nonetheless determined to murder you."
density = 0
faction = list("mining", "boss")
weather_immunities = list("lava","ash")
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/slaughter/CanPass(atom/movable/mover, turf/target, height = 0)
if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum))
return 1
return 0
#undef MEDAL_PREFIX
@@ -0,0 +1,266 @@
#define MEDAL_PREFIX "Colossus"
/*
COLOSSUS
The colossus spawns randomly wherever a lavaland creature is able to spawn. It is powerful, ancient, and extremely deadly.
The colossus has a degree of sentience, proving this in speech during its attacks.
It acts as a melee creature, chasing down and attacking its target while also using different attacks to augment its power that increase as it takes damage.
The colossus' true danger lies in its ranged capabilities. It fires immensely damaging death bolts that penetrate all armor in a variety of ways:
1. The colossus fires death bolts in alternating patterns: the cardinal directions and the diagonal directions.
2. The colossus fires death bolts in a shotgun-like pattern, instantly downing anything unfortunate enough to be hit by all of them.
3. The colossus fires a spiral of death bolts.
At 33% health, the colossus gains an additional attack:
4. The colossus fires two spirals of death bolts, spinning in opposite directions.
When a colossus dies, it leaves behind a chunk of glowing crystal known as a black box. Anything placed inside will carry over into future rounds.
For instance, you could place a bag of holding into the black box, and then kill another colossus next round and retrieve the bag of holding from inside.
Difficulty: Very Hard
*/
/mob/living/simple_animal/hostile/megafauna/colossus
name = "colossus"
desc = "A monstrous creature protected by heavy shielding."
health = 2500
maxHealth = 2500
attacktext = "judges"
attack_sound = 'sound/magic/ratvar_attack.ogg'
icon_state = "eva"
icon_living = "eva"
icon_dead = "dragon_dead"
friendly = "stares down"
icon = 'icons/mob/lavaland/96x96megafauna.dmi'
speak_emote = list("roars")
armour_penetration = 40
melee_damage_lower = 40
melee_damage_upper = 40
speed = 1
move_to_delay = 10
ranged = 1
pixel_x = -32
del_on_death = 1
medal_type = MEDAL_PREFIX
score_type = COLOSSUS_SCORE
loot = list(/obj/machinery/anomalous_crystal/random, /obj/item/organ/internal/vocal_cords/colossus)
butcher_results = list(/obj/item/weapon/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/animalhide/ashdrake = 10, /obj/item/stack/sheet/bone = 30)
deathmessage = "disintegrates, leaving a glowing core in its wake."
death_sound = 'sound/misc/demon_dies.ogg'
/mob/living/simple_animal/hostile/megafauna/colossus/devour(mob/living/L)
visible_message("<span class='colossus'>[src] disintegrates [L]!</span>")
L.dust()
/mob/living/simple_animal/hostile/megafauna/colossus/OpenFire()
anger_modifier = Clamp(((maxHealth - health)/50),0,20)
ranged_cooldown = world.time + 120
if(enrage(target))
if(move_to_delay == initial(move_to_delay))
visible_message("<span class='colossus'>\"<b>You can't dodge.</b>\"</span>")
ranged_cooldown = world.time + 30
telegraph()
dir_shots(alldirs)
move_to_delay = 3
return
else
move_to_delay = initial(move_to_delay)
if(prob(20+anger_modifier)) //Major attack
telegraph()
if(health < maxHealth/3)
double_spiral()
else
visible_message("<span class='colossus'>\"<b>Judgement.</b>\"</span>")
spawn(0)
spiral_shoot(rand(0, 1))
else if(prob(20))
ranged_cooldown = world.time + 30
random_shots()
else
if(prob(70))
ranged_cooldown = world.time + 20
blast()
else
ranged_cooldown = world.time + 40
spawn(0)
alternating_dir_shots()
/mob/living/simple_animal/hostile/megafauna/colossus/New()
..()
internal_gps = new/obj/item/device/gps/internal/colossus(src)
/obj/effect/overlay/temp/at_shield
name = "anti-toolbox field"
desc = "A shimmering forcefield protecting the colossus."
icon = 'icons/effects/effects.dmi'
icon_state = "at_shield2"
layer = FLY_LAYER
luminosity = 2
duration = 8
var/target
/obj/effect/overlay/temp/at_shield/New(new_loc, new_target)
..()
target = new_target
spawn(0)
orbit(target, 0, FALSE, 0, 0, FALSE, TRUE)
/mob/living/simple_animal/hostile/megafauna/colossus/bullet_act(obj/item/projectile/P)
if(!stat)
var/obj/effect/overlay/temp/at_shield/AT = new /obj/effect/overlay/temp/at_shield(loc, src)
var/random_x = rand(-32, 32)
AT.pixel_x += random_x
var/random_y = rand(0, 72)
AT.pixel_y += random_y
..()
/mob/living/simple_animal/hostile/megafauna/colossus/proc/enrage(mob/living/L)
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(H.martial_art && prob(H.martial_art.deflection_chance))
. = TRUE
/mob/living/simple_animal/hostile/megafauna/colossus/proc/alternating_dir_shots()
dir_shots(diagonals)
sleep(10)
dir_shots(cardinal)
sleep(10)
dir_shots(diagonals)
sleep(10)
dir_shots(cardinal)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/double_spiral()
visible_message("<span class='colossus'>\"<b>Die.</b>\"</span>")
sleep(10)
spawn(0)
spiral_shoot()
spawn(0)
spiral_shoot(1)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/spiral_shoot(negative = 0, counter_start = 1)
var/counter = counter_start
var/turf/marker
for(var/i in 1 to 80)
switch(counter)
if(1)
marker = locate(x, y - 2, z)
if(2)
marker = locate(x - 1, y - 2, z)
if(3)
marker = locate(x - 2, y - 2, z)
if(4)
marker = locate(x - 2, y - 1, z)
if(5)
marker = locate(x - 2, y, z)
if(6)
marker = locate(x - 2, y + 1, z)
if(7)
marker = locate(x - 2, y + 2, z)
if(8)
marker = locate(x - 1, y + 2, z)
if(9)
marker = locate(x, y + 2, z)
if(10)
marker = locate(x + 1, y + 2, z)
if(11)
marker = locate(x + 2, y + 2, z)
if(12)
marker = locate(x + 2, y + 1, z)
if(13)
marker = locate(x + 2, y, z)
if(14)
marker = locate(x + 2, y - 1, z)
if(15)
marker = locate(x + 2, y - 2, z)
if(16)
marker = locate(x + 1, y - 2, z)
if(negative)
counter--
else
counter++
if(counter > 16)
counter = 1
if(counter < 1)
counter = 16
shoot_projectile(marker)
playsound(get_turf(src), 'sound/magic/invoke_general.ogg', 20, 1)
sleep(1)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/shoot_projectile(turf/marker)
if(!marker || marker == loc)
return
var/turf/startloc = get_turf(src)
var/obj/item/projectile/P = new /obj/item/projectile/colossus(startloc)
P.current = startloc
P.starting = startloc
P.firer = src
P.yo = marker.y - startloc.y
P.xo = marker.x - startloc.x
if(target)
P.original = target
else
P.original = marker
P.fire()
/mob/living/simple_animal/hostile/megafauna/colossus/proc/random_shots()
var/turf/U = get_turf(src)
playsound(U, 'sound/magic/invoke_general.ogg', 300, 1, 5)
for(var/T in RANGE_TURFS(12, U) - U)
if(prob(5))
shoot_projectile(T)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/blast()
playsound(get_turf(src), 'sound/magic/invoke_general.ogg', 200, 1, 2)
var/turf/T = get_turf(target)
newtonian_move(get_dir(T, targets_from))
for(var/turf/turf in range(1, T))
shoot_projectile(turf)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/dir_shots(list/dirs)
if(!islist(dirs))
dirs = alldirs.Copy()
playsound(get_turf(src), 'sound/magic/invoke_general.ogg', 200, 1, 2)
for(var/d in dirs)
var/turf/E = get_step(src, d)
shoot_projectile(E)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/telegraph()
for(var/mob/M in range(10,src))
if(M.client)
flash_color(M.client, rgb(200, 0, 0), 1)
shake_camera(M, 4, 3)
playsound(get_turf(src),'sound/magic/narsie_attack.ogg', 200, 1)
/obj/item/projectile/colossus
name ="death bolt"
icon_state= "chronobolt"
damage = 25
armour_penetration = 100
speed = 2
eyeblur = 0
damage_type = BRUTE
pass_flags = PASSTABLE
/obj/item/projectile/colossus/on_hit(atom/target, blocked = 0)
. = ..()
if(isturf(target) || isobj(target))
target.ex_act(2)
/obj/item/device/gps/internal/colossus
icon_state = null
gpstag = "Angelic Signal"
desc = "Get in the fucking robot."
invisibility = 100
#undef MEDAL_PREFIX
@@ -0,0 +1,278 @@
#define MEDAL_PREFIX "Drake"
/*
ASH DRAKE
Ash drakes spawn randomly wherever a lavaland creature is able to spawn. They are the draconic guardians of the Necropolis.
It acts as a melee creature, chasing down and attacking its target while also using different attacks to augment its power that increase as it takes damage.
Whenever possible, the drake will breathe fire in the four cardinal directions, igniting and heavily damaging anything caught in the blast.
It also often causes fire to rain from the sky - many nearby turfs will flash red as a fireball crashes into them, dealing damage to anything on the turfs.
The drake also utilizes its wings to fly into the sky and crash down onto a specified point. Anything on this point takes tremendous damage.
- Sometimes it will chain these swooping attacks over and over, making swiftness a necessity.
When an ash drake dies, it leaves behind a chest that can contain four things:
1. A spectral blade that allows its wielder to call ghosts to it, enhancing its power
2. A lava staff that allows its wielder to create lava
3. A spellbook and wand of fireballs
4. A bottle of dragon's blood with several effects, including turning its imbiber into a drake themselves.
When butchered, they leave behind diamonds, sinew, bone, and ash drake hide. Ash drake hide can be used to create a hooded cloak that protects its wearer from ash storms.
Difficulty: Medium
*/
/mob/living/simple_animal/hostile/megafauna/dragon
name = "ash drake"
desc = "Guardians of the necropolis."
health = 2500
maxHealth = 2500
attacktext = "chomps"
attack_sound = 'sound/misc/demon_attack1.ogg'
icon_state = "dragon"
icon_living = "dragon"
icon_dead = "dragon_dead"
friendly = "stares down"
icon = 'icons/mob/lavaland/dragon.dmi'
speak_emote = list("roars")
armour_penetration = 40
melee_damage_lower = 40
melee_damage_upper = 40
speed = 1
move_to_delay = 10
ranged = 1
pixel_x = -16
loot = list(/obj/structure/closet/crate/necropolis/dragon)
butcher_results = list(/obj/item/weapon/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/animalhide/ashdrake = 10, /obj/item/stack/sheet/bone = 30)
var/swooping = 0
var/swoop_cooldown = 0
medal_type = MEDAL_PREFIX
score_type = DRAKE_SCORE
deathmessage = "collapses into a pile of bones, its flesh sloughing away."
death_sound = 'sound/misc/demon_dies.ogg'
/mob/living/simple_animal/hostile/megafauna/dragon/New()
..()
internal_gps = new/obj/item/device/gps/internal/dragon(src)
/mob/living/simple_animal/hostile/megafauna/dragon/ex_act(severity, target)
if(severity == 3)
return
..()
/mob/living/simple_animal/hostile/megafauna/dragon/adjustHealth(amount)
if(swooping)
return 0
return ..()
/mob/living/simple_animal/hostile/megafauna/dragon/AttackingTarget()
if(!swooping)
..()
/mob/living/simple_animal/hostile/megafauna/dragon/DestroySurroundings()
if(!swooping)
..()
/mob/living/simple_animal/hostile/megafauna/dragon/Move()
if(!swooping)
..()
/mob/living/simple_animal/hostile/megafauna/dragon/Goto(target, delay, minimum_distance)
if(!swooping)
..()
/mob/living/simple_animal/hostile/megafauna/dragon/Process_Spacemove(movement_dir = 0)
return 1
/obj/effect/overlay/temp/fireball
icon = 'icons/obj/wizard.dmi'
icon_state = "fireball"
name = "fireball"
desc = "Get out of the way!"
layer = 6
randomdir = 0
duration = 12
pixel_z = 500
/obj/effect/overlay/temp/fireball/New(loc)
..()
animate(src, pixel_z = 0, time = 12)
/obj/effect/overlay/temp/target
icon = 'icons/mob/actions.dmi'
icon_state = "sniper_zoom"
layer = MOB_LAYER - 0.1
luminosity = 2
duration = 12
/obj/effect/overlay/temp/dragon_swoop
name = "certain death"
desc = "Don't just stand there, move!"
icon = 'icons/effects/96x96.dmi'
icon_state = "landing"
layer = MOB_LAYER - 0.1
pixel_x = -32
pixel_y = -32
color = "#FF0000"
duration = 10
/obj/effect/overlay/temp/target/ex_act()
return
/obj/effect/overlay/temp/target/New(loc)
..()
spawn(0)
fall()
/obj/effect/overlay/temp/target/proc/fall()
var/turf/T = get_turf(src)
playsound(T,'sound/magic/Fireball.ogg', 200, 1)
new /obj/effect/overlay/temp/fireball(T)
sleep(12)
explosion(T, 0, 0, 1, 0, 0, 0, 1)
/mob/living/simple_animal/hostile/megafauna/dragon/OpenFire()
anger_modifier = Clamp(((maxHealth - health)/50),0,20)
ranged_cooldown = world.time + ranged_cooldown_time
if(swooping)
fire_rain()
return
if(prob(15 + anger_modifier) && !client)
if(health < maxHealth/2)
spawn(0)
swoop_attack(1)
else
fire_rain()
else if(prob(10+anger_modifier) && !client)
if(health > maxHealth/2)
spawn(0)
swoop_attack(0)
else
spawn(0)
triple_swoop(0)
else
fire_walls()
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_rain()
visible_message("<span class='boldwarning'>Fire rains from the sky!</span>")
for(var/turf/turf in range(12,get_turf(src)))
if(prob(10))
new /obj/effect/overlay/temp/target(turf)
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_walls()
playsound(get_turf(src),'sound/magic/Fireball.ogg', 200, 1)
for(var/d in cardinal)
spawn(0)
fire_wall(d)
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_wall(dir)
var/list/hit_things = list(src)
var/turf/E = get_edge_target_turf(src, dir)
var/range = 10
var/turf/previousturf = get_turf(src)
for(var/turf/J in getline(src,E))
if(!range || !previousturf.CanAtmosPass(J))
break
range--
new /obj/effect/hotspot(J)
J.hotspot_expose(700,50,1)
for(var/mob/living/L in J.contents - hit_things)
L.adjustFireLoss(20)
to_chat(L, "<span class='userdanger'>You're hit by the drake's fire breath!</span>")
hit_things += L
previousturf = J
sleep(1)
/mob/living/simple_animal/hostile/megafauna/dragon/proc/triple_swoop()
swoop_attack()
swoop_attack()
swoop_attack()
/mob/living/simple_animal/hostile/megafauna/dragon/proc/swoop_attack(fire_rain = 0, atom/movable/manual_target)
if(stat || swooping)
return
swoop_cooldown = world.time + 200
var/atom/swoop_target
if(manual_target)
swoop_target = manual_target
else
swoop_target = target
stop_automated_movement = TRUE
swooping = 1
density = 0
icon_state = "swoop"
visible_message("<span class='boldwarning'>[src] swoops up high!</span>")
if(prob(50))
animate(src, pixel_x = 500, pixel_z = 500, time = 10)
else
animate(src, pixel_x = -500, pixel_z = 500, time = 10)
sleep(30)
var/turf/tturf
if(fire_rain)
fire_rain()
icon_state = "dragon"
if(swoop_target && !qdeleted(swoop_target) && swoop_target.z == src.z)
tturf = get_turf(swoop_target)
else
tturf = get_turf(src)
forceMove(tturf)
new /obj/effect/overlay/temp/dragon_swoop(tturf)
animate(src, pixel_x = initial(pixel_x), pixel_z = 0, time = 10)
sleep(10)
playsound(src.loc, 'sound/effects/meteorimpact.ogg', 200, 1)
for(var/mob/living/L in orange(1, src))
if(L.stat)
visible_message("<span class='warning'>[src] slams down on [L], crushing them!</span>")
L.gib()
else
L.adjustBruteLoss(75)
if(L && !qdeleted(L)) // Some mobs are deleted on death
var/throw_dir = get_dir(src, L)
if(L.loc == loc)
throw_dir = pick(alldirs)
var/throwtarget = get_edge_target_turf(src, throw_dir)
L.throw_at_fast(throwtarget, 3)
visible_message("<span class='warning'>[L] is thrown clear of [src]!</span>")
for(var/mob/M in range(7, src))
shake_camera(M, 15, 1)
stop_automated_movement = FALSE
swooping = 0
density = 1
/mob/living/simple_animal/hostile/megafauna/dragon/AltClickOn(atom/movable/A)
if(!istype(A))
return
if(swoop_cooldown >= world.time)
to_chat(src, "<span class='warning'>You need to wait 20 seconds between swoop attacks!</span>")
return
swoop_attack(1, A)
/obj/item/device/gps/internal/dragon
icon_state = null
gpstag = "Fiery Signal"
desc = "Here there be dragons."
invisibility = 100
/mob/living/simple_animal/hostile/megafauna/dragon/lesser
name = "lesser ash drake"
maxHealth = 200
health = 200
faction = list("neutral")
melee_damage_upper = 30
melee_damage_lower = 30
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
loot = list()
/mob/living/simple_animal/hostile/megafauna/dragon/lesser/grant_achievement(medaltype,scoretype)
return
#undef MEDAL_PREFIX
@@ -0,0 +1,611 @@
#define MEDAL_PREFIX "Hierophant"
/*
The Hierophant
The Hierophant spawns in its arena, an area designed to make it harder to fight than it would otherwise be.
The text this boss speaks is ROT4, use ROT22 to decode
The Hierophant's attacks are as follows, and INTENSIFY at a random chance based on Hierophant's health;
- Creates a cardinal or diagonal blast(Cross Blast) under its target, exploding after a short time.
INTENSITY EFFECT: Creates one of the cross blast types under itself instead of under the target.
INTENSITY EFFECT: The created Cross Blast fires in all directions if below half health.
- If no chasers exist, creates a chaser that will seek its target, leaving a trail of blasts.
INTENSITY EFFECT: Creates a second, slower chaser.
- Creates an expanding AoE burst.
- INTENSE ATTACKS:
If target is at least 2 tiles away; Blinks to the target after a very brief delay, damaging everything near the start and end points.
As above, but does so multiple times if below half health.
Rapidly creates Cross Blasts under a target.
If chasers are off cooldown, creates four high-speed chasers.
- IF TARGET WAS STRUCK IN MELEE: Creates a 3x3 square of blasts under the target.
Cross Blasts and the AoE burst gain additional range as the Hierophant loses health, while Chasers gain additional speed.
When The Hierophant dies, it leaves behind its staff, which, while much weaker than when wielded by The Hierophant itself, is still quite effective.
- The staff can place a teleport rune, allowing the user to teleport themself and their allies to the rune.
Difficulty: Hard
*/
/mob/living/simple_animal/hostile/megafauna/hierophant
name = "Hierophant"
desc = "An ancient, powerful priest-like being wielding a mighty staff."
health = 2500
maxHealth = 2500
attacktext = "clubs"
//attack_sound = 'sound/weapons/sonic_jackhammer.ogg'
attack_sound = "swing_hit"
icon_state = "hierophant"
icon_living = "hierophant"
friendly = "stares down"
icon = 'icons/mob/lavaland/hierophant.dmi'
faction = list("boss") //asteroid mobs? get that shit out of my beautiful square house
speak_emote = list("preaches")
armour_penetration = 50
melee_damage_lower = 10
melee_damage_upper = 10
speed = 1
move_to_delay = 10
ranged = 1
pixel_x = -16
ranged_cooldown_time = 40
aggro_vision_range = 23
loot = list(/obj/item/weapon/hierophant_staff)
wander = FALSE
var/burst_range = 3 //range on burst aoe
var/beam_range = 5 //range on cross blast beams
var/chaser_speed = 3 //how fast chasers are currently
var/chaser_cooldown = 101 //base cooldown/cooldown var between spawning chasers
var/major_attack_cooldown = 60 //base cooldown for major attacks
var/blinking = FALSE //if we're doing something that requires us to stand still and not attack
var/obj/effect/hierophant/spawned_rune //the rune we teleport back to
var/timeout_time = 15 //after this many Life() ticks with no target, we return to our rune
var/did_reset = TRUE //if we timed out, returned to our rune, and healed some
//var/list/kill_phrases = list("Wsyvgi sj irivkc xettih. Vitemvmrk...", "Irivkc wsyvgi jsyrh. Vitemvmrk...", "Jyip jsyrh. Egxmzexmrk vitemv gcgpiw...")
//var/list/target_phrases = list("Xevkix psgexih.", "Iriqc jsyrh.", "Eguymvih xevkix.")
medal_type = MEDAL_PREFIX
score_type = BIRD_SCORE
del_on_death = TRUE
death_sound = 'sound/magic/Repulse.ogg'
/mob/living/simple_animal/hostile/megafauna/hierophant/New()
..()
internal_gps = new/obj/item/device/gps/internal/hierophant(src)
spawned_rune = new(loc)
/mob/living/simple_animal/hostile/megafauna/hierophant/Life()
. = ..()
if(. && spawned_rune && !client)
if(target || loc == spawned_rune.loc)
timeout_time = initial(timeout_time)
else
timeout_time--
if(timeout_time <= 0 && !did_reset)
did_reset = TRUE
//visible_message("<span class='hierophant'>\"Vixyvrmrk xs fewi...\"</span>")
blink(spawned_rune)
adjustHealth(min((health - maxHealth) * 0.5, -50)) //heal for 50% of our missing health
wander = FALSE
/*if(health > maxHealth * 0.9)
visible_message("<span class='hierophant'>\"Vitemvw gsqtpixi. Stivexmrk ex qebmqyq ijjmgmirgc.\"</span>")
else
visible_message("<span class='hierophant'>\"Vitemvw gsqtpixi. Stivexmsrep ijjmgmirgc gsqtvsqmwih.\"</span>")*/
/mob/living/simple_animal/hostile/megafauna/hierophant/death()
if(health > 0 || stat == DEAD)
return
else
stat = DEAD
blinking = TRUE //we do a fancy animation, release a huge burst(), and leave our staff.
animate(src, alpha = 0, color = "660099", time = 20, easing = EASE_OUT)
burst_range = 10
//visible_message("<span class='hierophant'>\"Mrmxmexmrk wipj-hiwxvygx wiuyirgi...\"</span>")
visible_message("<span class='hierophant_warning'>[src] disappears in a massive burst of magic, leaving only its staff.</span>")
burst(get_turf(src))
..()
/mob/living/simple_animal/hostile/megafauna/hierophant/Destroy()
qdel(spawned_rune)
. = ..()
/mob/living/simple_animal/hostile/megafauna/hierophant/devour(mob/living/L)
for(var/obj/item/W in L)
if(!L.unEquip(W))
qdel(W)
/*visible_message(
"<span class='hierophant'>\"[pick(kill_phrases)]\"</span>\n<span class='hierophant_warning'>[src] annihilates [L]!</span>",
"<span class='userdanger'>You annihilate [L], restoring your health!</span>")*/
visible_message(
"<span class='hierophant'>\"Caw.\"</span>\n<span class='hierophant_warning'>[src] annihilates [L]!</span>",
"<span class='userdanger'>You annihilate [L], restoring your health!</span>")
adjustHealth(-L.maxHealth*0.5)
L.dust()
/*/mob/living/simple_animal/hostile/megafauna/hierophant/GiveTarget(new_target)
var/targets_the_same = (new_target == target)
. = ..()
if(. && target && !targets_the_same)
visible_message("<span class='hierophant'>\"[pick(target_phrases)]\"</span>")*/
/mob/living/simple_animal/hostile/megafauna/hierophant/adjustHealth(amount)
. = ..()
if(src && amount > 0 && !blinking)
wander = TRUE
did_reset = FALSE
/mob/living/simple_animal/hostile/megafauna/hierophant/AttackingTarget()
if(!blinking)
if(target && isliving(target))
spawn(0)
melee_blast(get_turf(target)) //melee attacks on living mobs produce a 3x3 blast
..()
/mob/living/simple_animal/hostile/megafauna/hierophant/DestroySurroundings()
if(!blinking)
..()
/mob/living/simple_animal/hostile/megafauna/hierophant/Move()
if(!blinking)
/*if(!stat)
playsound(loc, 'sound/mecha/mechmove04.ogg', 150, 1, -4)*/
..()
/mob/living/simple_animal/hostile/megafauna/hierophant/Goto(target, delay, minimum_distance)
wander = TRUE
if(!blinking)
..()
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/calculate_rage() //how angry we are overall
did_reset = FALSE //oh hey we're doing SOMETHING, clearly we might need to heal if we recall
anger_modifier = Clamp(((maxHealth - health) / 42),0,50)
burst_range = initial(burst_range) + round(anger_modifier * 0.08)
beam_range = initial(beam_range) + round(anger_modifier * 0.12)
/mob/living/simple_animal/hostile/megafauna/hierophant/OpenFire()
calculate_rage()
var/target_is_slow = FALSE
if(isliving(target))
var/mob/living/L = target
if(!blinking && L.stat == DEAD && get_dist(src, L) > 2)
blink(L)
return
if(L.movement_delay() > 1.5)
target_is_slow = TRUE
chaser_speed = max(1, (3 - anger_modifier * 0.04) + target_is_slow * 0.5)
if(blinking)
return
ranged_cooldown = world.time + max(5, ranged_cooldown_time - anger_modifier * 0.75) //scale cooldown lower with high anger.
if(prob(anger_modifier * 0.75)) //major ranged attack
var/list/possibilities = list()
var/cross_counter = 1 + round(anger_modifier * 0.12)
if(cross_counter > 1)
possibilities += "cross_blast_spam"
if(get_dist(src, target) > 2)
possibilities += "blink_spam"
if(chaser_cooldown < world.time)
if(prob(anger_modifier * 2))
possibilities = list("chaser_swarm")
else
possibilities += "chaser_swarm"
if(possibilities.len)
ranged_cooldown = world.time + max(5, major_attack_cooldown - anger_modifier * 0.75) //we didn't cancel out of an attack, use the higher cooldown
var/blink_counter = 1 + round(anger_modifier * 0.08)
switch(pick(possibilities))
if("blink_spam") //blink either once or multiple times.
if(health < maxHealth * 0.5 && !target_is_slow && blink_counter > 1)
//visible_message("<span class='hierophant'>\"Mx ampp rsx iwgeti.\"</span>")
animate(src, color = "#660099", time = 6)
while(health && target && blink_counter)
if(loc == target.loc || loc == target) //we're on the same tile as them after about a second we can stop now
break
blink_counter--
blinking = FALSE
blink(target)
blinking = TRUE
sleep(5)
animate(src, color = initial(color), time = 8)
sleep(8)
blinking = FALSE
else
blink(target)
if("cross_blast_spam") //fire a lot of cross blasts at a target.
//visible_message("<span class='hierophant'>\"Piezi mx rsalivi xs vyr.\"</span>")
blinking = TRUE
animate(src, color = "#660099", time = 6)
while(health && target && cross_counter)
cross_counter--
var/delay = 6
if(prob(60))
spawn(0)
cardinal_blasts(target)
else
spawn(0)
diagonal_blasts(target)
delay = 5 //this one isn't so mean, so do the next one faster(if there is one)
sleep(delay)
animate(src, color = initial(color), time = 8)
sleep(8)
blinking = FALSE
if("chaser_swarm") //fire four fucking chasers at a target and their friends.
//visible_message("<span class='hierophant'>\"Mx gerrsx lmhi.\"</span>")
blinking = TRUE
animate(src, color = "#660099", time = 10)
var/list/targets = ListTargets()
var/list/cardinal_copy = cardinal.Copy()
while(health && targets.len && cardinal_copy.len)
var/mob/living/pickedtarget = pick(targets)
if(targets.len > 4)
pickedtarget = pick_n_take(targets)
if(pickedtarget.stat == DEAD)
pickedtarget = target
var/obj/effect/overlay/temp/hierophant/chaser/C = new /obj/effect/overlay/temp/hierophant/chaser(loc, src, pickedtarget, chaser_speed, FALSE)
C.moving = 3
C.moving_dir = pick_n_take(cardinal_copy)
sleep(10)
chaser_cooldown = world.time + initial(chaser_cooldown)
animate(src, color = initial(color), time = 8)
sleep(8)
blinking = FALSE
return
if(prob(10 + (anger_modifier * 0.5)) && get_dist(src, target) > 2)
blink(target)
else if(prob(70 - anger_modifier)) //a cross blast of some type
if(prob(anger_modifier)) //at us?
if(prob(anger_modifier * 2) && health < maxHealth * 0.5) //we're super angry do it at all dirs
spawn(0)
alldir_blasts(src)
else if(prob(60))
spawn(0)
cardinal_blasts(src)
else
spawn(0)
diagonal_blasts(src)
else //at them?
if(prob(anger_modifier * 2) && health < maxHealth * 0.5 && !target_is_slow) //we're super angry do it at all dirs
spawn(0)
alldir_blasts(target)
else if(prob(60))
spawn(0)
cardinal_blasts(target)
else
spawn(0)
diagonal_blasts(target)
else if(chaser_cooldown < world.time) //if chasers are off cooldown, fire some!
var/obj/effect/overlay/temp/hierophant/chaser/C = new /obj/effect/overlay/temp/hierophant/chaser(loc, src, target, chaser_speed, FALSE)
chaser_cooldown = world.time + initial(chaser_cooldown)
if((prob(anger_modifier) || target.Adjacent(src)) && target != src)
var/obj/effect/overlay/temp/hierophant/chaser/OC = new /obj/effect/overlay/temp/hierophant/chaser(loc, src, target, max(1.5, 5 - anger_modifier * 0.07), FALSE)
OC.moving = 4
OC.moving_dir = pick(cardinal - C.moving_dir)
else //just release a burst of power
spawn(0)
burst(get_turf(src))
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/diagonal_blasts(mob/victim) //fire diagonal cross blasts with a delay
var/turf/T = get_turf(victim)
if(!T)
return
new /obj/effect/overlay/temp/hierophant/telegraph/diagonal(T, src)
playsound(T,'sound/magic/blink.ogg', 200, 1)
//playsound(T,'sound/effects/bin_close.ogg', 200, 1)
sleep(2)
new /obj/effect/overlay/temp/hierophant/blast(T, src, FALSE)
for(var/d in diagonals)
spawn(0)
blast_wall(T, d)
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/cardinal_blasts(mob/victim) //fire cardinal cross blasts with a delay
var/turf/T = get_turf(victim)
if(!T)
return
new /obj/effect/overlay/temp/hierophant/telegraph/cardinal(T, src)
playsound(T,'sound/magic/blink.ogg', 200, 1)
//playsound(T,'sound/effects/bin_close.ogg', 200, 1)
sleep(2)
new /obj/effect/overlay/temp/hierophant/blast(T, src, FALSE)
for(var/d in cardinal)
spawn(0)
blast_wall(T, d)
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/alldir_blasts(mob/victim) //fire alldir cross blasts with a delay
var/turf/T = get_turf(victim)
if(!T)
return
new /obj/effect/overlay/temp/hierophant/telegraph(T, src)
playsound(T,'sound/magic/blink.ogg', 200, 1)
//playsound(T,'sound/effects/bin_close.ogg', 200, 1)
sleep(2)
new /obj/effect/overlay/temp/hierophant/blast(T, src, FALSE)
for(var/d in alldirs)
spawn(0)
blast_wall(T, d)
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blast_wall(turf/T, dir) //make a wall of blasts beam_range tiles long
var/range = beam_range
var/turf/previousturf = T
var/turf/J = get_step(previousturf, dir)
for(var/i in 1 to range)
new /obj/effect/overlay/temp/hierophant/blast(J, src, FALSE)
previousturf = J
J = get_step(previousturf, dir)
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blink(mob/victim) //blink to a target
if(blinking || !victim)
return
var/turf/T = get_turf(victim)
var/turf/source = get_turf(src)
new /obj/effect/overlay/temp/hierophant/telegraph(T, src)
new /obj/effect/overlay/temp/hierophant/telegraph(source, src)
playsound(T,'sound/magic/blink.ogg', 200, 1)
//playsound(T,'sound/magic/Wand_Teleport.ogg', 200, 1)
playsound(source,'sound/magic/blink.ogg', 200, 1)
//playsound(source,'sound/machines/AirlockOpen.ogg', 200, 1)
blinking = TRUE
sleep(2) //short delay before we start...
new /obj/effect/overlay/temp/hierophant/telegraph/teleport(T, src)
new /obj/effect/overlay/temp/hierophant/telegraph/teleport(source, src)
for(var/t in RANGE_TURFS(1, T))
var/obj/effect/overlay/temp/hierophant/blast/B = new /obj/effect/overlay/temp/hierophant/blast(t, src, FALSE)
B.damage = 30
for(var/t in RANGE_TURFS(1, source))
var/obj/effect/overlay/temp/hierophant/blast/B = new /obj/effect/overlay/temp/hierophant/blast(t, src, FALSE)
B.damage = 30
animate(src, alpha = 0, time = 2, easing = EASE_OUT) //fade out
sleep(1)
visible_message("<span class='hierophant_warning'>[src] fades out!</span>")
density = FALSE
sleep(2)
forceMove(T)
sleep(1)
animate(src, alpha = 255, time = 2, easing = EASE_IN) //fade IN
sleep(1)
density = TRUE
visible_message("<span class='hierophant_warning'>[src] fades in!</span>")
sleep(1) //at this point the blasts we made detonate
blinking = FALSE
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/melee_blast(mob/victim) //make a 3x3 blast around a target
if(!victim)
return
var/turf/T = get_turf(victim)
if(!T)
return
new /obj/effect/overlay/temp/hierophant/telegraph(T, src)
playsound(T,'sound/magic/blink.ogg', 200, 1)
//playsound(T,'sound/effects/bin_close.ogg', 200, 1)
sleep(2)
for(var/t in RANGE_TURFS(1, T))
new /obj/effect/overlay/temp/hierophant/blast(t, src, FALSE)
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/burst(turf/original) //release a wave of blasts
playsound(original,'sound/magic/blink.ogg', 200, 1)
//playsound(original,'sound/machines/AirlockOpen.ogg', 200, 1)
var/last_dist = 0
for(var/t in spiral_range_turfs(burst_range, original))
var/turf/T = t
if(!T)
continue
var/dist = get_dist(original, T)
if(dist > last_dist)
last_dist = dist
sleep(1 + (burst_range - last_dist) * 0.5) //gets faster as it gets further out
new /obj/effect/overlay/temp/hierophant/blast(T, src, FALSE)
/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
blink(A)
//Hierophant overlays
/obj/effect/overlay/temp/hierophant
layer = MOB_LAYER - 0.1
var/mob/living/caster //who made this, anyway
/obj/effect/overlay/temp/hierophant/New(loc, new_caster)
..()
if(new_caster)
caster = new_caster
/obj/effect/overlay/temp/hierophant/chaser //a hierophant's chaser. follows target around, moving and producing a blast every speed deciseconds.
duration = 98
var/mob/living/target //what it's following
var/turf/targetturf //what turf the target is actually on
var/moving_dir //what dir it's moving in
var/previous_moving_dir //what dir it was moving in before that
var/more_previouser_moving_dir //what dir it was moving in before THAT
var/moving = 0 //how many steps to move before recalculating
var/standard_moving_before_recalc = 4 //how many times we step before recalculating normally
var/tiles_per_step = 1 //how many tiles we move each step
var/speed = 3 //how many deciseconds between each step
var/currently_seeking = FALSE
var/friendly_fire_check = FALSE //if blasts produced apply friendly fire
/obj/effect/overlay/temp/hierophant/chaser/New(loc, new_caster, new_target, new_speed, is_friendly_fire)
..()
target = new_target
friendly_fire_check = is_friendly_fire
if(new_speed)
speed = new_speed
spawn(0)
seek_target()
/obj/effect/overlay/temp/hierophant/chaser/proc/get_target_dir()
. = get_cardinal_dir(src, targetturf)
if((. != previous_moving_dir && . == more_previouser_moving_dir) || . == 0) //we're alternating, recalculate
var/list/cardinal_copy = cardinal.Copy()
cardinal_copy -= more_previouser_moving_dir
. = pick(cardinal_copy)
/obj/effect/overlay/temp/hierophant/chaser/proc/seek_target()
if(!currently_seeking)
currently_seeking = TRUE
targetturf = get_turf(target)
while(target && src && !qdeleted(src) && currently_seeking && x && y && targetturf) //can this target actually be sook out
if(!moving) //we're out of tiles to move, find more and where the target is!
more_previouser_moving_dir = previous_moving_dir
previous_moving_dir = moving_dir
moving_dir = get_target_dir()
var/standard_target_dir = get_cardinal_dir(src, targetturf)
if((standard_target_dir != previous_moving_dir && standard_target_dir == more_previouser_moving_dir) || standard_target_dir == 0)
moving = 1 //we would be repeating, only move a tile before checking
else
moving = standard_moving_before_recalc
if(moving) //move in the dir we're moving in right now
var/turf/T = get_turf(src)
for(var/i in 1 to tiles_per_step)
var/maybe_new_turf = get_step(T, moving_dir)
if(maybe_new_turf)
T = maybe_new_turf
else
break
forceMove(T)
make_blast() //make a blast, too
moving--
sleep(speed)
targetturf = get_turf(target)
/obj/effect/overlay/temp/hierophant/chaser/proc/make_blast()
new /obj/effect/overlay/temp/hierophant/blast(loc, caster, friendly_fire_check)
/obj/effect/overlay/temp/hierophant/telegraph
icon = 'icons/effects/96x96.dmi'
icon_state = "hierophant_telegraph"
pixel_x = -32
pixel_y = -32
duration = 3
/obj/effect/overlay/temp/hierophant/telegraph/diagonal
icon_state = "hierophant_telegraph_diagonal"
/obj/effect/overlay/temp/hierophant/telegraph/cardinal
icon_state = "hierophant_telegraph_cardinal"
/obj/effect/overlay/temp/hierophant/telegraph/teleport
icon_state = "hierophant_telegraph_teleport"
duration = 9
/obj/effect/overlay/temp/hierophant/blast
icon = 'icons/effects/effects.dmi'
icon_state = "hierophant_blast"
name = "vortex blast"
luminosity = 1
desc = "Get out of the way!"
duration = 9
var/damage = 10 //how much damage do we do?
var/list/hit_things = list() //we hit these already, ignore them
var/friendly_fire_check = FALSE
var/bursting = FALSE //if we're bursting and need to hit anyone crossing us
/obj/effect/overlay/temp/hierophant/blast/New(loc, new_caster, friendly_fire)
..()
friendly_fire_check = friendly_fire
if(new_caster)
hit_things += new_caster
if(ismineralturf(loc)) //drill mineral turfs
var/turf/simulated/mineral/M = loc
M.gets_drilled(caster)
spawn(0)
blast()
/obj/effect/overlay/temp/hierophant/blast/proc/blast()
var/turf/T = get_turf(src)
if(!T)
return
playsound(T,'sound/magic/Blind.ogg', 125, 1, -5) //make a sound
sleep(6) //wait a little
bursting = TRUE
do_damage(T) //do damage and mark us as bursting
sleep(1.3) //slightly forgiving; the burst animation is 1.5 deciseconds
bursting = FALSE //we no longer damage crossers
/obj/effect/overlay/temp/hierophant/blast/Crossed(atom/movable/AM)
..()
if(bursting)
do_damage(get_turf(src))
/obj/effect/overlay/temp/hierophant/blast/proc/do_damage(turf/T)
for(var/mob/living/L in T.contents - hit_things) //find and damage mobs...
hit_things += L
if((friendly_fire_check && caster && caster.faction_check(L)) || L.stat == DEAD)
continue
if(L.client)
flash_color(L.client, "#660099", 1)
playsound(L,'sound/weapons/sear.ogg', 50, 1, -4)
to_chat(L, "<span class='userdanger'>You're struck by a [name]!</span>")
var/limb_to_hit = pick("head", "chest", "r_arm", "l_arm", "r_leg", "l_leg")
var/armor = L.run_armor_check(limb_to_hit, "melee", "Your armor absorbs [src]!", "Your armor blocks part of [src]!", 50, "Your armor was penetrated by [src]!")
L.apply_damage(damage, BURN, limb_to_hit, armor)
if(ismegafauna(L) || istype(L, /mob/living/simple_animal/hostile/asteroid))
L.adjustBruteLoss(damage)
add_logs(caster, L, "struck with a [name]")
for(var/obj/mecha/M in T.contents - hit_things) //and mechs.
hit_things += M
if(M.occupant)
if(friendly_fire_check && caster && caster.faction_check(M.occupant))
continue
to_chat(M.occupant, "<span class='userdanger'>Your [M.name] is struck by a [name]!</span>")
playsound(M,'sound/weapons/sear.ogg', 50, 1, -4)
M.take_damage(damage, BURN, 0, 0)
/obj/effect/hierophant
name = "hierophant rune"
desc = "A powerful magic mark allowing whomever attunes themself to it to return to it at will."
icon = 'icons/obj/rune.dmi'
icon_state = "hierophant"
layer = 2.5
anchored = TRUE
color = "#CC00FF"
/obj/effect/hierophant/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/weapon/hierophant_staff))
var/obj/item/weapon/hierophant_staff/H = I
if(H.rune == src)
to_chat(user, "<span class='notice'>You start removing your hierophant rune...</span>")
H.timer = world.time + 51
if(do_after(user, 50, target = src))
playsound(src,'sound/magic/Blind.ogg', 200, 1, -4)
new /obj/effect/overlay/temp/hierophant/telegraph/teleport(get_turf(src), user)
to_chat(user, "<span class='hierophant_warning'>You touch the rune with the staff, dispelling it!</span>")
H.rune = null
user.update_action_buttons_icon()
qdel(src)
else
H.timer = world.time
else
to_chat(user, "<span class='hierophant_warning'>You touch the rune with the staff, but nothing happens.</span>")
else
..()
/obj/item/device/gps/internal/hierophant
icon_state = null
gpstag = "Zealous Signal"
desc = "Heed its words."
invisibility = 100
/turf/simulated/indestructible/hierophant
icon_state = "hierophant1"
oxygen = 14
nitrogen = 23
temperature = 300
desc = "A floor with a square pattern. It's faintly cool to the touch."
/turf/simulated/indestructible/hierophant/New()
..()
if(prob(50))
icon_state = "hierophant2"
/turf/simulated/indestructible/riveted/hierophant
name = "wall"
desc = "A wall made out of smooth, cold stone."
icon = 'icons/turf/walls/hierophant_wall.dmi'
icon_state = "hierophant"
smooth = SMOOTH_TRUE
#undef MEDAL_PREFIX
@@ -0,0 +1,142 @@
#define MEDAL_PREFIX "Legion"
/*
LEGION
Legion spawns from the necropolis gate in the far north of lavaland. It is the guardian of the Necropolis and emerges from within whenever an intruder tries to enter through its gate.
Whenever Legion emerges, everything in lavaland will receive a notice via color, audio, and text. This is because Legion is powerful enough to slaughter the entirety of lavaland with little effort.
It has two attack modes that it constantly rotates between.
In ranged mode, it will behave like a normal legion - retreating when possible and firing legion skulls at the target.
In charge mode, it will spin and rush its target, attacking with melee whenever possible.
When Legion dies, it drops a staff of storms, which allows its wielder to call and disperse ash storms at will and functions as a powerful melee weapon.
Difficulty: Medium
*/
/mob/living/simple_animal/hostile/megafauna/legion
name = "Legion"
health = 800
maxHealth = 800
icon_state = "legion"
icon_living = "legion"
desc = "One of many."
icon = 'icons/mob/lavaland/legion.dmi'
attacktext = "chomps"
attack_sound = 'sound/misc/demon_attack1.ogg'
speak_emote = list("echoes")
armour_penetration = 50
melee_damage_lower = 25
melee_damage_upper = 25
speed = 2
ranged = 1
del_on_death = 1
retreat_distance = 5
minimum_distance = 5
ranged_cooldown_time = 20
var/size = 5
var/charging = 0
medal_type = MEDAL_PREFIX
score_type = LEGION_SCORE
pixel_y = -90
pixel_x = -75
loot = list(/obj/item/stack/sheet/bone = 3)
vision_range = 13
elimination = 1
idle_vision_range = 13
appearance_flags = 0
mouse_opacity = 1
stat_attack = 1 // Overriden from /tg/ - otherwise Legion starts chasing its minions
/mob/living/simple_animal/hostile/megafauna/legion/New()
..()
internal_gps = new/obj/item/device/gps/internal/legion(src)
/mob/living/simple_animal/hostile/megafauna/legion/AttackingTarget()
..()
if(ishuman(target))
var/mob/living/L = target
if(L.stat == UNCONSCIOUS)
var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/A = new(loc)
A.infest(L)
/mob/living/simple_animal/hostile/megafauna/legion/OpenFire(the_target)
if(world.time >= ranged_cooldown && !charging)
if(prob(75))
var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/A = new(loc)
A.GiveTarget(target)
A.friends = friends
A.faction = faction
ranged_cooldown = world.time + ranged_cooldown_time
else
visible_message("<span class='warning'><b>[src] charges!</b></span>")
SpinAnimation(speed = 20, loops = 5)
ranged = 0
retreat_distance = 0
minimum_distance = 0
speed = 0
charging = 1
spawn(50)
reset_charge()
/mob/living/simple_animal/hostile/megafauna/legion/proc/reset_charge()
ranged = 1
retreat_distance = 5
minimum_distance = 5
speed = 2
charging = 0
/mob/living/simple_animal/hostile/megafauna/legion/death()
if(health > 0)
return
if(size > 1)
adjustHealth(-maxHealth) //heal ourself to full in prep for splitting
var/mob/living/simple_animal/hostile/megafauna/legion/L = new(loc)
L.maxHealth = maxHealth * 0.6
maxHealth = L.maxHealth
L.health = L.maxHealth
health = maxHealth
size--
L.size = size
L.resize = L.size * 0.2
transform = initial(transform)
resize = size * 0.2
L.update_transform()
update_transform()
L.faction = faction.Copy()
L.GiveTarget(target)
visible_message("<span class='boldannounce'>[src] splits in twain!</span>")
else
var/last_legion = TRUE
for(var/mob/living/simple_animal/hostile/megafauna/legion/other in mob_list)
if(other != src)
last_legion = FALSE
break
if(last_legion)
loot = list(/obj/item/weapon/staff/storm)
elimination = 0
else if(prob(5))
loot = list(/obj/structure/closet/crate/necropolis/tendril)
..()
/mob/living/simple_animal/hostile/megafauna/legion/Process_Spacemove(movement_dir = 0)
return 1
/obj/item/device/gps/internal/legion
icon_state = null
gpstag = "Echoing Signal"
desc = "The message repeats."
invisibility = 100
#undef MEDAL_PREFIX
@@ -0,0 +1,230 @@
#define MEDAL_PREFIX "Boss"
/mob/living/simple_animal/hostile/megafauna
name = "megafauna"
desc = "Attack the weak point for massive damage."
health = 1000
maxHealth = 1000
a_intent = "harm"
sentience_type = SENTIENCE_BOSS
environment_smash = 3
luminosity = 3
faction = list("mining", "boss")
weather_immunities = list("lava","ash")
flying = 1
robust_searching = 1
ranged_ignores_vision = TRUE
stat_attack = 2
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)
damage_coeff = list(BRUTE = 1, BURN = 0.5, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
minbodytemp = 0
maxbodytemp = INFINITY
aggro_vision_range = 18
idle_vision_range = 5
environment_target_typecache = list(
/obj/machinery/door/window,
/obj/structure/window,
/obj/structure/closet,
/obj/structure/table,
/obj/structure/grille,
/obj/structure/girder,
/obj/structure/rack,
/obj/structure/barricade,
/obj/machinery/field,
/obj/machinery/power/emitter)
var/medal_type = MEDAL_PREFIX
var/score_type = BOSS_SCORE
var/elimination = 0
var/anger_modifier = 0
var/obj/item/device/gps/internal_gps
anchored = TRUE
mob_size = MOB_SIZE_LARGE
layer = MOB_LAYER + 0.5 //Looks weird with them slipping under mineral walls and cameras and shit otherwise
mouse_opacity = 2 // Easier to click on in melee, they're giant targets anyway
/mob/living/simple_animal/hostile/megafauna/Destroy()
qdel(internal_gps)
. = ..()
/mob/living/simple_animal/hostile/megafauna/death(gibbed)
if(health > 0)
return
else
if(!admin_spawned)
feedback_set_details("megafauna_kills","[initial(name)]")
if(!elimination) //used so the achievment only occurs for the last legion to die.
grant_achievement(medal_type,score_type)
..()
/mob/living/simple_animal/hostile/megafauna/gib()
if(health > 0)
return
else
..()
/mob/living/simple_animal/hostile/megafauna/dust()
if(health > 0)
return
else
..()
/mob/living/simple_animal/hostile/megafauna/AttackingTarget()
..()
if(isliving(target))
var/mob/living/L = target
if(L.stat != DEAD)
if(!client && ranged && ranged_cooldown <= world.time)
OpenFire()
else
devour(L)
/mob/living/simple_animal/hostile/megafauna/onShuttleMove()
var/turf/oldloc = loc
. = ..()
if(!.)
return
var/turf/newloc = loc
message_admins("Megafauna [src] \
(<A HREF='?_src_=holder;adminplayerobservefollow=[UID()]'>FLW</A>) \
moved via shuttle from ([oldloc.x], [oldloc.y], [oldloc.z]) to \
([newloc.x], [newloc.y], [newloc.z])")
/mob/living/simple_animal/hostile/megafauna/proc/devour(mob/living/L)
if(!L)
return
visible_message(
"<span class='danger'>[src] devours [L]!</span>",
"<span class='userdanger'>You feast on [L], restoring your health!</span>")
adjustBruteLoss(-L.maxHealth/2)
L.gib()
/mob/living/simple_animal/hostile/megafauna/ex_act(severity, target)
switch(severity)
if(1)
adjustBruteLoss(250)
if(2)
adjustBruteLoss(100)
if(3)
adjustBruteLoss(50)
/mob/living/simple_animal/hostile/megafauna/proc/grant_achievement(medaltype,scoretype)
if(medal_type == "Boss") //Don't award medals if the medal type isn't set
return
if(admin_spawned)
return
if(global.medal_hub && global.medal_pass && global.medals_enabled)
for(var/mob/living/L in view(7,src))
if(L.stat)
continue
if(L.client)
var/client/C = L.client
var/suffixm = BOSS_KILL_MEDAL
UnlockMedal("Boss [suffixm]",C)
UnlockMedal("[medaltype] [suffixm]",C)
SetScore(BOSS_SCORE,C,1)
SetScore(score_type,C,1)
/proc/UnlockMedal(medal,client/player)
if(!player || !medal)
return
if(global.medal_hub && global.medal_pass && global.medals_enabled)
spawn()
var/result = world.SetMedal(medal, player, global.medal_hub, global.medal_pass)
if(isnull(result))
global.medals_enabled = FALSE
log_game("MEDAL ERROR: Could not contact hub to award medal:[medal] player:[player.ckey]")
message_admins("Error! Failed to contact hub to award [medal] medal to [player.ckey]!")
else if(result)
to_chat(player.mob, "<span class='greenannounce'><B>Achievement unlocked: [medal]!</B></span>")
/proc/SetScore(score,client/player,increment,force)
if(!score || !player)
return
if(global.medal_hub && global.medal_pass && global.medals_enabled)
spawn()
var/list/oldscore = GetScore(score,player,1)
if(increment)
if(!oldscore[score])
oldscore[score] = 1
else
oldscore[score] = (text2num(oldscore[score]) + 1)
else
oldscore[score] = force
var/newscoreparam = list2params(oldscore)
var/result = world.SetScores(player.ckey, newscoreparam, global.medal_hub, global.medal_pass)
if(isnull(result))
global.medals_enabled = FALSE
log_game("SCORE ERROR: Could not contact hub to set score. Score:[score] player:[player.ckey]")
message_admins("Error! Failed to contact hub to set [score] score for [player.ckey]!")
/proc/GetScore(score,client/player,returnlist)
if(!score || !player)
return
if(global.medal_hub && global.medal_pass && global.medals_enabled)
var/scoreget = world.GetScores(player.ckey, score, global.medal_hub, global.medal_pass)
if(isnull(scoreget))
global.medals_enabled = FALSE
log_game("SCORE ERROR: Could not contact hub to get score. Score:[score] player:[player.ckey]")
message_admins("Error! Failed to contact hub to get score: [score] for [player.ckey]!")
return
var/list/scoregetlist = params2list(scoreget)
if(returnlist)
return scoregetlist
else
return scoregetlist[score]
/proc/CheckMedal(medal,client/player)
if(!player || !medal)
return
if(global.medal_hub && global.medal_pass && global.medals_enabled)
var/result = world.GetMedal(medal, player, global.medal_hub, global.medal_pass)
if(isnull(result))
global.medals_enabled = FALSE
log_game("MEDAL ERROR: Could not contact hub to get medal:[medal] player:[player.ckey]")
message_admins("Error! Failed to contact hub to get [medal] medal for [player.ckey]!")
else if(result)
to_chat(player.mob, "[medal] is unlocked")
/proc/LockMedal(medal,client/player)
if(!player || !medal)
return
if(global.medal_hub && global.medal_pass && global.medals_enabled)
var/result = world.ClearMedal(medal, player, global.medal_hub, global.medal_pass)
if(isnull(result))
global.medals_enabled = FALSE
log_game("MEDAL ERROR: Could not contact hub to clear medal:[medal] player:[player.ckey]")
message_admins("Error! Failed to contact hub to clear [medal] medal for [player.ckey]!")
else if(result)
message_admins("Medal: [medal] removed for [player.ckey]")
else
message_admins("Medal: [medal] was not found for [player.ckey]. Unable to clear.")
/proc/ClearScore(client/player)
world.SetScores(player.ckey, "", global.medal_hub, global.medal_pass)
#undef MEDAL_PREFIX
@@ -91,10 +91,6 @@
..()
icon_state = initial(icon_state)
/mob/living/simple_animal/hostile/mimic/crate/LostTarget()
..()
icon_state = initial(icon_state)
/mob/living/simple_animal/hostile/mimic/crate/death(gibbed)
var/obj/structure/closet/crate/C = new(get_turf(src))
// Put loot in crate
@@ -0,0 +1,78 @@
/mob/living/simple_animal/hostile/asteroid/goldgrub
name = "goldgrub"
desc = "A worm that grows fat from eating everything in its sight. Seems to enjoy precious metals and other shiny things, hence the name."
icon = 'icons/mob/animal.dmi'
icon_state = "Goldgrub"
icon_living = "Goldgrub"
icon_aggro = "Goldgrub_alert"
icon_dead = "Goldgrub_dead"
icon_gib = "syndicate_gib"
vision_range = 2
aggro_vision_range = 9
idle_vision_range = 2
move_to_delay = 5
friendly = "harmlessly rolls into"
maxHealth = 45
health = 45
harm_intent_damage = 5
melee_damage_lower = 0
melee_damage_upper = 0
attacktext = "barrels into"
attack_sound = 'sound/weapons/punch1.ogg'
a_intent = I_HELP
speak_emote = list("screeches")
throw_message = "sinks in slowly, before being pushed out of "
status_flags = CANPUSH
search_objects = 1
wanted_objects = list(/obj/item/weapon/ore/diamond, /obj/item/weapon/ore/gold, /obj/item/weapon/ore/silver,
/obj/item/weapon/ore/uranium)
var/chase_time = 100
var/will_burrow = TRUE
/mob/living/simple_animal/hostile/asteroid/goldgrub/New()
..()
var/i = rand(1,3)
while(i)
loot += pick(/obj/item/weapon/ore/silver, /obj/item/weapon/ore/gold, /obj/item/weapon/ore/uranium, /obj/item/weapon/ore/diamond)
i--
/mob/living/simple_animal/hostile/asteroid/goldgrub/GiveTarget(new_target)
target = new_target
if(target != null)
if(istype(target, /obj/item/weapon/ore) && loot.len < 10)
visible_message("<span class='notice'>The [src.name] looks at [target.name] with hungry eyes.</span>")
else if(isliving(target))
Aggro()
visible_message("<span class='danger'>The [src.name] tries to flee from [target.name]!</span>")
retreat_distance = 10
minimum_distance = 10
if(will_burrow)
spawn(chase_time)
Burrow()
/mob/living/simple_animal/hostile/asteroid/goldgrub/AttackingTarget()
if(istype(target, /obj/item/weapon/ore))
EatOre(target)
return
..()
/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/EatOre(var/atom/targeted_ore)
for(var/obj/item/weapon/ore/O in targeted_ore.loc)
if(loot.len < 10)
loot += O.type
qdel(O)
visible_message("<span class='notice'>The ore was swallowed whole!</span>")
/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/Burrow()//Begin the chase to kill the goldgrub in time
if(!stat)
visible_message("<span class='danger'>The [src.name] buries into the ground, vanishing from sight!</span>")
qdel(src)
/mob/living/simple_animal/hostile/asteroid/goldgrub/bullet_act(obj/item/projectile/P)
visible_message("<span class='danger'>The [P.name] was repelled by [src.name]'s girth!</span>")
return
/mob/living/simple_animal/hostile/asteroid/goldgrub/adjustHealth(damage)
idle_vision_range = 9
. = ..()
@@ -0,0 +1,319 @@
/mob/living/simple_animal/hostile/asteroid/hivelord
name = "hivelord"
desc = "A truly alien creature, it is a mass of unknown organic material, constantly fluctuating. When attacking, pieces of it split off and attack in tandem with the original."
icon = 'icons/mob/lavaland/lavaland_monsters.dmi'
icon_state = "Hivelord"
icon_living = "Hivelord"
icon_aggro = "Hivelord_alert"
icon_dead = "Hivelord_dead"
icon_gib = "syndicate_gib"
mouse_opacity = 2
move_to_delay = 14
ranged = 1
vision_range = 5
aggro_vision_range = 9
idle_vision_range = 5
speed = 3
maxHealth = 75
health = 75
harm_intent_damage = 5
melee_damage_lower = 0
melee_damage_upper = 0
attacktext = "lashes out at"
speak_emote = list("telepathically cries")
attack_sound = 'sound/weapons/pierce.ogg'
throw_message = "falls right through the strange body of the"
ranged_cooldown = 0
ranged_cooldown_time = 20
environment_smash = 0
retreat_distance = 3
minimum_distance = 3
pass_flags = PASSTABLE
loot = list(/obj/item/organ/internal/hivelord_core)
var/brood_type = /mob/living/simple_animal/hostile/asteroid/hivelordbrood
/mob/living/simple_animal/hostile/asteroid/hivelord/OpenFire(the_target)
if(world.time >= ranged_cooldown)
var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/A = new brood_type(src.loc)
A.admin_spawned = admin_spawned
A.GiveTarget(target)
A.friends = friends
A.faction = faction.Copy()
ranged_cooldown = world.time + ranged_cooldown_time
/mob/living/simple_animal/hostile/asteroid/hivelord/AttackingTarget()
OpenFire()
/mob/living/simple_animal/hostile/asteroid/hivelord/death(gibbed)
mouse_opacity = 1
..(gibbed)
/obj/item/organ/internal/hivelord_core
name = "hivelord remains"
desc = "All that remains of a hivelord, it seems to be what allows it to break pieces of itself off without being hurt... its healing properties will soon become inert if not used quickly."
icon_state = "roro core 2"
flags = NOBLUDGEON
slot = "hivecore"
force = 0
actions_types = list(/datum/action/item_action/organ_action/use)
var/inert = 0
var/preserved = 0
/obj/item/organ/internal/hivelord_core/New()
..()
addtimer(src, "inert_check", 2400)
/obj/item/organ/internal/hivelord_core/proc/inert_check()
if(!owner && !preserved)
go_inert()
else
preserved(implanted = 1)
/obj/item/organ/internal/hivelord_core/proc/preserved(implanted = 0)
inert = FALSE
preserved = TRUE
update_icon()
if(implanted)
feedback_add_details("hivelord_core", "[type]|implanted")
else
feedback_add_details("hivelord_core", "[type]|stabilizer")
/obj/item/organ/internal/hivelord_core/proc/go_inert()
inert = TRUE
desc = "The remains of a hivelord that have become useless, having been left alone too long after being harvested."
feedback_add_details("hivelord_core", "[src.type]|inert")
update_icon()
/obj/item/organ/internal/hivelord_core/ui_action_click()
owner.revive()
qdel(src)
/obj/item/organ/internal/hivelord_core/on_life()
..()
if(owner.health < config.health_threshold_crit)
ui_action_click()
/obj/item/organ/internal/hivelord_core/afterattack(atom/target, mob/user, proximity_flag)
if(proximity_flag && ishuman(target))
var/mob/living/carbon/human/H = target
if(inert)
to_chat(user, "<span class='notice'>[src] has become inert, its healing properties are no more.</span>")
return
else
if(H.stat == DEAD)
to_chat(user, "<span class='notice'>[src] are useless on the dead.</span>")
return
if(H != user)
H.visible_message("[user] forces [H] to apply [src]... They quickly regenerate all injuries!")
feedback_add_details("hivelord_core","[src.type]|used|other")
else
to_chat(user, "<span class='notice'>You start to smear [src] on yourself. It feels and smells disgusting, but you feel amazingly refreshed in mere moments.</span>")
feedback_add_details("hivelord_core","[src.type]|used|self")
playsound(src.loc,'sound/items/eatfood.ogg', rand(10,50), 1)
H.revive()
qdel(src)
..()
/obj/item/organ/internal/hivelord_core/prepare_eat()
return null
/mob/living/simple_animal/hostile/asteroid/hivelordbrood
name = "hivelord brood"
desc = "A fragment of the original Hivelord, rallying behind its original. One isn't much of a threat, but..."
icon = 'icons/mob/lavaland/lavaland_monsters.dmi'
icon_state = "Hivelordbrood"
icon_living = "Hivelordbrood"
icon_aggro = "Hivelordbrood"
icon_dead = "Hivelordbrood"
icon_gib = "syndicate_gib"
mouse_opacity = 2
move_to_delay = 1
friendly = "buzzes near"
vision_range = 10
speed = 3
maxHealth = 1
health = 1
flying = 1
harm_intent_damage = 5
melee_damage_lower = 2
melee_damage_upper = 2
attacktext = "slashes"
speak_emote = list("telepathically cries")
attack_sound = 'sound/weapons/pierce.ogg'
throw_message = "falls right through the strange body of the"
environment_smash = 0
pass_flags = PASSTABLE
del_on_death = 1
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/New()
..()
addtimer(src, "death", 100)
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood
name = "blood brood"
desc = "A living string of blood and alien materials."
icon_state = "bloodbrood"
icon_living = "bloodbrood"
icon_aggro = "bloodbrood"
attacktext = "pierces"
color = "#C80000"
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/death()
if(loc) // Splash the turf we are on with blood
reagents.reaction(get_turf(src))
..()
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/New()
create_reagents(30)
..()
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/AttackingTarget()
..()
if(iscarbon(target))
transfer_reagents(target, 1)
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/attack_hand(mob/living/carbon/human/M)
if("\ref[M]" in faction)
reabsorb_host(M)
else
return ..()
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/attack_alien(mob/living/carbon/alien/humanoid/M)
if("\ref[M]" in faction)
reabsorb_host(M)
else
return ..()
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/proc/reabsorb_host(mob/living/carbon/C)
C.visible_message("<span class='notice'>[src] is reabsorbed by [C]'s body.</span>", \
"<span class='notice'>[src] is reabsorbed by your body.</span>")
transfer_reagents(C)
death()
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/proc/transfer_reagents(mob/living/carbon/C, volume = 30)
if(!reagents.total_volume)
return
volume = min(volume, reagents.total_volume)
var/fraction = min(volume/reagents.total_volume, 1)
reagents.reaction(C, INGEST, fraction)
reagents.trans_to(C, volume)
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/proc/link_host(mob/living/carbon/human/H)
faction = list("\ref[src]", "\ref[H]") // Hostile to everyone except the host.
H.vessel.trans_to(src, 30)
color = mix_color_from_reagents(reagents.reagent_list)
// Legion
/mob/living/simple_animal/hostile/asteroid/hivelord/legion
name = "legion"
desc = "You can still see what was once a human under the shifting mass of corruption."
icon = 'icons/mob/lavaland/lavaland_monsters.dmi'
icon_state = "legion"
icon_living = "legion"
icon_aggro = "legion"
icon_dead = "legion"
icon_gib = "syndicate_gib"
melee_damage_lower = 15
melee_damage_upper = 15
attacktext = "lashes out at"
speak_emote = list("echoes")
attack_sound = 'sound/weapons/pierce.ogg'
throw_message = "bounces harmlessly off of"
loot = list(/obj/item/organ/internal/hivelord_core/legion)
brood_type = /mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion
del_on_death = 1
stat_attack = 1
robust_searching = 1
var/mob/living/carbon/human/stored_mob
/mob/living/simple_animal/hostile/asteroid/hivelord/legion/death(gibbed)
visible_message("<span class='warning'>The skulls on [src] wail in anger as they flee from their dying host!</span>")
var/turf/T = get_turf(src)
if(T)
if(stored_mob)
stored_mob.forceMove(get_turf(src))
stored_mob = null
else
new /obj/effect/landmark/corpse/damaged(T)
..(gibbed)
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion
name = "legion"
desc = "One of many."
icon = 'icons/mob/lavaland/lavaland_monsters.dmi'
icon_state = "legion_head"
icon_living = "legion_head"
icon_aggro = "legion_head"
icon_dead = "legion_head"
icon_gib = "syndicate_gib"
friendly = "buzzes near"
vision_range = 10
maxHealth = 1
health = 5
harm_intent_damage = 5
melee_damage_lower = 12
melee_damage_upper = 12
attacktext = "bites"
speak_emote = list("echoes")
attack_sound = 'sound/weapons/pierce.ogg'
throw_message = "is shrugged off by"
pass_flags = PASSTABLE
del_on_death = 1
stat_attack = 1
robust_searching = 1
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/Life()
if(isturf(loc))
for(var/mob/living/carbon/human/H in view(src,1)) //Only for corpse right next to/on same tile
if(H.stat == UNCONSCIOUS)
infest(H)
..()
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/proc/infest(mob/living/carbon/human/H)
visible_message("<span class='warning'>[name] burrows into the flesh of [H]!</span>")
var/mob/living/simple_animal/hostile/asteroid/hivelord/legion/L = new(H.loc)
visible_message("<span class='warning'>[L] staggers to their feet!</span>")
H.death()
H.adjustBruteLoss(1000)
L.stored_mob = H
H.forceMove(L)
qdel(src)
/obj/item/organ/internal/hivelord_core/legion
name = "legion's soul"
desc = "A strange rock that still crackles with power... its \
healing properties will soon become inert if not used quickly."
icon_state = "legion_soul"
/obj/item/organ/internal/hivelord_core/legion/New()
..()
update_icon()
/obj/item/organ/internal/hivelord_core/legion/update_icon()
icon_state = inert ? "legion_soul_inert" : "legion_soul"
overlays.Cut()
if(!inert && !preserved)
overlays += image(icon, "legion_soul_crackle")
for(var/X in actions)
var/datum/action/A = X
A.UpdateButtonIcon()
/obj/item/organ/internal/hivelord_core/legion/go_inert()
. = ..()
desc = "[src] has become inert, it crackles no more and is useless for \
healing injuries."
/obj/item/organ/internal/hivelord_core/legion/preserved(implanted = 0)
..()
desc = "[src] has been stabilized. It no longer crackles with power, but it's healing properties are preserved indefinitely."
/obj/item/weapon/legion_skull
name = "legion's head"
desc = "The once living, now empty eyes of the former human's skull cut deep into your soul."
icon = 'icons/obj/mining.dmi'
icon_state = "skull"
@@ -58,7 +58,7 @@
projectilesound = 'sound/weapons/pierce.ogg'
ranged = 1
ranged_message = "stares"
ranged_cooldown_cap = 20
ranged_cooldown_time = 30
throw_message = "does nothing against the hard shell of"
vision_range = 2
speed = 3
@@ -71,7 +71,6 @@
a_intent = I_HARM
speak_emote = list("chitters")
attack_sound = 'sound/weapons/bladeslice.ogg'
ranged_cooldown_cap = 4
aggro_vision_range = 9
idle_vision_range = 2
turns_per_move = 5
@@ -104,232 +103,6 @@
if(3.0)
adjustBruteLoss(110)
/mob/living/simple_animal/hostile/asteroid/goldgrub
name = "goldgrub"
desc = "A worm that grows fat from eating everything in its sight. Seems to enjoy precious metals and other shiny things, hence the name."
icon = 'icons/mob/animal.dmi'
icon_state = "Goldgrub"
icon_living = "Goldgrub"
icon_aggro = "Goldgrub_alert"
icon_dead = "Goldgrub_dead"
icon_gib = "syndicate_gib"
vision_range = 2
aggro_vision_range = 9
idle_vision_range = 2
move_to_delay = 5
friendly = "harmlessly rolls into"
maxHealth = 45
health = 45
harm_intent_damage = 5
melee_damage_lower = 0
melee_damage_upper = 0
attacktext = "barrels into"
attack_sound = 'sound/weapons/punch1.ogg'
a_intent = I_HELP
speak_emote = list("screeches")
throw_message = "sinks in slowly, before being pushed out of "
status_flags = CANPUSH
search_objects = 1
wanted_objects = list(/obj/item/weapon/ore/diamond, /obj/item/weapon/ore/gold, /obj/item/weapon/ore/silver,
/obj/item/weapon/ore/uranium)
var/list/ore_types_eaten = list()
var/alerted = 0
var/ore_eaten = 1
var/chase_time = 100
var/will_burrow = 1
/mob/living/simple_animal/hostile/asteroid/goldgrub/New()
..()
ore_types_eaten += pick(/obj/item/weapon/ore/silver, /obj/item/weapon/ore/gold, /obj/item/weapon/ore/uranium, /obj/item/weapon/ore/diamond)
ore_eaten = rand(1,3)
/mob/living/simple_animal/hostile/asteroid/goldgrub/GiveTarget(var/new_target)
target = new_target
if(target != null)
if(istype(target, /obj/item/weapon/ore))
visible_message("<span class='notice'>The [src.name] looks at [target.name] with hungry eyes.</span>")
else if(isliving(target))
Aggro()
visible_message("<span class='danger'>The [src.name] tries to flee from [target.name]!</span>")
retreat_distance = 10
minimum_distance = 10
Burrow()
/mob/living/simple_animal/hostile/asteroid/goldgrub/AttackingTarget()
if(istype(target, /obj/item/weapon/ore))
EatOre(target)
return
..()
/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/EatOre(var/atom/targeted_ore)
for(var/obj/item/weapon/ore/O in targeted_ore.loc)
ore_eaten++
if(!(O.type in ore_types_eaten))
ore_types_eaten += O.type
qdel(O)
if(ore_eaten > 10)//Limit the scope of the reward you can get, or else things might get silly
ore_eaten = 10
visible_message("<span class='notice'>The ore was swallowed whole!</span>")
/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/Burrow()//Begin the chase to kill the goldgrub in time
if(!alerted && will_burrow)
alerted = 1
spawn(chase_time)
if(alerted)
visible_message("<span class='danger'>The [src.name] buries into the ground, vanishing from sight!</span>")
qdel(src)
/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/Reward()
if(!ore_eaten || ore_types_eaten.len == 0)
return
visible_message("<span class='danger'>[src] spits up the contents of its stomach before dying!</span>")
var/counter
for(var/R in ore_types_eaten)
for(counter=0, counter < ore_eaten, counter++)
new R(src.loc)
ore_types_eaten.Cut()
ore_eaten = 0
/mob/living/simple_animal/hostile/asteroid/goldgrub/bullet_act(var/obj/item/projectile/P)
visible_message("<span class='danger'>The [P.name] was repelled by [src.name]'s girth!</span>")
return
/mob/living/simple_animal/hostile/asteroid/goldgrub/death(gibbed)
alerted = 0
Reward()
..()
/mob/living/simple_animal/hostile/asteroid/goldgrub/adjustHealth(damage)
idle_vision_range = 9
..()
/mob/living/simple_animal/hostile/asteroid/hivelord
name = "hivelord"
desc = "A truly alien creature, it is a mass of unknown organic material, constantly fluctuating. When attacking, pieces of it split off and attack in tandem with the original."
icon = 'icons/mob/animal.dmi'
icon_state = "Hivelord"
icon_living = "Hivelord"
icon_aggro = "Hivelord_alert"
icon_dead = "Hivelord_dead"
icon_gib = "syndicate_gib"
mouse_opacity = 2
move_to_delay = 14
ranged = 1
vision_range = 5
aggro_vision_range = 9
idle_vision_range = 5
speed = 3
maxHealth = 75
health = 75
harm_intent_damage = 5
melee_damage_lower = 0
melee_damage_upper = 0
attacktext = "lashes out at"
speak_emote = list("telepathically cries")
attack_sound = 'sound/weapons/pierce.ogg'
throw_message = "falls right through the strange body of the"
ranged_cooldown = 0
ranged_cooldown_cap = 0
environment_smash = 0
retreat_distance = 3
minimum_distance = 3
pass_flags = PASSTABLE
loot = list(/obj/item/organ/internal/hivelord_core)
/mob/living/simple_animal/hostile/asteroid/hivelord/OpenFire(var/the_target)
var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/A = new /mob/living/simple_animal/hostile/asteroid/hivelordbrood(src.loc)
A.GiveTarget(target)
A.friends = friends
A.faction = faction
return
/mob/living/simple_animal/hostile/asteroid/hivelord/AttackingTarget()
OpenFire()
/obj/item/organ/internal/hivelord_core
name = "hivelord remains"
desc = "All that remains of a hivelord, it seems to be what allows it to break pieces of itself off without being hurt... its healing properties will soon become inert if not used quickly. Try not to think about what you're eating."
icon = 'icons/obj/food/food.dmi'
icon_state = "boiledrorocore"
slot = "hivecore"
var/inert = 0
var/preserved = 0
/obj/item/organ/internal/hivelord_core/New()
spawn(2400)
if(!preserved)
inert = 1
desc = "The remains of a hivelord that have become useless, having been left alone too long after being harvested."
/obj/item/organ/internal/hivelord_core/on_life()
..()
if(owner)
owner.adjustBruteLoss(-1)
owner.adjustFireLoss(-1)
owner.adjustOxyLoss(-2)
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
var/datum/reagent/blood/B = locate() in H.vessel.reagent_list //Grab some blood
var/blood_volume = round(H.vessel.get_reagent_amount("blood"))
if(B && blood_volume < H.max_blood && blood_volume)
B.volume += 2 // Fast blood regen
/obj/item/organ/internal/hivelord_core/attack(mob/living/M as mob, mob/living/user as mob)
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(inert)
to_chat(user, "<span class='notice'>[src] have become inert, its healing properties are no more.</span>")
return
else
if(H.stat == DEAD)
to_chat(user, "<span class='notice'>[src] are useless on the dead.</span>")
return
if(H != user)
H.visible_message("<span class='notice'>[user] forces [H] to eat [src]... they quickly regenerate all injuries!</span>")
else
to_chat(user, "<span class='notice'>You chomp into [src], barely managing to hold it down, but feel amazingly refreshed in mere moments.</span>")
playsound(src.loc,'sound/items/eatfood.ogg', rand(10,50), 1)
H.revive()
qdel(src)
..()
/obj/item/organ/internal/hivelord_core/prepare_eat()
return null
/mob/living/simple_animal/hostile/asteroid/hivelordbrood
name = "hivelord brood"
desc = "A fragment of the original Hivelord, rallying behind its original. One isn't much of a threat, but..."
icon = 'icons/mob/animal.dmi'
icon_state = "Hivelordbrood"
icon_living = "Hivelordbrood"
icon_aggro = "Hivelordbrood"
icon_dead = "Hivelordbrood"
icon_gib = "syndicate_gib"
mouse_opacity = 2
move_to_delay = 1
friendly = "buzzes near"
vision_range = 10
speed = 3
maxHealth = 1
health = 1
harm_intent_damage = 5
melee_damage_lower = 2
melee_damage_upper = 2
attacktext = "slashes"
speak_emote = list("telepathically cries")
attack_sound = 'sound/weapons/pierce.ogg'
throw_message = "falls right through the strange body of the"
environment_smash = 0
pass_flags = PASSTABLE
del_on_death = 1
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/New()
..()
spawn(100)
death()
/mob/living/simple_animal/hostile/asteroid/goliath
name = "goliath"
desc = "A massive beast that uses long tentacles to ensare its prey, threatening them is not advised under any conditions."
@@ -344,7 +117,7 @@
move_to_delay = 40
ranged = 1
ranged_cooldown = 2 //By default, start the Goliath with his cooldown off so that people can run away quickly on first sight
ranged_cooldown_cap = 8
ranged_cooldown_time = 120
friendly = "wails at"
speak_emote = list("bellows")
vision_range = 4
@@ -368,7 +141,7 @@
handle_preattack()
/mob/living/simple_animal/hostile/asteroid/goliath/proc/handle_preattack()
if(ranged_cooldown <= 2 && !pre_attack)
if(ranged_cooldown <= world.time + ranged_cooldown_time * 0.25 && !pre_attack)
pre_attack++
if(!pre_attack || stat || AIStatus == AI_IDLE)
return
@@ -383,7 +156,7 @@
if(get_dist(src, target) <= 7)//Screen range check, so you can't get tentacle'd offscreen
visible_message("<span class='warning'>The [src.name] digs its tentacles under [target.name]!</span>")
new /obj/effect/goliath_tentacle/original(tturf)
ranged_cooldown = ranged_cooldown_cap
ranged_cooldown = world.time + ranged_cooldown_time
icon_state = icon_aggro
pre_attack = 0
return
@@ -156,7 +156,7 @@
var/counter
for(counter=0, counter<=powerlevel, counter++)
var/obj/item/weapon/reagent_containers/food/snacks/hugemushroomslice/S = new /obj/item/weapon/reagent_containers/food/snacks/hugemushroomslice(src.loc)
S.reagents.add_reagent("mushroomhallucinogen", powerlevel)
S.reagents.add_reagent("psilocybin", powerlevel)
S.reagents.add_reagent("omnizine", powerlevel)
S.reagents.add_reagent("synaptizine", powerlevel)
qdel(src)
@@ -163,7 +163,7 @@
clothes_req = 0
range = 14
/obj/effect/proc_holder/spell/aoe_turf/flicker_lights/cast(list/targets)
/obj/effect/proc_holder/spell/aoe_turf/flicker_lights/cast(list/targets, mob/user = usr)
for(var/turf/T in targets)
for(var/obj/machinery/light/L in T)
L.flicker()
@@ -179,9 +179,9 @@
clothes_req = 0
range = 10
/obj/effect/proc_holder/spell/aoe_turf/blindness/cast(list/targets)
/obj/effect/proc_holder/spell/aoe_turf/blindness/cast(list/targets, mob/user = usr)
for(var/mob/living/L in living_mob_list)
if(L == usr)
if(L == user)
continue
var/turf/T = get_turf(L.loc)
if(T && T in targets)
@@ -200,7 +200,7 @@
range = -1
include_user = 1
/obj/effect/proc_holder/spell/targeted/night_vision/cast(list/targets)
/obj/effect/proc_holder/spell/targeted/night_vision/cast(list/targets, mob/user = usr)
for(var/mob/living/target in targets)
if(target.see_invisible == SEE_INVISIBLE_LIVING)
@@ -0,0 +1,116 @@
/obj/structure/alien/resin/flower_bud_enemy //inheriting basic attack/damage stuff from alien structures
name = "flower bud"
desc = "A large pulsating plant..."
icon = 'icons/effects/spacevines.dmi'
icon_state = "flower_bud"
layer = MOB_LAYER + 0.9
opacity = 0
canSmoothWith = list()
smooth = SMOOTH_FALSE
var/growth_time = 1200
/obj/structure/alien/resin/flower_bud_enemy/New()
..()
var/list/anchors = list()
anchors += locate(x-2,y+2,z)
anchors += locate(x+2,y+2,z)
anchors += locate(x-2,y-2,z)
anchors += locate(x+2,y-2,z)
for(var/turf/T in anchors)
var/datum/beam/B = Beam(T, "vine", time=INFINITY, maxdistance=5, beam_type=/obj/effect/ebeam/vine)
B.sleep_time = 10 //these shouldn't move, so let's slow down updates to 1 second (any slower and the deletion of the vines would be too slow)
addtimer(src, "bear_fruit", growth_time)
/obj/structure/alien/resin/flower_bud_enemy/proc/bear_fruit()
visible_message("<span class='danger'>the plant has borne fruit!</span>")
new /mob/living/simple_animal/hostile/venus_human_trap(get_turf(src))
qdel(src)
/obj/effect/ebeam/vine
name = "thick vine"
mouse_opacity = 1
desc = "A thick vine, painful to the touch."
/obj/effect/ebeam/vine/Crossed(atom/movable/AM)
if(isliving(AM))
var/mob/living/L = AM
if(!("vines" in L.faction))
L.adjustBruteLoss(5)
to_chat(L, "<span class='alert'>You cut yourself on the thorny vines.</span>")
/mob/living/simple_animal/hostile/venus_human_trap
name = "venus human trap"
desc = "Now you know how the fly feels."
icon_state = "venus_human_trap"
layer = MOB_LAYER + 0.9
health = 50
maxHealth = 50
ranged = 1
harm_intent_damage = 5
melee_damage_lower = 25
melee_damage_upper = 25
a_intent = I_HARM
attack_sound = 'sound/weapons/bladeslice.ogg'
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
unsuitable_atmos_damage = 0
faction = list("hostile","vines","plants")
var/list/grasping = list()
var/max_grasps = 4
var/grasp_chance = 20
var/grasp_pull_chance = 85
var/grasp_range = 4
del_on_death = 1
/mob/living/simple_animal/hostile/venus_human_trap/handle_automated_action()
if(..())
for(var/mob/living/L in grasping)
if(L.stat == DEAD)
var/datum/beam/B = grasping[L]
if(B)
B.End()
grasping -= L
//Can attack+pull multiple times per cycle
if(L.Adjacent(src))
L.attack_animal(src)
else
if(prob(grasp_pull_chance))
dir = get_dir(src,L) //staaaare
step(L,get_dir(L,src)) //reel them in
L.Weaken(3) //you can't get away now~
if(grasping.len < max_grasps)
grasping:
for(var/mob/living/L in view(grasp_range, src))
if(L == src || faction_check(L) || (L in grasping) || L == target)
continue
for(var/t in getline(src,L))
for(var/a in t)
var/atom/A = a
if(A.density && A != L)
continue grasping
if(prob(grasp_chance))
to_chat(L, "<span class='userdanger'>\The [src] has you entangled!</span>")
grasping[L] = Beam(L, "vine", time=INFINITY, maxdistance=5, beam_type=/obj/effect/ebeam/vine)
break //only take 1 new victim per cycle
/mob/living/simple_animal/hostile/venus_human_trap/OpenFire(atom/the_target)
var/dist = get_dist(src,the_target)
Beam(the_target, "vine", time=dist*2, maxdistance=dist+2, beam_type=/obj/effect/ebeam/vine)
the_target.attack_animal(src)
/mob/living/simple_animal/hostile/venus_human_trap/CanAttack(atom/the_target)
. = ..()
if(.)
if(the_target in grasping)
return 0
@@ -301,6 +301,9 @@
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
attack_threshold_check(damage,M.melee_damage_type)
/mob/living/simple_animal/proc/attacked_by(obj/item/I, mob/living/user) // Handled in _onclick/click.dm
return
/mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj)
if(!Proj)
return
@@ -579,21 +582,7 @@
density = initial(density)
update_canmove()
/mob/living/simple_animal/show_inv(mob/user as mob)
user.set_machine(src)
var/dat = {"<table>
<tr><td><B>Left Hand:</B></td><td><A href='?src=[UID()];item=[slot_l_hand]'>[(l_hand && !(l_hand.flags&ABSTRACT)) ? l_hand : "<font color=grey>Empty</font>"]</A></td></tr>
<tr><td><B>Right Hand:</B></td><td><A href='?src=[UID()];item=[slot_r_hand]'>[(r_hand && !(r_hand.flags&ABSTRACT)) ? r_hand : "<font color=grey>Empty</font>"]</A></td></tr>
<tr><td>&nbsp;</td></tr>"}
if(can_collar)
dat += "<tr><td><B>Collar:</B></td><td><A href='?src=[UID()];[collar?"remove_inv":"add_inv"]=collar'>[(collar && !(collar.flags&ABSTRACT)) ? collar : "<font color=grey>Empty</font>"]</A></td></tr>"
dat += {"</table>
<A href='?src=[user.UID()];mach_close=mob\ref[src]'>Close</A>
"}
var/datum/browser/popup = new(user, "mob\ref[src]", "[src]", 440, 250)
popup.set_content(dat)
popup.open()
/mob/living/simple_animal/proc/make_babies() // <3 <3 <3
if(gender != FEMALE || stat || !scan_ready || !childtype || !simplespecies)
@@ -652,57 +641,74 @@
if(changed)
animate(src, transform = ntransform, time = 2, easing = EASE_IN|EASE_OUT)
/mob/living/simple_animal/Topic(href, href_list)
if(!usr.stat && usr.canmove && !usr.restrained() && in_range(src, usr))
if(href_list["remove_inv"])
if(!Adjacent(usr) || !(ishuman(usr) || isrobot(usr) || isalienadult(usr)))
return
var/remove_from = href_list["remove_inv"]
switch(remove_from)
if("collar")
if(!can_collar)
return
if(collar)
if(collar.flags & NODROP)
to_chat(usr, "<span class='warning'>\The [collar] is stuck too hard to [src] for you to remove!</span>")
return
collar.dropped(src)
collar.forceMove(src.loc)
collar = null
regenerate_icons()
else
to_chat(usr, "<span class='danger'>There is nothing to remove from its [remove_from].</span>")
return
show_inv(usr)
else if(href_list["add_inv"])
if(!Adjacent(usr) || !(ishuman(usr) || isrobot(usr) || isalienadult(usr)))
return
/* Inventory */
var/add_to = href_list["add_inv"]
switch(add_to)
if("collar")
if(!can_collar || collar)
return
var/obj/item/clothing/accessory/petcollar/C = usr.get_active_hand()
if(!istype(C))
usr.visible_message("[usr] rubs [src]'s neck.","<span class='notice'>You rub [src]'s neck for a moment.</span>")
return
usr.drop_item()
C.forceMove(src)
collar = C
collar.equipped(src)
regenerate_icons()
to_chat(usr, "<span class='notice'>You put \the [C] around \the [src]'s neck.</span>")
if(C.tagname)
name = C.tagname
real_name = C.tagname
show_inv(usr)
/mob/living/simple_animal/show_inv(mob/user as mob)
if(!can_collar)
return
user.set_machine(src)
var/dat = "<table><tr><td><B>Collar:</B></td><td><A href='?src=[UID()];item=[slot_collar]'>[(collar && !(collar.flags&ABSTRACT)) ? collar : "<font color=grey>Empty</font>"]</A></td></tr></table>"
dat += "<A href='?src=[user.UID()];mach_close=mob\ref[src]'>Close</A>"
var/datum/browser/popup = new(user, "mob\ref[src]", "[src]", 440, 250)
popup.set_content(dat)
popup.open()
/mob/living/simple_animal/get_item_by_slot(slot_id)
switch(slot_id)
if(slot_collar)
return collar
. = ..()
/mob/living/simple_animal/can_equip(obj/item/I, slot, disable_warning = 0)
// . = ..() // Do not call parent. We do not want animals using their hand slots.
switch(slot)
if(slot_collar)
if(collar)
return 0
if(!can_collar)
return 0
if(!istype(I, /obj/item/clothing/accessory/petcollar))
return 0
return 1
/mob/living/simple_animal/equip_to_slot(obj/item/W, slot)
if(!istype(W))
return 0
if(!slot)
return 0
W.forceMove(src)
W.equipped(src, slot)
W.layer = 20
W.plane = HUD_PLANE
switch(slot)
if(slot_collar)
collar = W
if(collar.tagname)
name = collar.tagname
real_name = collar.tagname
regenerate_icons()
/mob/living/simple_animal/unEquip(obj/item/I, force)
. = ..()
if(!. || !I)
return
if(I == collar)
collar = null
regenerate_icons()
/mob/living/simple_animal/get_access()
. = ..()
if(collar)
. |= collar.GetAccess()
/* End Inventory */
/mob/living/simple_animal/proc/sentience_act() //Called when a simple animal gains sentience via gold slime potion
return
@@ -40,6 +40,7 @@
return 0
spawn_delay = world.time + spawn_time
var/mob/living/simple_animal/L = new mob_type(src.loc)
L.admin_spawned = admin_spawned //If we were admin spawned, lets have our children count as that as well.
spawned_mobs += L
L.nest = src
L.faction = src.faction
+40 -2
View File
@@ -1222,9 +1222,11 @@ mob/proc/yank_out_object()
if(mind)
return mind.grab_ghost(force = force)
/mob/proc/notify_ghost_cloning(var/message = "Someone is trying to revive you. Re-enter your corpse if you want to be revived!", var/sound = 'sound/effects/genetics.ogg', var/atom/source = null)
/mob/proc/notify_ghost_cloning(message = "Someone is trying to revive you. Re-enter your corpse if you want to be revived!", sound = 'sound/effects/genetics.ogg', atom/source = null, flashwindow = TRUE)
var/mob/dead/observer/ghost = get_ghost()
if(ghost)
if(flashwindow)
window_flash(ghost.client)
ghost.notify_cloning(message, sound, source)
return ghost
@@ -1263,7 +1265,7 @@ mob/proc/yank_out_object()
return // Only living mobs can ventcrawl
//You can buckle on mobs if you're next to them since most are dense
/mob/buckle_mob(mob/living/M)
/mob/buckle_mob(mob/living/M, force = 0)
if(M.buckled)
return 0
var/turf/T = get_turf(src)
@@ -1309,3 +1311,39 @@ mob/proc/yank_out_object()
if(F in target.faction)
return 1
return 0
/mob/proc/create_attack_log(var/text, var/collapse = 1)//forgive me code gods for this shitcode proc
//this proc enables lovely stuff like an attack log that looks like this: "[18:20:29-18:20:45]21x John Smith attacked Andrew Jackson with a crowbar."
//That makes the logs easier to read, but because all of this is stored in strings, weird things have to be used to get it all out.
var/new_log = "\[[time_stamp()]] [text]"
if(length(attack_log) > 0)//if there are other logs already present
var/previous_log = attack_log[length(attack_log)]//get the latest log
var/last_log_is_range = (copytext(previous_log, 10, 11) == "-") //whether the last log is a time range or not. The "-" will be an indicator that it is.
var/x_sign_position = findtext(previous_log, "x")
if(world.timeofday - last_log > 100)//if more than 10 seconds from last log
collapse = 0//don't collapse anyway
//the following checks if the last log has the same contents as the new one
if(last_log_is_range)
if(!(copytext(previous_log, x_sign_position + 13) == text))//the 13 is there because of span classes; you won't see those normally in-game
collapse = 0
else
if(!(copytext(previous_log, 12) == text))
collapse = 0
if(collapse == 1)
var/rep = 0
var/old_timestamp = copytext(previous_log, 2, 10)//copy the first time value. This one doesn't move when it's a timespan, so no biggie
//An attack log entry can either be a time range with multiple occurences of an action or a single one, with just one time stamp
if(last_log_is_range)
rep = text2num(copytext(previous_log, 44, x_sign_position))//get whatever number is right before the 'x'
new_log = "\[[old_timestamp]-[time_stamp()]]<font color='purple'><b>[rep?rep+1:2]x</b></font> [text]"
attack_log -= attack_log[length(attack_log)]//remove the last log
attack_log += new_log
last_log = world.timeofday
+1
View File
@@ -30,6 +30,7 @@
var/lastattacker = null
var/lastattacked = null
var/attack_log = list( )
var/last_log = 0
var/obj/machinery/machine = null
var/other_mobs = null
var/memory = ""
+10 -10
View File
@@ -269,8 +269,8 @@
state = GRAB_NECK
icon_state = "grabbed+1"
assailant.set_dir(get_dir(assailant, affecting))
affecting.attack_log += "\[[time_stamp()]\] <font color='orange'>Has had their neck grabbed by [assailant.name] ([assailant.ckey])</font>"
assailant.attack_log += "\[[time_stamp()]\] <font color='red'>Grabbed the neck of [affecting.name] ([affecting.ckey])</font>"
affecting.create_attack_log("<font color='orange'>Has had their neck grabbed by [assailant.name] ([assailant.ckey])</font>")
assailant.create_attack_log("<font color='red'>Grabbed the neck of [affecting.name] ([affecting.ckey])</font>")
log_attack("<font color='red'>[assailant.name] ([assailant.ckey]) grabbed the neck of [affecting.name] ([affecting.ckey])</font>")
if(!iscarbon(assailant))
affecting.LAssailant = null
@@ -285,8 +285,8 @@
state = GRAB_KILL
assailant.visible_message("<span class='danger'>[assailant] has tightened \his grip on [affecting]'s neck!</span>")
affecting.attack_log += "\[[time_stamp()]\] <font color='orange'>Has been strangled (kill intent) by [assailant.name] ([assailant.ckey])</font>"
assailant.attack_log += "\[[time_stamp()]\] <font color='red'>Strangled (kill intent) [affecting.name] ([affecting.ckey])</font>"
affecting.create_attack_log("<font color='orange'>Has been strangled (kill intent) by [assailant.name] ([assailant.ckey])</font>")
assailant.create_attack_log("<font color='red'>Strangled (kill intent) [affecting.name] ([affecting.ckey])</font>")
msg_admin_attack("[key_name(assailant)] strangled (kill intent) [key_name(affecting)]")
assailant.next_move = world.time + 10
@@ -338,8 +338,8 @@
damage += hat.force * 3
affecting.apply_damage(damage*rand(90, 110)/100, BRUTE, "head", affected.run_armor_check(affecting, "melee"))
playsound(assailant.loc, "swing_hit", 25, 1, -1)
assailant.attack_log += text("\[[time_stamp()]\] <font color='red'>Headbutted [affecting.name] ([affecting.ckey])</font>")
affecting.attack_log += text("\[[time_stamp()]\] <font color='orange'>Headbutted by [assailant.name] ([assailant.ckey])</font>")
assailant.create_attack_log("<font color='red'>Headbutted [affecting.name] ([affecting.ckey])</font>")
affecting.create_attack_log("<font color='orange'>Headbutted by [assailant.name] ([assailant.ckey])</font>")
msg_admin_attack("[key_name(assailant)] has headbutted [key_name(affecting)]")
return
@@ -357,8 +357,8 @@
return
assailant.visible_message("<span class='danger'>[assailant] presses \his fingers into [affecting]'s eyes!</span>")
to_chat(affecting, "<span class='danger'>You feel immense pain as digits are being pressed into your eyes!</span>")
assailant.attack_log += text("\[[time_stamp()]\] <font color='red'>Pressed fingers into the eyes of [affecting.name] ([affecting.ckey])</font>")
affecting.attack_log += text("\[[time_stamp()]\] <font color='orange'>Had fingers pressed into their eyes by [assailant.name] ([assailant.ckey])</font>")
assailant.create_attack_log("<font color='red'>Pressed fingers into the eyes of [affecting.name] ([affecting.ckey])</font>")
affecting.create_attack_log("<font color='orange'>Had fingers pressed into their eyes by [assailant.name] ([assailant.ckey])</font>")
msg_admin_attack("[key_name(assailant)] has pressed his fingers into [key_name(affecting)]'s eyes.")
var/obj/item/organ/internal/eyes/eyes = affected.get_int_organ(/obj/item/organ/internal/eyes)
eyes.damage += rand(3,4)
@@ -396,8 +396,8 @@
user.visible_message("<span class='danger'>[user] devours \the [affecting]!</span>")
if(affecting.mind)
affecting.attack_log += "\[[time_stamp()]\] <font color='orange'>Has been devoured by [attacker.name] ([attacker.ckey])</font>"
attacker.attack_log += "\[[time_stamp()]\] <font color='red'>Devoured [affecting.name] ([affecting.ckey])</font>"
affecting.create_attack_log("<font color='orange'>Has been devoured by [attacker.name] ([attacker.ckey])</font>")
attacker.create_attack_log("<font color='red'>Devoured [affecting.name] ([affecting.ckey])</font>")
msg_admin_attack("[key_name(attacker)] devoured [key_name(affecting)]")
affecting.loc = user
+6 -4
View File
@@ -453,20 +453,22 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HARM)
lname = "<span class='name'>[lname]</span> "
to_chat(M, "<span class='deadsay'>[lname][follow][message]</span>")
/proc/notify_ghosts(var/message, var/ghost_sound = null, var/enter_link = null, var/atom/source = null, var/image/alert_overlay = null, var/attack_not_jump = 0) //Easy notification of ghosts.
/proc/notify_ghosts(message, ghost_sound = null, enter_link = null, atom/source = null, image/alert_overlay = null, attack_not_jump = 0, flashwindow = TRUE, var/action = NOTIFY_JUMP) //Easy notification of ghosts.
for(var/mob/dead/observer/O in player_list)
if(O.client)
to_chat(O, "<span class='ghostalert'>[message][(enter_link) ? " [enter_link]" : ""]<span>")
if(ghost_sound)
O << sound(ghost_sound)
if(flashwindow)
window_flash(O.client)
if(source)
var/obj/screen/alert/notify_jump/A = O.throw_alert("\ref[source]_notify_jump", /obj/screen/alert/notify_jump)
var/obj/screen/alert/notify_action/A = O.throw_alert("\ref[source]_notify_action", /obj/screen/alert/notify_action)
if(A)
if(O.client.prefs && O.client.prefs.UI_style)
A.icon = ui_style2icon(O.client.prefs.UI_style)
A.desc = message
A.attack_not_jump = attack_not_jump
A.jump_target = source
A.action = action
A.target = source
if(!alert_overlay)
var/old_layer = source.layer
var/old_plane = source.plane