Files
Bubberstation/code/game/objects/structures/lavaland/necropolis_tendril.dm
T
JacquerelandGitHub 72174845f5 Basic Watchers & Basilisks (#77630)
## About The Pull Request

This one is a double feature because Watchers and Basilisks share the
same typepath. You might see a couple more of those.
As is tradition I decided to fuck with them rather than just port them.
Here's what's up.

**Basilisks**

![image](https://github.com/tgstation/tgstation/assets/7483112/9e4b0115-65dd-4df7-b62a-21c7be8549bf)

![image](https://github.com/tgstation/tgstation/assets/7483112/59162e68-7d73-4659-9531-5078ff751228)

- Have a new soulless sprite which looks less like a living blue hedge.
- Walk at you and shoot you while you are not in range (just like
before).
- Become supercharged if they become "heated" by lava, lasers, or
temperature weapons. This was a feature they also previously had but
they would never encounter lava, so now it also works if you use the
wrong gun on them.
- Lose their supercharge if you cool them down.
- Otherwise pretty normal mobs.

**Watchers**

https://www.youtube.com/watch?v=kOq_Bf78k5A
Here's a traditional video of me intentionally getting hit by mechanics
(trust me its definitely on purpose)

- They glow emmissively a little bit so you can see them from further
away.
- Their eyes light up about 0.5 seconds before they are able to shoot at
you.
- No longer melee attack, instead try to stay out of melee.
- Will occasionally put you into "Overwatch", meaning they will shoot
you rapidly if you move or act while they're staring at you for a brief
time period (after which you become immune for 12 seconds, and during
which other watchers will play fair and stop shooting at you).
- If they start taking damage they will also start using their "Gaze"
attack, look away or suffer some kind of negative effect!
- - Normal watcher gaze flashes and confuses you.
- - Magmawing watcher gaze obviously burns (and briefly stuns) you.
- - Icewing watcher gaze freezes you and throws you backwards.
- Magnetically attract and eat diamonds. They also used to do this, but
just if they happened to coincidentally walk past some.

**Other accompanying changes**

All basic mobs will now adopt the "stop gliding" trait if they get
slowed down too much.
I moved behaviour for "fire a projectile from this atom" into a helper
proc because I was using it in three places and I will probably use it
in more places. There are probably other places in the existing code
which could be using this.
I think I made the basic mob melee attack forecast default a little more
forgiving, they were fucking me up too much and I am the playtester.

## Why It's Good For The Game

Another one off the list.
New tricks for old dogs.
Framework for making mobs with ranged attacks "fairer" (you can see when
they are ready to shoot you).
More (hopefully) versatile AI behaviours which we will reuse later (I
hope I'm not duplicating one someone already made).
If our players "enjoy" them enough we can give more mobs "don't look at
me" mechanics.
Removes some soul sprites.

## Changelog

🆑
refactor: Basilisks and Watchers now use the basic mob framework. Please
bug report any unusual behaviour.
sprite: Basilisks have new sprites.
add: Basilisks will go into a frenzy if heated by energy weapons or
temperature beams as well as by lava.
add: Watcher eyes will be illuminated briefly when they are ready to
fire at you.
add: Watchers can now briefly put you into "Overwatch" and penalise you
for moving while they can see you.
add: Wounded watchers will occasionally punish players who look at them.
balance: Unusual watcher variants are more likely to appear.
/🆑
2023-08-16 13:04:41 -06:00

139 lines
5.0 KiB
Plaintext

//Necropolis Tendrils, which spawn lavaland monsters and break into a chasm when killed
/obj/structure/spawner/lavaland
name = "necropolis tendril"
desc = "A vile tendril of corruption, originating deep underground. Terrible monsters are pouring out of it."
icon = 'icons/mob/simple/lavaland/nest.dmi'
icon_state = "tendril"
faction = list(FACTION_MINING)
max_mobs = 3
max_integrity = 250
mob_types = list(/mob/living/basic/mining/watcher)
move_resist=INFINITY // just killing it tears a massive hole in the ground, let's not move it
anchored = TRUE
resistance_flags = FIRE_PROOF | LAVA_PROOF
var/gps = null
var/obj/effect/light_emitter/tendril/emitted_light
/obj/structure/spawner/lavaland/goliath
mob_types = list(/mob/living/basic/mining/goliath)
/obj/structure/spawner/lavaland/legion
mob_types = list(/mob/living/simple_animal/hostile/asteroid/hivelord/legion/tendril)
/obj/structure/spawner/lavaland/icewatcher
mob_types = list(/mob/living/basic/mining/watcher/icewing)
GLOBAL_LIST_INIT(tendrils, list())
/obj/structure/spawner/lavaland/Initialize(mapload)
. = ..()
emitted_light = new(loc)
for(var/F in RANGE_TURFS(1, src))
if(ismineralturf(F))
var/turf/closed/mineral/M = F
M.ScrapeAway(null, CHANGETURF_IGNORE_AIR)
AddComponent(/datum/component/gps, "Eerie Signal")
GLOB.tendrils += src
/obj/structure/spawner/lavaland/deconstruct(disassembled)
new /obj/effect/collapse(loc)
return ..()
/obj/structure/spawner/lavaland/examine(mob/user)
var/list/examine_messages = ..()
examine_messages += span_notice("Once this thing gets hurts enough, it triggers a violent final retaliation.")
examine_messages += span_notice("You'll only have a few moments to run up, grab some loot with an open hand, and get out with it.")
return examine_messages
/obj/structure/spawner/lavaland/Destroy()
var/last_tendril = TRUE
if(GLOB.tendrils.len>1)
last_tendril = FALSE
if(last_tendril && !(flags_1 & ADMIN_SPAWNED_1))
if(SSachievements.achievements_enabled)
for(var/mob/living/L in view(7,src))
if(L.stat || !L.client)
continue
L.client.give_award(/datum/award/achievement/boss/tendril_exterminator, L)
L.client.give_award(/datum/award/score/tendril_score, L) //Progresses score by one
GLOB.tendrils -= src
QDEL_NULL(emitted_light)
QDEL_NULL(gps)
return ..()
/obj/effect/light_emitter/tendril
set_luminosity = 4
set_cap = 2.5
light_color = LIGHT_COLOR_LAVA
/obj/effect/collapse
name = "collapsing necropolis tendril"
desc = "Get your loot and get clear!"
layer = TABLE_LAYER
icon = 'icons/mob/simple/lavaland/nest.dmi'
icon_state = "tendril"
anchored = TRUE
density = TRUE
/// weakref list of which mobs have gotten their loot from this effect.
var/list/collected = list()
/// a bit of light as to make less unfair deaths from the chasm
var/obj/effect/light_emitter/tendril/emitted_light
/obj/effect/collapse/Initialize(mapload)
. = ..()
emitted_light = new(loc)
visible_message(span_boldannounce("The tendril writhes in fury as the earth around it begins to crack and break apart! Get back!"))
balloon_alert_to_viewers("interact to grab loot before collapse!", vision_distance = 7)
playsound(loc,'sound/effects/tendril_destroyed.ogg', 200, FALSE, 50, TRUE, TRUE)
addtimer(CALLBACK(src, PROC_REF(collapse)), 50)
/obj/effect/collapse/examine(mob/user)
var/list/examine_messages = ..()
if(isliving(user))
if(has_collected(user))
examine_messages += span_boldnotice("You've grabbed what you can, now get out!")
else
examine_messages += span_boldnotice("You might have some time to grab some goodies with an open hand before it collapses!")
return examine_messages
/obj/effect/collapse/attack_hand(mob/living/collector, list/modifiers)
. = ..()
if(has_collected(collector))
to_chat(collector, span_danger("You've already gotten some loot, just get out of there with it!"))
return
visible_message(span_warning("Something falls free of the tendril!"))
var/obj/structure/closet/crate/necropolis/tendril/loot = new /obj/structure/closet/crate/necropolis/tendril(loc)
collector.start_pulling(loot)
collected += WEAKREF(collector)
/obj/effect/collapse/Destroy()
QDEL_NULL(collected)
QDEL_NULL(emitted_light)
return ..()
///Helper proc that resolves weakrefs to determine if collector is in collected list, returning a boolean.
/obj/effect/collapse/proc/has_collected(mob/collector)
for(var/datum/weakref/weakref as anything in collected)
var/mob/living/resolved = weakref.resolve()
//it could have been collector, it could not have been, we don't care
if(!resolved)
continue
if(resolved == collector)
return TRUE
return FALSE
/obj/effect/collapse/proc/collapse()
for(var/mob/M in range(7,src))
shake_camera(M, 15, 1)
playsound(get_turf(src),'sound/effects/explosionfar.ogg', 200, TRUE)
visible_message(span_boldannounce("The tendril falls inward, the ground around it widening into a yawning chasm!"))
for(var/turf/T in RANGE_TURFS(2,src))
if(!T.density)
T.TerraformTurf(/turf/open/chasm/lavaland, /turf/open/chasm/lavaland, flags = CHANGETURF_INHERIT_AIR)
qdel(src)