diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index 719274857ec..7cd4cc7a918 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -208,6 +208,7 @@
#define isguardian(A) (istype((A), /mob/living/simple_animal/hostile/guardian))
#define isnymph(A) (istype((A), /mob/living/simple_animal/diona))
#define ishostile(A) (istype(A, /mob/living/simple_animal/hostile))
+#define isterrorspider(A) (istype((A), /mob/living/simple_animal/hostile/poison/terror_spider))
#define issilicon(A) (istype((A), /mob/living/silicon))
#define isAI(A) (istype((A), /mob/living/silicon/ai))
diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm
index 639687a45e9..a1538b5fe92 100644
--- a/code/game/objects/effects/spiders.dm
+++ b/code/game/objects/effects/spiders.dm
@@ -42,7 +42,7 @@
/obj/structure/spider/stickyweb/CanPass(atom/movable/mover, turf/target, height=0)
if(height == 0)
return TRUE
- if(istype(mover, /mob/living/simple_animal/hostile/poison/giant_spider))
+ if(istype(mover, /mob/living/simple_animal/hostile/poison/giant_spider) || isterrorspider(mover))
return TRUE
else if(istype(mover, /mob/living))
if(prob(50))
diff --git a/code/modules/events/spider_terror.dm b/code/modules/events/spider_terror.dm
index 79acc49fe73..ae10f427506 100644
--- a/code/modules/events/spider_terror.dm
+++ b/code/modules/events/spider_terror.dm
@@ -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
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm
index 2b15e584922..218e01af6a2 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm
@@ -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, "ERROR: attempt to use evolve queen ability on a non-princess")
- return
- var/feedings_left = user.feedings_to_evolve - user.fed
- if(feedings_left > 0)
- to_chat(user, "You must wrap [feedings_left] more humanoid prey before you can do this!")
- 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, "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()
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/chem.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/chem.dm
index 60e11de670a..b685fdd1959 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/chem.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/chem.dm
@@ -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
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress.dm
index 137d6739466..f011becf6b8 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress.dm
@@ -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, "Unrecognized egg type.")
-/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, iThrough the hivemind, the raw power of [src] floods into your body, burning it from the inside out!")
@@ -106,8 +107,6 @@
qdel(T)
to_chat(src, "All Terror Spiders, except yourself, will die off shortly.")
-
/obj/item/projectile/terrorqueenspit/empress
- damage_type = BURN
- damage = 30
- bonus_tox = 0
+ damage = 90
+
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/green.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/green.dm
index 1946f1a32ee..b07f34ec368 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/green.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/green.dm
@@ -39,11 +39,10 @@
to_chat(src, "You must wrap more humanoid prey before you can do this!")
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)
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/hive.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/hive.dm
index 245ae95c5e9..407e6f3174e 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/hive.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/hive.dm
@@ -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
+
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/prince.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/prince.dm
index e486872abbb..7b900d8a881 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/prince.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/prince.dm
@@ -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)
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/princess.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/princess.dm
index 6f33c51b246..7a840405cd0 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/princess.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/princess.dm
@@ -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, "You cannot generate eggs while hiding in [loc].")
+ return
+
+ if((brood_count + canlay) >= spider_max_children)
+ return
+ canlay++
+ if(canlay == 1)
+ to_chat(src, "You have an egg available to lay.")
+ else
+ to_chat(src, "You have [canlay] eggs available to lay.")
+
+
+/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
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm
index 737b6eba22a..af475b1a59a 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm
@@ -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, "You have an egg available to lay.")
- else if(canlay == 12)
- to_chat(src, "You have [canlay] eggs available to lay. You won't grow any more eggs until you lay some of your existing ones.")
- else
- to_chat(src, "You have [canlay] eggs available to lay.")
+ 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, "You have an egg available to lay.")
+ else if(canlay > 1)
+ to_chat(src, "You have [canlay] eggs available to lay.")
+
+
+/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("\The [src] writhes in pain!")
- to_chat(P,"\The [src] has died. Without her hivemind link, purple terrors like yourself cannot survive more than a few minutes!")
- 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, "\The psychic backlash from the death of [src] crashes into your mind! Somehow... you find a way to keep going!")
+ continue
+ T.visible_message("[T] writhes in pain!")
+ to_chat(T, "\The psychic backlash from the death of [src] overwhelms you! You feel the life start to drain out of you...")
+ 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, "You have matured to your egglaying stage. You can now smash through walls, and lay eggs, but can no longer ventcrawl.")
-/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, "Too soon to attempt that again. Wait just a few more seconds...")
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, "Too soon to lay another egg.")
+ return
if(!(eggtype in eggtypes))
to_chat(src, "Unrecognized egg type.")
return 0
- if(eggtype == TS_DESC_MOTHER || eggtype == TS_DESC_PRINCE)
- if(canlay < 12)
- to_chat(src, "Insufficient strength. It takes as much effort to lay one of those as it does to lay 12 normal eggs.")
- 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, "Insufficient strength. It takes as much effort to lay one of those as it does to lay 4 normal eggs.")
- 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, "Cancelled.")
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, "Too soon to do this again!")
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, "Unrecognized egg type.")
+ 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, "Unrecognized egg type.")
+
+
+/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("\The [src] emits a bone-chilling shriek!")
+ visible_message("[src] emits a bone-chilling shriek!")
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, "You must lay at least 10 eggs before doing this.")
+
+/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, "You have run out of uses of this ability.")
+ if(!isobserver(user) && !isterrorspider(user))
+ return
+ . += "[p_they(TRUE)] has laid [eggslaid] egg[eggslaid != 1 ? "s" : ""]."
+ . += "[p_they(TRUE)] has lived for [MinutesAlive()] minutes."
+
/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)
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/reproduction.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/reproduction.dm
index a889bc6d328..8961fcdddb5 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/reproduction.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/reproduction.dm
@@ -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
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_ai.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_ai.dm
index 11e4cac3e4a..c3e0c9a0511 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_ai.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_ai.dm
@@ -126,7 +126,7 @@
spider_steps_taken++
CreatePath(entry_vent)
step_to(src,entry_vent)
- if(spider_debug > 0)
+ if(spider_debug)
visible_message("[src] moves towards the vent [entry_vent].")
else
path_to_vent = 0
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm
index ab36c6ca313..6c943b26f53 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm
@@ -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("\The [src] pries open the firedoor!")
+ visible_message("[src] pries open the firedoor!")
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 += "It appears to be dead.\n"
- else
+ if(stat != DEAD)
if(key)
- msgs += "Its eyes regard you with a curious intelligence."
+ . += "[p_they(TRUE)] regards [p_their()] surroundings with a curious intelligence."
if(health > (maxHealth*0.95))
- msgs += "It is in excellent health."
+ . += "[p_they(TRUE)] is in excellent health."
else if(health > (maxHealth*0.75))
- msgs += "It has a few injuries."
+ . += "[p_they(TRUE)] has a few injuries."
else if(health > (maxHealth*0.55))
- msgs += "It has many injuries."
+ . += "[p_they(TRUE)] has many injuries."
else if(health > (maxHealth*0.25))
- msgs += "It is barely clinging on to life!"
+ . += "[p_they(TRUE)] is barely clinging on to life!"
if(degenerate)
- msgs += "It appears to be dying."
+ . += "[p_they(TRUE)] appears to be dying."
else if(health < maxHealth && regen_points > regen_points_per_kill)
- msgs += "It appears to be regenerating quickly."
+ . += "[p_they(TRUE)] appears to be regenerating quickly."
if(killcount >= 1)
- msgs += "It has blood dribbling from its mouth."
- . += msgs.Join("
")
+ . += "[p_they(TRUE)] has blood dribbling from [p_their()] mouth."
/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 = "(Click to control)", 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, "TerrorSense: [msgtext]")
@@ -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, "Closing doors does not help us.")
- else if(D.welded)
- to_chat(src, "The door is welded shut.")
+ if(D.welded)
+ to_chat(src, "The door is welded.")
else if(D.locked)
- to_chat(src, "The door is bolted shut.")
+ to_chat(src, "The door is bolted.")
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, "The door's motors resist your efforts to force it.")
else if(!spider_opens_doors)
to_chat(src, "Your type of spider is not strong enough to force open doors.")
else
- visible_message("[src] pries open the door!")
+ visible_message("[src] forces the door!")
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 because the status panel does NOT accept .
+ if(statpanel("Status") && ckey && stat == CONSCIOUS)
+ if(degenerate)
+ stat(null, "Hivemind Connection Severed! Dying...") // 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]: [num2text(pc_of_max_per_second)]% of health per second")
+
+
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index ae8cbd2d7ca..6acfb92a515 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -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))
diff --git a/code/modules/surgery/organs/parasites.dm b/code/modules/surgery/organs/parasites.dm
index b61a7c429bc..b9afa20b7d2 100644
--- a/code/modules/surgery/organs/parasites.dm
+++ b/code/modules/surgery/organs/parasites.dm
@@ -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++