mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-10 06:34:45 +01:00
Terror Princess Rework (#13657)
* rework queen eggs, princess caste * add trailing newlines for travis * refactor for code standards * Remove old/incorrect comment from queen.dm * refactor purple.dm, add notification for which area queen is in * princesses no longer lose ventcrawl or gain wallsmash when nesting, deletes MassFlicker() * add status tab info for purples about where their queen is * Simplified princess code: removed NestMode(), NestMode2(). * makes terrors use 'bite' animation when attacking something * status tab spider regeneration helptext * converts queen spit from TOX to BURN, empress single-fire * fixes terror gender, double-examine text. add terrors closing airlocks, remove queen wrap * newline for travis * alter terror spider event balance depending on server pop * white infection sequence: gray, red, brown, green, green * moves #define isterrorspider(A) to __DEFINES\mobs.dm * remove typoed comment * fix: prevent exploit with spam-clicking egglay action button * fix: prevent AI trying to move spiders after a player takes control of them * fix bug where terrors bumping an airlock repeatedly could make it both open and close * clarify comment on event odds * increase queen spit burn damage from 30 to 40 * add: queen webs are now airtight, instead of dealing damage/hallucination * remove spider alert for already-controlled spiders * queen spit naming fix * travis newline * encourage princesses to remain outside vents * fixes calls to CountSpidersDetailed not using list() * makes it easier to debug away mission AI * code quality: more typeless loops * add: killing a queen, also kills most of her offspring * remove walk fix, for splitting into another PR * remove events\spider_terror.dm changes, move to another PR * makes it compile - will still require merge conflict resolving later. * fix: purple webs cause purples to lose sign of queen and die * visible-> near for purples * fix wrong gender on spiders * queen spit now damages structures (like mechs) and other spiders * ghost spacing * show queen living time on examine * Fixes #12969 - terrors getting stuck in web * revert all changes to purple.dm * farie requests 1 * farie refactoring II * var/list/spider_array * var/list/spider_totals * more farie * queen examine laycount, initial eggcount * terror heat vulnerability, refactoring 1/0 vars Co-authored-by: Kyep <Kyep@users.noreply.github.com>
This commit is contained in:
@@ -43,8 +43,8 @@
|
||||
spawncount = 2
|
||||
if(4)
|
||||
// Pretty strong.
|
||||
spider_type = /mob/living/simple_animal/hostile/poison/terror_spider/princess
|
||||
spawncount = 2
|
||||
spider_type = /mob/living/simple_animal/hostile/poison/terror_spider/queen/princess
|
||||
spawncount = 3
|
||||
if(5)
|
||||
// Strongest, only used during highpop.
|
||||
spider_type = /mob/living/simple_animal/hostile/poison/terror_spider/queen
|
||||
|
||||
@@ -42,27 +42,6 @@
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/user = owner
|
||||
user.DoVentSmash()
|
||||
|
||||
// ---------- PRINCESS ACTIONS
|
||||
|
||||
/datum/action/innate/terrorspider/evolvequeen
|
||||
name = "Evolve Queen"
|
||||
icon_icon = 'icons/mob/terrorspider.dmi'
|
||||
button_icon_state = "terror_queen"
|
||||
|
||||
/datum/action/innate/terrorspider/evolvequeen/Activate()
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/princess/user = owner
|
||||
if(!istype(user))
|
||||
to_chat(user, "<span class='warning'>ERROR: attempt to use evolve queen ability on a non-princess</span>")
|
||||
return
|
||||
var/feedings_left = user.feedings_to_evolve - user.fed
|
||||
if(feedings_left > 0)
|
||||
to_chat(user, "<span class='warning'>You must wrap [feedings_left] more humanoid prey before you can do this!</span>")
|
||||
return
|
||||
for(var/mob/living/simple_animal/hostile/poison/terror_spider/queen/Q in GLOB.ts_spiderlist)
|
||||
if(Q.spider_awaymission == user.spider_awaymission)
|
||||
to_chat(user, "<span class='warning'>The presence of another Queen in the area is preventing you from maturing.")
|
||||
return
|
||||
user.evolve_to_queen()
|
||||
|
||||
// ---------- QUEEN ACTIONS
|
||||
|
||||
@@ -93,19 +72,11 @@
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/queen/user = owner
|
||||
user.LayQueenEggs()
|
||||
|
||||
/datum/action/innate/terrorspider/queen/queenfakelings
|
||||
name = "Fake Spiderlings"
|
||||
icon_icon = 'icons/effects/effects.dmi'
|
||||
button_icon_state = "spiderling"
|
||||
|
||||
/datum/action/innate/terrorspider/queen/queenfakelings/Activate()
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/queen/user = owner
|
||||
user.QueenFakeLings()
|
||||
|
||||
// ---------- EMPRESS
|
||||
|
||||
/datum/action/innate/terrorspider/queen/empress/empresserase
|
||||
name = "Erase Brood"
|
||||
name = "Empress Erase Brood"
|
||||
icon_icon = 'icons/effects/blood.dmi'
|
||||
button_icon_state = "mgibbl1"
|
||||
|
||||
@@ -113,6 +84,16 @@
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/user = owner
|
||||
user.EraseBrood()
|
||||
|
||||
/datum/action/innate/terrorspider/queen/empress/empresslings
|
||||
name = "Empresss Spiderlings"
|
||||
icon_icon = 'icons/effects/effects.dmi'
|
||||
button_icon_state = "spiderling"
|
||||
|
||||
/datum/action/innate/terrorspider/queen/empress/empresslings/Activate()
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/user = owner
|
||||
user.EmpressLings()
|
||||
|
||||
|
||||
// ---------- WEB
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/Web()
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
else if(volume < 90)
|
||||
// bitten thrice, die quickly, severe muscle cramps make movement very difficult. Even calling for help probably won't save you.
|
||||
// total damage: 4, human health 150 until crit, = 37.5 ticks, = 75s = 1m15s until death
|
||||
update_flags |= M.adjustToxLoss(4, FALSE) // a bit worse than coiine
|
||||
update_flags |= M.adjustToxLoss(4, FALSE)
|
||||
update_flags |= M.EyeBlurry(6, FALSE)
|
||||
M.Confused(6)
|
||||
else
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
ventcrawler = 1
|
||||
idle_ventcrawl_chance = 0
|
||||
ai_playercontrol_allowtype = 0
|
||||
rapid = 3
|
||||
canlay = 1000
|
||||
spider_tier = TS_TIER_5
|
||||
projectiletype = /obj/item/projectile/terrorqueenspit/empress
|
||||
@@ -35,6 +34,8 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/New()
|
||||
..()
|
||||
empresslings_action = new()
|
||||
empresslings_action.Grant(src)
|
||||
empresserase_action = new()
|
||||
empresserase_action.Grant(src)
|
||||
|
||||
@@ -44,7 +45,6 @@
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/NestMode()
|
||||
..()
|
||||
queeneggs_action.button.name = "Empress Eggs"
|
||||
queenfakelings_action.button.name = "Empress Lings"
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/LayQueenEggs()
|
||||
var/eggtype = input("What kind of eggs?") as null|anything in list(TS_DESC_QUEEN, TS_DESC_MOTHER, TS_DESC_PRINCE, TS_DESC_PRINCESS, TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN, TS_DESC_BLACK, TS_DESC_PURPLE, TS_DESC_WHITE, TS_DESC_BROWN)
|
||||
@@ -70,7 +70,7 @@
|
||||
if(TS_DESC_PRINCE)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/prince, numlings)
|
||||
if(TS_DESC_PRINCESS)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/princess, numlings)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess, numlings)
|
||||
if(TS_DESC_MOTHER)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/mother, numlings)
|
||||
if(TS_DESC_QUEEN)
|
||||
@@ -78,7 +78,7 @@
|
||||
else
|
||||
to_chat(src, "<span class='danger'>Unrecognized egg type.</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/QueenFakeLings()
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/proc/EmpressLings()
|
||||
var/numlings = input("How many?") as null|anything in list(10, 20, 30, 40, 50)
|
||||
var/sbpc = input("%chance to be stillborn?") as null|anything in list(0, 25, 50, 75, 100)
|
||||
for(var/i=0, i<numlings, i++)
|
||||
@@ -96,7 +96,8 @@
|
||||
S.amount_grown = 250
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/proc/EraseBrood()
|
||||
for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in GLOB.ts_spiderlist)
|
||||
for(var/thing in GLOB.ts_spiderlist)
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing
|
||||
if(T.spider_tier < spider_tier)
|
||||
T.degenerate = 1
|
||||
to_chat(T, "<span class='userdanger'>Through the hivemind, the raw power of [src] floods into your body, burning it from the inside out!</span>")
|
||||
@@ -106,8 +107,6 @@
|
||||
qdel(T)
|
||||
to_chat(src, "<span class='userdanger'>All Terror Spiders, except yourself, will die off shortly.</span>")
|
||||
|
||||
|
||||
/obj/item/projectile/terrorqueenspit/empress
|
||||
damage_type = BURN
|
||||
damage = 30
|
||||
bonus_tox = 0
|
||||
damage = 90
|
||||
|
||||
|
||||
@@ -39,11 +39,10 @@
|
||||
to_chat(src, "<span class='warning'>You must wrap more humanoid prey before you can do this!</span>")
|
||||
return
|
||||
var/list/eggtypes = list(TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN)
|
||||
var/num_brown = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/brown)
|
||||
if(num_brown < 2)
|
||||
var/list/spider_array = CountSpidersDetailed(FALSE)
|
||||
if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/brown] < 2)
|
||||
eggtypes += TS_DESC_BROWN
|
||||
var/num_black = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/black)
|
||||
if(num_black < 2)
|
||||
if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/black] < 2)
|
||||
eggtypes += TS_DESC_BLACK
|
||||
var/eggtype = pick(eggtypes)
|
||||
if(client)
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/DoHiveSense()
|
||||
var/hsline = ""
|
||||
to_chat(src, "Your Brood: ")
|
||||
for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in GLOB.ts_spiderlist)
|
||||
for(var/thing in GLOB.ts_spiderlist)
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing
|
||||
if(T.spider_awaymission != spider_awaymission)
|
||||
continue
|
||||
hsline = "* [T] in [get_area(T)], "
|
||||
@@ -20,21 +21,55 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/CountSpiders()
|
||||
var/numspiders = 0
|
||||
for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in GLOB.ts_spiderlist)
|
||||
for(var/thing in GLOB.ts_spiderlist)
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing
|
||||
if(T.stat != DEAD && !T.spider_placed && spider_awaymission == T.spider_awaymission)
|
||||
numspiders += 1
|
||||
return numspiders
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/CountSpidersType(specific_type)
|
||||
var/numspiders = 0
|
||||
for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in GLOB.ts_spiderlist)
|
||||
if(T.stat != DEAD && !T.spider_placed && spider_awaymission == T.spider_awaymission)
|
||||
if(T.type == specific_type)
|
||||
numspiders += 1
|
||||
for(var/obj/structure/spider/eggcluster/terror_eggcluster/E in GLOB.ts_egg_list)
|
||||
if(E.spiderling_type == specific_type && E.z == z)
|
||||
numspiders += E.spiderling_number
|
||||
for(var/obj/structure/spider/spiderling/terror_spiderling/L in GLOB.ts_spiderling_list)
|
||||
if(!L.stillborn && L.grow_as == specific_type && L.z == z)
|
||||
numspiders += 1
|
||||
return numspiders
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/CountSpidersDetailed(check_mine = FALSE, list/mytypes = list())
|
||||
var/list/spider_totals = list("all" = 0)
|
||||
var/check_list = length(mytypes) > 0
|
||||
for(var/thistype in mytypes)
|
||||
spider_totals[thistype] = 0
|
||||
for(var/thing in GLOB.ts_spiderlist)
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing
|
||||
if(T.stat == DEAD || T.spider_placed || spider_awaymission != T.spider_awaymission)
|
||||
continue
|
||||
if(check_mine && T.spider_myqueen != src)
|
||||
continue
|
||||
if(check_list && !(T.type in mytypes))
|
||||
continue
|
||||
if(T == src)
|
||||
continue
|
||||
if(spider_totals[T.type])
|
||||
spider_totals[T.type]++
|
||||
else
|
||||
spider_totals[T.type] = 1
|
||||
spider_totals["all"]++
|
||||
for(var/thing in GLOB.ts_egg_list)
|
||||
var/obj/structure/spider/eggcluster/terror_eggcluster/E = thing
|
||||
if(check_mine && E.spider_myqueen != src)
|
||||
continue
|
||||
if(check_list && E.spiderling_type && !(E.spiderling_type in mytypes))
|
||||
continue
|
||||
if(spider_totals[E.spiderling_type])
|
||||
spider_totals[E.spiderling_type] += E.spiderling_number
|
||||
else
|
||||
spider_totals[E.spiderling_type] = E.spiderling_number
|
||||
spider_totals["all"] += E.spiderling_number
|
||||
for(var/thing in GLOB.ts_spiderling_list)
|
||||
var/obj/structure/spider/spiderling/terror_spiderling/L = thing
|
||||
if(L.stillborn)
|
||||
continue
|
||||
if(check_mine && L.spider_myqueen != src)
|
||||
continue
|
||||
if(check_list && L.grow_as && !(L.grow_as in mytypes))
|
||||
continue
|
||||
if(spider_totals[L.grow_as])
|
||||
spider_totals[L.grow_as]++
|
||||
else
|
||||
spider_totals[L.grow_as] = 1
|
||||
spider_totals["all"]++
|
||||
return spider_totals
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
spider_opens_doors = 2
|
||||
web_type = /obj/structure/spider/terrorweb/purple
|
||||
ai_spins_webs = FALSE
|
||||
gender = MALE
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/prince/death(gibbed)
|
||||
if(can_die() && !hasdied && spider_uo71)
|
||||
|
||||
@@ -2,58 +2,76 @@
|
||||
// --------------------------------------------------------------------------------
|
||||
// ----------------- TERROR SPIDERS: T3 PRINCESS OF TERROR --------------------------
|
||||
// --------------------------------------------------------------------------------
|
||||
// -------------: ROLE: cutesy
|
||||
// -------------: AI: as green, but will evolve to queen when it can
|
||||
// -------------: SPECIAL: can evolve into a queen, if fed enough
|
||||
// -------------: TO FIGHT IT: kill it before it evolves
|
||||
// -------------: ROLE: mini-queen, maintains a smaller nest, but also more expendable
|
||||
// -------------: AI: maintains a small group of spiders. Small fraction of a queen's nest.
|
||||
// -------------: SPECIAL: lays eggs over time, like a queen
|
||||
// -------------: TO FIGHT IT: hunt it before it lays eggs
|
||||
// -------------: SPRITES FROM: FoS, https://www.paradisestation.org/forum/profile/335-fos
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/princess
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess
|
||||
name = "Princess of Terror spider"
|
||||
desc = "An enormous spider. It looks strangely cute and fluffy."
|
||||
spider_role_summary = "Future Queen"
|
||||
spider_role_summary = "Mini-Queen"
|
||||
ai_target_method = TS_DAMAGE_SIMPLE
|
||||
icon_state = "terror_princess1"
|
||||
icon_living = "terror_princess1"
|
||||
icon_dead = "terror_princess1_dead"
|
||||
maxHealth = 150
|
||||
health = 150
|
||||
regen_points_per_hp = 1 // always regens very fast
|
||||
force_threshold = 18 // outright immune to anything of force under 18, same as queen
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 20
|
||||
idle_ventcrawl_chance = 5
|
||||
spider_tier = TS_TIER_3
|
||||
spider_opens_doors = 2
|
||||
web_type = /obj/structure/spider/terrorweb/queen
|
||||
var/feedings_to_evolve = 3
|
||||
var/datum/action/innate/terrorspider/ventsmash/ventsmash_action
|
||||
var/datum/action/innate/terrorspider/evolvequeen/evolvequeen_action
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/princess/New()
|
||||
..()
|
||||
ventsmash_action = new()
|
||||
ventsmash_action.Grant(src)
|
||||
evolvequeen_action = new()
|
||||
evolvequeen_action.Grant(src)
|
||||
// Unlike queens, no ranged attack.
|
||||
ranged = 0
|
||||
retreat_distance = 0
|
||||
minimum_distance = 0
|
||||
projectilesound = null
|
||||
projectiletype = null
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/princess/proc/evolve_to_queen()
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/queen/Q = new(loc)
|
||||
if(mind)
|
||||
mind.transfer_to(Q)
|
||||
// Calling `transfer_to()` removes our new body (the Queen's) ability to see the med hud, so we have to re-add the queen here.
|
||||
var/datum/atom_hud/U = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
|
||||
U.add_hud_to(Q)
|
||||
qdel(src)
|
||||
canlay = 0
|
||||
hasnested = TRUE
|
||||
spider_spawnfrequency = 300 // 30 seconds
|
||||
var/grant_prob = 25 // 25% chance every spider_spawnfrequency seconds to gain 1 egg
|
||||
var/spider_max_children = 8
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/princess/DoWrap()
|
||||
. = ..()
|
||||
if(fed == 0)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/grant_queen_subtype_abilities()
|
||||
// Queens start in movement mode, where they can ventcrawl but not lay eggs. Then they move to NestMode() where they can wallsmash and egglay, but not ventcrawl.
|
||||
// Princesses are simpler, and can always lay eggs, always vent crawl, but never smash walls. Unlike queens, they don't have a "nesting" transformation.
|
||||
queeneggs_action = new()
|
||||
queeneggs_action.Grant(src)
|
||||
queensense_action = new()
|
||||
queensense_action.Grant(src)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/ListAvailableEggTypes()
|
||||
var/list/valid_types = list(TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN)
|
||||
|
||||
// Each princess can also have ONE black/purple/brown. If it dies, they can pick a new spider from the 3 advanced types to lay.
|
||||
var/list/spider_array = CountSpidersDetailed(TRUE, list(/mob/living/simple_animal/hostile/poison/terror_spider/black, /mob/living/simple_animal/hostile/poison/terror_spider/purple, /mob/living/simple_animal/hostile/poison/terror_spider/brown))
|
||||
if(spider_array["all"] < 1)
|
||||
valid_types |= TS_DESC_BLACK
|
||||
valid_types |= TS_DESC_PURPLE
|
||||
valid_types |= TS_DESC_BROWN
|
||||
|
||||
return valid_types
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/grant_eggs()
|
||||
spider_lastspawn = world.time
|
||||
|
||||
if(!prob(grant_prob))
|
||||
return
|
||||
|
||||
var/list/spider_array = CountSpidersDetailed(TRUE)
|
||||
var/brood_count = spider_array["all"]
|
||||
|
||||
// Color shifts depending on how much of their brood capacity they have used.
|
||||
if(brood_count == 0)
|
||||
icon_state = "terror_princess1"
|
||||
icon_living = "terror_princess1"
|
||||
icon_dead = "terror_princess1_dead"
|
||||
desc = "An enormous spider. It looks strangely cute and fluffy, with soft pink fur covering most of its body."
|
||||
else if(fed == 1)
|
||||
else if(brood_count < (spider_max_children /2))
|
||||
icon_state = "terror_princess2"
|
||||
icon_living = "terror_princess2"
|
||||
icon_dead = "terror_princess2_dead"
|
||||
@@ -62,13 +80,45 @@
|
||||
icon_state = "terror_princess3"
|
||||
icon_living = "terror_princess3"
|
||||
icon_dead = "terror_princess3_dead"
|
||||
desc = "An enormous spider. Its entire body has turned an ominous blood red color, with actual blood dripping from its jaws. It stares around, hungrily."
|
||||
desc = "An enormous spider. Its entire body looks to be the color of dried blood."
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/princess/spider_special_action()
|
||||
if(cocoon_target)
|
||||
handle_cocoon_target()
|
||||
else if(fed >= feedings_to_evolve)
|
||||
evolve_to_queen()
|
||||
else if(world.time > (last_cocoon_object + freq_cocoon_object))
|
||||
seek_cocoon_target()
|
||||
if(!isturf(loc))
|
||||
to_chat(src, "<span class='danger'>You cannot generate eggs while hiding in [loc].</span>")
|
||||
return
|
||||
|
||||
if((brood_count + canlay) >= spider_max_children)
|
||||
return
|
||||
canlay++
|
||||
if(canlay == 1)
|
||||
to_chat(src, "<span class='notice'>You have an egg available to lay.</span>")
|
||||
else
|
||||
to_chat(src, "<span class='notice'>You have [canlay] eggs available to lay.</span>")
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/NestMode()
|
||||
// Princesses don't nest. However, we still need to override this in case an AI princess calls it.
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/spider_special_action()
|
||||
// Princess AI routine. GREATLY simplified version of queen routine.
|
||||
if(!stat && !ckey)
|
||||
// Utilize normal queen AI for finding a nest site (neststep=0), and activating NestMode() (neststep=1)
|
||||
if(neststep != 2)
|
||||
return ..()
|
||||
// After that, simply lay an egg once per nestfrequency, until we have the max.
|
||||
if(world.time < (lastnestsetup + nestfrequency))
|
||||
return
|
||||
lastnestsetup = world.time
|
||||
if(ai_nest_is_full())
|
||||
return
|
||||
spider_lastspawn = world.time
|
||||
DoLayTerrorEggs(pick(spider_types_standard), 1)
|
||||
// Yes, this means NPC princesses won't create T2 spiders.
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/ai_nest_is_full()
|
||||
var/list/spider_array = CountSpidersDetailed(TRUE)
|
||||
if(spider_array["all"] >= spider_max_children)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// -------------: ROLE: gamma-level threat to the whole station, like a blob
|
||||
// -------------: AI: builds a nest, lays many eggs, attempts to take over the station
|
||||
// -------------: SPECIAL: spins webs, breaks lights, breaks cameras, webs objects, lays eggs, commands other spiders...
|
||||
// -------------: TO FIGHT IT: bring an army, and take no prisoners. Mechs and/or decloner guns are a very good idea.
|
||||
// -------------: TO FIGHT IT: bring an army, and take no prisoners. Mechs are a very good idea.
|
||||
// -------------: SPRITES FROM: IK3I
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen
|
||||
@@ -43,69 +43,94 @@
|
||||
var/neststep = 0
|
||||
var/hasnested = FALSE
|
||||
var/spider_max_per_nest = 35 // above this, AI queens become stable
|
||||
var/canlay = 4 // main counter for egg-laying ability! # = num uses, incremented at intervals
|
||||
var/canlay = 5 // main counter for egg-laying ability! # = num uses, incremented at intervals
|
||||
var/eggslaid = 0
|
||||
var/spider_can_fakelings = 3 // spawns defective spiderlings that don't grow up, used to freak out crew, atmosphere
|
||||
var/list/spider_types_standard = list(/mob/living/simple_animal/hostile/poison/terror_spider/red, /mob/living/simple_animal/hostile/poison/terror_spider/gray, /mob/living/simple_animal/hostile/poison/terror_spider/green, /mob/living/simple_animal/hostile/poison/terror_spider/black)
|
||||
var/datum/action/innate/terrorspider/queen/queennest/queennest_action
|
||||
var/datum/action/innate/terrorspider/queen/queensense/queensense_action
|
||||
var/datum/action/innate/terrorspider/queen/queeneggs/queeneggs_action
|
||||
var/datum/action/innate/terrorspider/queen/queenfakelings/queenfakelings_action
|
||||
var/datum/action/innate/terrorspider/ventsmash/ventsmash_action
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/New()
|
||||
..()
|
||||
queennest_action = new()
|
||||
queennest_action.Grant(src)
|
||||
ventsmash_action = new()
|
||||
ventsmash_action.Grant(src)
|
||||
grant_queen_subtype_abilities()
|
||||
spider_myqueen = src
|
||||
if(spider_awaymission)
|
||||
spider_growinstantly = 1
|
||||
spider_growinstantly = TRUE
|
||||
spider_spawnfrequency = 150
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/grant_queen_subtype_abilities()
|
||||
queennest_action = new()
|
||||
queennest_action.Grant(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/Life(seconds, times_fired)
|
||||
. = ..()
|
||||
if(stat != DEAD) // Can't use if(.) for this due to the fact it can sometimes return FALSE even when mob is alive.
|
||||
if(ckey && canlay < 12 && hasnested) // max 12 eggs worth stored at any one time, realistically that's tons.
|
||||
if(ckey && hasnested)
|
||||
if(world.time > (spider_lastspawn + spider_spawnfrequency))
|
||||
if(eggslaid >= 20)
|
||||
canlay += 3
|
||||
else if(eggslaid >= 10)
|
||||
canlay += 2
|
||||
else
|
||||
canlay++
|
||||
spider_lastspawn = world.time
|
||||
if(canlay == 1)
|
||||
to_chat(src, "<span class='notice'>You have an egg available to lay.</span>")
|
||||
else if(canlay == 12)
|
||||
to_chat(src, "<span class='notice'>You have [canlay] eggs available to lay. You won't grow any more eggs until you lay some of your existing ones.</span>")
|
||||
else
|
||||
to_chat(src, "<span class='notice'>You have [canlay] eggs available to lay.</span>")
|
||||
grant_eggs()
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/grant_eggs()
|
||||
spider_lastspawn = world.time
|
||||
canlay += getSpiderLevel()
|
||||
if(canlay == 1)
|
||||
to_chat(src, "<span class='notice'>You have an egg available to lay.</span>")
|
||||
else if(canlay > 1)
|
||||
to_chat(src, "<span class='notice'>You have [canlay] eggs available to lay.</span>")
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/getSpiderLevel()
|
||||
return 1 + round(MinutesAlive() / 10)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/MinutesAlive()
|
||||
return round((world.time - spider_creation_time) / 600)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/death(gibbed)
|
||||
if(can_die() && !hasdied)
|
||||
if(spider_uo71)
|
||||
UnlockBlastDoors("UO71_Caves")
|
||||
// When a queen dies, so do her player-controlled purple-type guardians. Intended as a motivator for purples to ensure they guard her.
|
||||
for(var/mob/living/simple_animal/hostile/poison/terror_spider/purple/P in GLOB.ts_spiderlist)
|
||||
if(ckey)
|
||||
P.visible_message("<span class='danger'>\The [src] writhes in pain!</span>")
|
||||
to_chat(P,"<span class='userdanger'>\The [src] has died. Without her hivemind link, purple terrors like yourself cannot survive more than a few minutes!</span>")
|
||||
P.degenerate = 1
|
||||
// When a queen (or subtype!) dies, so do all of her spiderlings, and half of all her fully grown offspring
|
||||
// This feature is intended to provide a way for crew to still win even if the queen has overwhelming numbers - by sniping the queen.
|
||||
for(var/thing in GLOB.ts_spiderlist)
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing
|
||||
if(!T.spider_myqueen)
|
||||
continue
|
||||
if(T.spider_myqueen != src)
|
||||
continue
|
||||
if(prob(50) || T.spider_tier >= spider_tier)
|
||||
to_chat(T, "<span class='userdanger'>\The psychic backlash from the death of [src] crashes into your mind! Somehow... you find a way to keep going!</span>")
|
||||
continue
|
||||
T.visible_message("<span class='danger'>[T] writhes in pain!</span>")
|
||||
to_chat(T, "<span class='userdanger'>\The psychic backlash from the death of [src] overwhelms you! You feel the life start to drain out of you...</span>")
|
||||
T.degenerate = TRUE
|
||||
for(var/thing in GLOB.ts_spiderling_list)
|
||||
var/obj/structure/spider/spiderling/terror_spiderling/T = thing
|
||||
if(T.spider_myqueen && T.spider_myqueen == src)
|
||||
qdel(T)
|
||||
return ..()
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/Retaliate()
|
||||
..()
|
||||
for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in GLOB.ts_spiderlist)
|
||||
for(var/thing in GLOB.ts_spiderlist)
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing
|
||||
T.enemies |= enemies
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/ai_nest_is_full()
|
||||
var/numspiders = CountSpiders()
|
||||
if(numspiders >= spider_max_per_nest)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/spider_special_action()
|
||||
if(!stat && !ckey)
|
||||
switch(neststep)
|
||||
@@ -152,11 +177,13 @@
|
||||
neststep = 2
|
||||
NestMode()
|
||||
if(2)
|
||||
// Create initial four purple nest guards.
|
||||
// Create initial T2 spiders.
|
||||
if(world.time > (lastnestsetup + nestfrequency))
|
||||
lastnestsetup = world.time
|
||||
spider_lastspawn = world.time
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, 4)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, 2)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/white, 2)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/brown, 2)
|
||||
neststep = 3
|
||||
if(3)
|
||||
// Create spiders (random types) until nest is full.
|
||||
@@ -183,28 +210,26 @@
|
||||
neststep = 4
|
||||
else
|
||||
spider_lastspawn = world.time
|
||||
var/num_purple = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/purple)
|
||||
var/num_white = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/white)
|
||||
var/num_brown = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/brown)
|
||||
if(num_purple < 4)
|
||||
var/list/spider_array = CountSpidersDetailed(FALSE)
|
||||
if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/purple] < 4)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, 2)
|
||||
else if(num_white < 2)
|
||||
else if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/white] < 2)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/white, 2)
|
||||
else if(num_brown < 4)
|
||||
else if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/brown] < 4)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/brown, 4)
|
||||
else
|
||||
DoLayTerrorEggs(pick(spider_types_standard), 5)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/NestPrompt()
|
||||
var/confirm = alert(src, "Are you sure you want to nest? You will be able to lay eggs, and smash walls, but not ventcrawl.","Nest?","Yes","No")
|
||||
if(confirm == "Yes")
|
||||
NestMode()
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/NestMode()
|
||||
queeneggs_action = new()
|
||||
queeneggs_action.Grant(src)
|
||||
queenfakelings_action = new()
|
||||
queenfakelings_action.Grant(src)
|
||||
queensense_action = new()
|
||||
queensense_action.Grant(src)
|
||||
queennest_action.Remove(src)
|
||||
@@ -213,21 +238,8 @@
|
||||
ai_ventcrawls = FALSE
|
||||
environment_smash = ENVIRONMENT_SMASH_RWALLS
|
||||
DoQueenScreech(8, 100, 8, 100)
|
||||
MassFlicker()
|
||||
to_chat(src, "<span class='notice'>You have matured to your egglaying stage. You can now smash through walls, and lay eggs, but can no longer ventcrawl.</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/MassFlicker()
|
||||
var/list/target_lights = list()
|
||||
for(var/mob/living/carbon/human/H in GLOB.player_list)
|
||||
if(H.z != z)
|
||||
continue
|
||||
if(H.stat == DEAD)
|
||||
continue
|
||||
for(var/obj/machinery/light/L in orange(7, H))
|
||||
if(L.on && prob(25))
|
||||
target_lights += L
|
||||
for(var/obj/machinery/light/I in target_lights)
|
||||
I.flicker()
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/LayQueenEggs()
|
||||
if(stat == DEAD)
|
||||
@@ -242,42 +254,21 @@
|
||||
else
|
||||
to_chat(src, "<span class='danger'>Too soon to attempt that again. Wait just a few more seconds...</span>")
|
||||
return
|
||||
var/list/eggtypes = list(TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN, TS_DESC_BLACK, TS_DESC_PURPLE)
|
||||
if(canlay >= 4)
|
||||
eggtypes |= TS_DESC_BROWN
|
||||
if(canlay >= 12)
|
||||
eggtypes |= TS_DESC_MOTHER
|
||||
eggtypes |= TS_DESC_PRINCE
|
||||
var/num_purples = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/purple)
|
||||
if(num_purples >= 2)
|
||||
eggtypes -= TS_DESC_PURPLE
|
||||
var/num_blacks = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/black)
|
||||
if(num_blacks >= 2)
|
||||
eggtypes -= TS_DESC_BLACK
|
||||
var/list/eggtypes = ListAvailableEggTypes()
|
||||
var/list/eggtypes_uncapped = list(TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN)
|
||||
|
||||
var/eggtype = input("What kind of eggs?") as null|anything in eggtypes
|
||||
if(canlay < 1)
|
||||
// this was checked before input() but we have to check again to prevent them spam-clicking the popup.
|
||||
to_chat(src, "<span class='danger'>Too soon to lay another egg.</span>")
|
||||
return
|
||||
if(!(eggtype in eggtypes))
|
||||
to_chat(src, "<span class='danger'>Unrecognized egg type.</span>")
|
||||
return 0
|
||||
if(eggtype == TS_DESC_MOTHER || eggtype == TS_DESC_PRINCE)
|
||||
if(canlay < 12)
|
||||
to_chat(src, "<span class='danger'>Insufficient strength. It takes as much effort to lay one of those as it does to lay 12 normal eggs.</span>")
|
||||
else
|
||||
if(eggtype == TS_DESC_MOTHER)
|
||||
canlay -= 12
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/mother, 1)
|
||||
else if(eggtype == TS_DESC_PRINCE)
|
||||
canlay -= 12
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/prince, 1)
|
||||
return
|
||||
else if(eggtype == TS_DESC_BROWN)
|
||||
if(canlay < 4)
|
||||
to_chat(src, "<span class='danger'>Insufficient strength. It takes as much effort to lay one of those as it does to lay 4 normal eggs.</span>")
|
||||
else
|
||||
canlay -= 4
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/brown, 1)
|
||||
return
|
||||
|
||||
// Multiple of eggtypes_uncapped can be laid at once. Other types must be laid one at a time (to prevent exploits)
|
||||
var/numlings = 1
|
||||
if(eggtype != TS_DESC_PURPLE)
|
||||
if(eggtype in eggtypes_uncapped)
|
||||
if(canlay >= 5)
|
||||
numlings = input("How many in the batch?") as null|anything in list(1, 2, 3, 4, 5)
|
||||
else if(canlay >= 3)
|
||||
@@ -287,27 +278,55 @@
|
||||
if(eggtype == null || numlings == null)
|
||||
to_chat(src, "<span class='danger'>Cancelled.</span>")
|
||||
return
|
||||
// Actually lay the eggs.
|
||||
if(canlay < numlings)
|
||||
// We have to check this again after the popups, to account for people spam-clicking the button, then doing all the popups at once.
|
||||
to_chat(src, "<span class='warning'>Too soon to do this again!</span>")
|
||||
return
|
||||
canlay -= numlings
|
||||
eggslaid += numlings
|
||||
if(eggtype == TS_DESC_RED)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/red, numlings)
|
||||
else if(eggtype == TS_DESC_GRAY)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/gray, numlings)
|
||||
else if(eggtype == TS_DESC_GREEN)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/green, numlings)
|
||||
else if(eggtype == TS_DESC_BLACK)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/black, numlings)
|
||||
else if(eggtype == TS_DESC_PURPLE)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, numlings)
|
||||
else
|
||||
to_chat(src, "<span class='danger'>Unrecognized egg type.</span>")
|
||||
switch(eggtype)
|
||||
if(TS_DESC_RED)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/red, numlings)
|
||||
if(TS_DESC_GRAY)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/gray, numlings)
|
||||
if(TS_DESC_GREEN)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/green, numlings)
|
||||
if(TS_DESC_BLACK)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/black, numlings)
|
||||
if(TS_DESC_PURPLE)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, numlings)
|
||||
if(TS_DESC_BROWN)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/brown, numlings)
|
||||
if(TS_DESC_MOTHER)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/mother, numlings)
|
||||
if(TS_DESC_PRINCE)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/prince, numlings)
|
||||
if(TS_DESC_PRINCESS)
|
||||
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess, numlings)
|
||||
else
|
||||
to_chat(src, "<span class='danger'>Unrecognized egg type.</span>")
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/ListAvailableEggTypes()
|
||||
if(MinutesAlive() >= 20)
|
||||
var/list/spider_array = CountSpidersDetailed(TRUE, list(/mob/living/simple_animal/hostile/poison/terror_spider/mother, /mob/living/simple_animal/hostile/poison/terror_spider/prince, /mob/living/simple_animal/hostile/poison/terror_spider/queen/princess))
|
||||
if(spider_array["all"] == 0)
|
||||
return list(TS_DESC_PRINCE, TS_DESC_PRINCESS) // Mother will be added to this list.... AFTER mothers are reworked.
|
||||
|
||||
var/list/valid_types = list(TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN)
|
||||
var/list/spider_array = CountSpidersDetailed(FALSE, list(/mob/living/simple_animal/hostile/poison/terror_spider/brown, /mob/living/simple_animal/hostile/poison/terror_spider/purple, /mob/living/simple_animal/hostile/poison/terror_spider/black))
|
||||
if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/brown] < 2)
|
||||
valid_types += TS_DESC_BROWN
|
||||
if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/purple] < 2)
|
||||
valid_types += TS_DESC_PURPLE
|
||||
if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/black] < 2)
|
||||
valid_types += TS_DESC_BLACK
|
||||
return valid_types
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/DoQueenScreech(light_range, light_chance, camera_range, camera_chance)
|
||||
visible_message("<span class='userdanger'>\The [src] emits a bone-chilling shriek!</span>")
|
||||
visible_message("<span class='userdanger'>[src] emits a bone-chilling shriek!</span>")
|
||||
for(var/obj/machinery/light/L in orange(light_range, src))
|
||||
if(L.on && prob(light_chance))
|
||||
L.break_light_tube()
|
||||
@@ -315,46 +334,33 @@
|
||||
if(C.status && prob(camera_chance))
|
||||
C.toggle_cam(src, 0)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/QueenFakeLings()
|
||||
if(eggslaid < 10)
|
||||
to_chat(src, "<span class='danger'>You must lay at least 10 eggs before doing this.</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/examine(mob/user)
|
||||
. = ..()
|
||||
if(!key || stat == DEAD)
|
||||
return
|
||||
if(spider_can_fakelings)
|
||||
spider_can_fakelings--
|
||||
var/numlings = 25
|
||||
for(var/i in 1 to numlings)
|
||||
var/obj/structure/spider/spiderling/terror_spiderling/S = new /obj/structure/spider/spiderling/terror_spiderling(get_turf(src))
|
||||
S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/red
|
||||
S.stillborn = 1
|
||||
S.spider_mymother = src
|
||||
if(!spider_can_fakelings)
|
||||
queenfakelings_action.Remove(src)
|
||||
else
|
||||
to_chat(src, "<span class='danger'>You have run out of uses of this ability.</span>")
|
||||
if(!isobserver(user) && !isterrorspider(user))
|
||||
return
|
||||
. += "<span class='notice'>[p_they(TRUE)] has laid [eggslaid] egg[eggslaid != 1 ? "s" : ""].</span>"
|
||||
. += "<span class='notice'>[p_they(TRUE)] has lived for [MinutesAlive()] minutes.</span>"
|
||||
|
||||
|
||||
/obj/item/projectile/terrorqueenspit
|
||||
name = "poisonous spit"
|
||||
damage = 0
|
||||
name = "acid spit"
|
||||
damage = 40
|
||||
icon_state = "toxin"
|
||||
damage_type = TOX
|
||||
var/bonus_tox = 30
|
||||
damage_type = BURN
|
||||
|
||||
/obj/item/projectile/terrorqueenspit/on_hit(mob/living/carbon/target, blocked = 0, hit_zone)
|
||||
if(ismob(target) && blocked < 100)
|
||||
var/mob/living/L = target
|
||||
if(L.reagents)
|
||||
if(L.can_inject(null, FALSE, "chest", FALSE))
|
||||
L.Hallucinate(400)
|
||||
if(!isterrorspider(L))
|
||||
L.adjustToxLoss(bonus_tox)
|
||||
|
||||
/obj/structure/spider/terrorweb/queen
|
||||
name = "shimmering web"
|
||||
desc = "This web seems to shimmer all different colors in the light."
|
||||
name = "airtight web"
|
||||
desc = "This multi-layered web seems to be able to resist air pressure."
|
||||
|
||||
|
||||
/obj/structure/spider/terrorweb/queen/New()
|
||||
. = ..()
|
||||
air_update_turf(TRUE)
|
||||
|
||||
/obj/structure/spider/terrorweb/queen/CanAtmosPass(turf/T)
|
||||
return FALSE
|
||||
|
||||
/obj/structure/spider/terrorweb/queen/web_special_ability(mob/living/carbon/C)
|
||||
if(istype(C))
|
||||
var/inject_target = pick("chest","head")
|
||||
if(C.can_inject(null, FALSE, inject_target, FALSE))
|
||||
C.Hallucinate(400)
|
||||
C.adjustToxLoss(30)
|
||||
|
||||
@@ -188,7 +188,7 @@
|
||||
C.enemies = enemies
|
||||
if(spider_growinstantly)
|
||||
C.amount_grown = 250
|
||||
C.spider_growinstantly = 1
|
||||
C.spider_growinstantly = TRUE
|
||||
spawn(10)
|
||||
stop_automated_movement = 0
|
||||
|
||||
@@ -196,7 +196,7 @@
|
||||
name = "terror egg cluster"
|
||||
desc = "A cluster of tiny spider eggs. They pulse with a strong inner life, and appear to have sharp thorns on the sides."
|
||||
icon_state = "eggs"
|
||||
var/spider_growinstantly = 0
|
||||
var/spider_growinstantly = FALSE
|
||||
var/spider_myqueen = null
|
||||
var/spider_mymother = null
|
||||
var/spiderling_type = null
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
spider_steps_taken++
|
||||
CreatePath(entry_vent)
|
||||
step_to(src,entry_vent)
|
||||
if(spider_debug > 0)
|
||||
if(spider_debug)
|
||||
visible_message("<span class='notice'>[src] moves towards the vent [entry_vent].</span>")
|
||||
else
|
||||
path_to_vent = 0
|
||||
|
||||
@@ -17,6 +17,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
// Name / Description
|
||||
name = "terror spider"
|
||||
desc = "The generic parent of all other terror spider types. If you see this in-game, it is a bug."
|
||||
gender = FEMALE
|
||||
|
||||
// Icons
|
||||
icon = 'icons/mob/terrorspider.dmi'
|
||||
@@ -141,29 +142,33 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
var/mylocation = null
|
||||
var/chasecycles = 0
|
||||
var/web_infects = 0
|
||||
var/spider_creation_time = 0
|
||||
|
||||
var/datum/action/innate/terrorspider/web/web_action
|
||||
var/web_type = /obj/structure/spider/terrorweb
|
||||
var/datum/action/innate/terrorspider/wrap/wrap_action
|
||||
|
||||
// Breathing - require some oxygen, and no toxins, but take little damage from this requirement not being met (they can hold their breath)
|
||||
// Breathing - require some oxygen, and no toxins
|
||||
atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
unsuitable_atmos_damage = 1
|
||||
|
||||
// Temperature - can freeze in space and cook in plasma, but it takes extreme temperatures to do this.
|
||||
minbodytemp = 100
|
||||
maxbodytemp = 500
|
||||
heat_damage_per_tick = 3
|
||||
// Temperature
|
||||
heat_damage_per_tick = 5 // Takes 250% normal damage from being in a hot environment ("kill it with fire!")
|
||||
|
||||
// DEBUG OPTIONS & COMMANDS
|
||||
var/spider_growinstantly = 0 // DEBUG OPTION, DO NOT ENABLE THIS ON LIVE. IT IS USED TO TEST NEST GROWTH/SETUP AI.
|
||||
var/spider_debug = 0
|
||||
var/spider_growinstantly = FALSE // DEBUG OPTION, DO NOT ENABLE THIS ON LIVE. IT IS USED TO TEST NEST GROWTH/SETUP AI.
|
||||
var/spider_debug = FALSE
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// --------------------- TERROR SPIDERS: SHARED ATTACK CODE -----------------------
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
|
||||
// Forces terrors to use the 'bite' graphic when attacking something. Same as code/modules/mob/living/carbon/alien/larva/larva_defense.dm#L34
|
||||
if(!no_effect && !visual_effect_icon)
|
||||
visual_effect_icon = ATTACK_EFFECT_BITE
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/AttackingTarget()
|
||||
if(isterrorspider(target))
|
||||
if(target in enemies)
|
||||
@@ -187,14 +192,13 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
if(F.welded)
|
||||
to_chat(src, "The fire door is welded shut.")
|
||||
else
|
||||
visible_message("<span class='danger'>\The [src] pries open the firedoor!</span>")
|
||||
visible_message("<span class='danger'>[src] pries open the firedoor!</span>")
|
||||
F.open()
|
||||
else
|
||||
to_chat(src, "Closing fire doors does not help.")
|
||||
else if(istype(target, /obj/machinery/door/airlock))
|
||||
var/obj/machinery/door/airlock/A = target
|
||||
if(A.density)
|
||||
try_open_airlock(A)
|
||||
try_open_airlock(A)
|
||||
else if(isliving(target) && (!client || a_intent == INTENT_HARM))
|
||||
var/mob/living/G = target
|
||||
if(issilicon(G))
|
||||
@@ -221,27 +225,23 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/examine(mob/user)
|
||||
. = ..()
|
||||
var/list/msgs = list()
|
||||
if(stat == DEAD)
|
||||
msgs += "<span class='notice'>It appears to be dead.</span>\n"
|
||||
else
|
||||
if(stat != DEAD)
|
||||
if(key)
|
||||
msgs += "<span class='warning'>Its eyes regard you with a curious intelligence.</span>"
|
||||
. += "<span class='warning'>[p_they(TRUE)] regards [p_their()] surroundings with a curious intelligence.</span>"
|
||||
if(health > (maxHealth*0.95))
|
||||
msgs += "<span class='notice'>It is in excellent health.</span>"
|
||||
. += "<span class='notice'>[p_they(TRUE)] is in excellent health.</span>"
|
||||
else if(health > (maxHealth*0.75))
|
||||
msgs += "<span class='notice'>It has a few injuries.</span>"
|
||||
. += "<span class='notice'>[p_they(TRUE)] has a few injuries.</span>"
|
||||
else if(health > (maxHealth*0.55))
|
||||
msgs += "<span class='warning'>It has many injuries.</span>"
|
||||
. += "<span class='warning'>[p_they(TRUE)] has many injuries.</span>"
|
||||
else if(health > (maxHealth*0.25))
|
||||
msgs += "<span class='warning'>It is barely clinging on to life!</span>"
|
||||
. += "<span class='warning'>[p_they(TRUE)] is barely clinging on to life!</span>"
|
||||
if(degenerate)
|
||||
msgs += "<span class='warning'>It appears to be dying.</span>"
|
||||
. += "<span class='warning'>[p_they(TRUE)] appears to be dying.</span>"
|
||||
else if(health < maxHealth && regen_points > regen_points_per_kill)
|
||||
msgs += "<span class='notice'>It appears to be regenerating quickly.</span>"
|
||||
. += "<span class='notice'>[p_they(TRUE)] appears to be regenerating quickly.</span>"
|
||||
if(killcount >= 1)
|
||||
msgs += "<span class='warning'>It has blood dribbling from its mouth.</span>"
|
||||
. += msgs.Join("<BR>")
|
||||
. += "<span class='warning'>[p_they(TRUE)] has blood dribbling from [p_their()] mouth.</span>"
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/New()
|
||||
..()
|
||||
@@ -254,9 +254,10 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
if(web_type)
|
||||
web_action = new()
|
||||
web_action.Grant(src)
|
||||
wrap_action = new()
|
||||
wrap_action.Grant(src)
|
||||
|
||||
if(regen_points_per_tick < regen_points_per_hp)
|
||||
// Only grant the Wrap action button to spiders who need to use it to regenerate their health
|
||||
wrap_action = new()
|
||||
wrap_action.Grant(src)
|
||||
name += " ([rand(1, 1000)])"
|
||||
real_name = name
|
||||
msg_terrorspiders("[src] has grown in [get_area(src)].")
|
||||
@@ -278,6 +279,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
addtimer(CALLBACK(src, .proc/announcetoghosts), 30)
|
||||
var/datum/atom_hud/U = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
|
||||
U.add_hud_to(src)
|
||||
spider_creation_time = world.time
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/announcetoghosts()
|
||||
if(spider_awaymission)
|
||||
@@ -285,8 +287,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
if(stat == DEAD)
|
||||
return
|
||||
if(ckey)
|
||||
var/image/alert_overlay = image('icons/mob/terrorspider.dmi', icon_state)
|
||||
notify_ghosts("[src] has appeared in [get_area(src)]. (already player-controlled)", source = src, alert_overlay = alert_overlay)
|
||||
notify_ghosts("[src] (player controlled) has appeared in [get_area(src)].")
|
||||
else if(ai_playercontrol_allowtype)
|
||||
var/image/alert_overlay = image('icons/mob/terrorspider.dmi', icon_state)
|
||||
notify_ghosts("[src] has appeared in [get_area(src)].", enter_link = "<a href=?src=[UID()];activate=1>(Click to control)</a>", source = src, alert_overlay = alert_overlay, action = NOTIFY_ATTACK)
|
||||
@@ -342,7 +343,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/ObjBump(obj/O)
|
||||
if(istype(O, /obj/machinery/door/airlock))
|
||||
var/obj/machinery/door/airlock/L = O
|
||||
if(L.density)
|
||||
if(L.density) // must check density here, to avoid rapid bumping of an airlock that is in the process of opening, instantly forcing it closed
|
||||
return try_open_airlock(L)
|
||||
if(istype(O, /obj/machinery/door/firedoor))
|
||||
var/obj/machinery/door/firedoor/F = O
|
||||
@@ -352,7 +353,8 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/msg_terrorspiders(msgtext)
|
||||
for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in GLOB.ts_spiderlist)
|
||||
for(var/thing in GLOB.ts_spiderlist)
|
||||
var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing
|
||||
if(T.stat != DEAD)
|
||||
to_chat(T, "<span class='terrorspider'>TerrorSense: [msgtext]</span>")
|
||||
|
||||
@@ -365,21 +367,54 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/proc/try_open_airlock(obj/machinery/door/airlock/D)
|
||||
if(D.operating)
|
||||
return
|
||||
if(!D.density)
|
||||
to_chat(src, "<span class='warning'>Closing doors does not help us.</span>")
|
||||
else if(D.welded)
|
||||
to_chat(src, "<span class='warning'>The door is welded shut.</span>")
|
||||
if(D.welded)
|
||||
to_chat(src, "<span class='warning'>The door is welded.</span>")
|
||||
else if(D.locked)
|
||||
to_chat(src, "<span class='warning'>The door is bolted shut.</span>")
|
||||
to_chat(src, "<span class='warning'>The door is bolted.</span>")
|
||||
else if(D.allowed(src))
|
||||
D.open(1)
|
||||
return 1
|
||||
if(D.density)
|
||||
D.open(TRUE)
|
||||
else
|
||||
D.close(TRUE)
|
||||
return TRUE
|
||||
else if(D.arePowerSystemsOn() && (spider_opens_doors != 2))
|
||||
to_chat(src, "<span class='warning'>The door's motors resist your efforts to force it.</span>")
|
||||
else if(!spider_opens_doors)
|
||||
to_chat(src, "<span class='warning'>Your type of spider is not strong enough to force open doors.</span>")
|
||||
else
|
||||
visible_message("<span class='danger'>[src] pries open the door!</span>")
|
||||
visible_message("<span class='danger'>[src] forces the door!</span>")
|
||||
playsound(src.loc, "sparks", 100, 1)
|
||||
D.open(1)
|
||||
return 1
|
||||
if(D.density)
|
||||
D.open(TRUE)
|
||||
else
|
||||
D.close(TRUE)
|
||||
return TRUE
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/Stat()
|
||||
..()
|
||||
// Determines what shows in the "Status" tab for player-controlled spiders. Used to help players understand spider health regeneration mechanics.
|
||||
// Uses <font color='#X'> because the status panel does NOT accept <span class='X'>.
|
||||
if(statpanel("Status") && ckey && stat == CONSCIOUS)
|
||||
if(degenerate)
|
||||
stat(null, "<font color='#eb4034'>Hivemind Connection Severed! Dying...</font>") // color=red
|
||||
return
|
||||
if(health != maxHealth)
|
||||
var/hp_points_per_second = 0
|
||||
var/ltext = "FAST"
|
||||
var/lcolor = "#fcba03" // orange
|
||||
var/secs_per_tick = (SSmobs.wait / 10) // This uses SSmobs.wait because it must use the same frequency as mobs are processed
|
||||
if(regen_points < (regen_points_per_hp * 2))
|
||||
// Slow regen speed: using regen_points as we get them. Figure out regen_points/sec, then convert that to hp/sec.
|
||||
var/regen_points_per_second = (regen_points_per_tick / secs_per_tick)
|
||||
hp_points_per_second = (regen_points_per_second / regen_points_per_hp)
|
||||
ltext = "SLOW (HUNGRY!)"
|
||||
lcolor = "#eb4034" // red
|
||||
else
|
||||
// Fast regen speed: healing at full 1 hp / tick rate. Just divide 1hp/tick by seconds/tick to get healing/sec.
|
||||
hp_points_per_second = 1 / secs_per_tick
|
||||
if(hp_points_per_second > 0)
|
||||
var/pc_of_max_per_second = round(((hp_points_per_second / maxHealth) * 100), 0.1)
|
||||
stat(null, "Regeneration: [ltext]: <font color='[lcolor]'>[num2text(pc_of_max_per_second)]% of health per second</font>")
|
||||
|
||||
|
||||
|
||||
@@ -675,4 +675,3 @@ GLOBAL_LIST_INIT(intents, list(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM
|
||||
return FALSE //This is the only case someone should actually be completely blocked from antag rolling as well
|
||||
return TRUE
|
||||
|
||||
#define isterrorspider(A) (istype((A), /mob/living/simple_animal/hostile/poison/terror_spider))
|
||||
|
||||
@@ -54,8 +54,6 @@
|
||||
var/eggs_hatched = 0 // num of hatch events completed
|
||||
var/awaymission_checked = FALSE
|
||||
var/awaymission_infection = FALSE // TRUE if infection occurred inside gateway
|
||||
var/list/types_basic = list(/mob/living/simple_animal/hostile/poison/terror_spider/red, /mob/living/simple_animal/hostile/poison/terror_spider/gray)
|
||||
var/list/types_adv = list(/mob/living/simple_animal/hostile/poison/terror_spider/red, /mob/living/simple_animal/hostile/poison/terror_spider/gray, /mob/living/simple_animal/hostile/poison/terror_spider/green)
|
||||
|
||||
|
||||
/obj/item/organ/internal/body_egg/terror_eggs/on_life()
|
||||
@@ -104,12 +102,16 @@
|
||||
var/infection_completed = FALSE
|
||||
var/obj/structure/spider/spiderling/terror_spiderling/S = new(get_turf(owner))
|
||||
switch(eggs_hatched)
|
||||
if(0) // First spiderling
|
||||
S.grow_as = pick(types_basic)
|
||||
if(1) // Second
|
||||
S.grow_as = pick(types_adv)
|
||||
if(2) // Last
|
||||
S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/princess
|
||||
if(0) // 1st spiderling
|
||||
S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/gray
|
||||
if(1) // 2nd
|
||||
S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/red
|
||||
if(2) // 3rd
|
||||
S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/brown
|
||||
if(3) // 4th
|
||||
S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/green
|
||||
if(4) // 5th
|
||||
S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/green
|
||||
infection_completed = TRUE
|
||||
S.immediate_ventcrawl = TRUE
|
||||
eggs_hatched++
|
||||
|
||||
Reference in New Issue
Block a user