TS Mother Rework (#14856)

* basic functionality

* map edit: delete mother from awaymission

* IncubateEggs, PickupSpiderlings, anti-exploit stuff

* editor, please stop messing with my indentation

* fixes

fixes: stops "cancelled" messages when a terror is in an airless pipe, stops incubate being used on eggs on an adjacent tile,  makes the "cannot incubate due to lack of regen points" message clearer, stops spiders using remoteview while in a pipe which messes up their vision

* fixes being able to wrap spiderlings/etc into coccoons if they're on top of a dead body

* mother webs block spiderlings from passing them

* AA suggestion

Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com>

Co-authored-by: Kyep <Kyep@users.noreply.github.com>
Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com>
This commit is contained in:
Kyep
2020-12-02 19:25:19 +00:00
committed by GitHub
parent a3f6ced32a
commit 8def3bf2af
10 changed files with 306 additions and 268 deletions
@@ -15,9 +15,9 @@
#define TS_DESC_BLACK "Black - Poison"
#define TS_DESC_PURPLE "Purple - Guard"
#define TS_DESC_BROWN "Brown - Breacher"
#define TS_DESC_PRINCE "Prince - WAR"
#define TS_DESC_PRINCE "Prince - HERO"
#define TS_DESC_PRINCESS "Princess - HORDE"
#define TS_DESC_MOTHER "Mother - HORROR"
#define TS_DESC_MOTHER "Mother - SUPPORT"
#define TS_DESC_QUEEN "Queen - LEADER"
#define TS_TIER_1 1
@@ -42,6 +42,44 @@
var/mob/living/simple_animal/hostile/poison/terror_spider/user = owner
user.DoVentSmash()
/datum/action/innate/terrorspider/remoteview
name = "Remote View"
icon_icon = 'icons/obj/eyes.dmi'
button_icon_state = "heye"
/datum/action/innate/terrorspider/remoteview/Activate()
var/mob/living/simple_animal/hostile/poison/terror_spider/user = owner
user.DoRemoteView()
// ---------- MOTHER ACTIONS
/datum/action/innate/terrorspider/mother/royaljelly
name = "Lay Royal Jelly"
icon_icon = 'icons/mob/actions/actions.dmi'
button_icon_state = "spiderjelly"
/datum/action/innate/terrorspider/mother/royaljelly/Activate()
var/mob/living/simple_animal/hostile/poison/terror_spider/mother/user = owner
user.DoCreateJelly()
/datum/action/innate/terrorspider/mother/gatherspiderlings
name = "Gather Spiderlings"
icon_icon = 'icons/effects/effects.dmi'
button_icon_state = "spiderling"
/datum/action/innate/terrorspider/mother/gatherspiderlings/Activate()
var/mob/living/simple_animal/hostile/poison/terror_spider/mother/user = owner
user.PickupSpiderlings()
/datum/action/innate/terrorspider/mother/incubateeggs
name = "Incubate Eggs"
icon_icon = 'icons/effects/effects.dmi'
button_icon_state = "eggs"
/datum/action/innate/terrorspider/mother/incubateeggs/Activate()
var/mob/living/simple_animal/hostile/poison/terror_spider/mother/user = owner
user.IncubateEggs()
// ---------- QUEEN ACTIONS
@@ -189,7 +227,7 @@
choices += L
for(var/obj/O in oview(1,src))
if(Adjacent(O) && !O.anchored)
if(!istype(O, /obj/structure/spider/terrorweb) && !istype(O, /obj/structure/spider/cocoon) && !istype(O, /obj/structure/spider/spiderling/terror_spiderling))
if(!istype(O, /obj/structure/spider))
choices += O
if(choices.len)
cocoon_target = input(src,"What do you wish to cocoon?") in null|choices
@@ -216,7 +254,10 @@
if(!O.anchored)
if(istype(O, /obj/item))
O.loc = C
else if(istype(O, /obj/machinery) || istype(O, /obj/structure))
else if(istype(O, /obj/machinery))
O.loc = C
large_cocoon = 1
else if(istype(O, /obj/structure) && !istype(O, /obj/structure/spider)) // can't wrap spiderlings/etc
O.loc = C
large_cocoon = 1
for(var/mob/living/L in C.loc)
@@ -271,3 +312,4 @@
C.visible_message("<span class='danger'>[src] smashes the welded cover off [C]!</span>")
return
to_chat(src, "<span class='danger'>There is no welded vent or scrubber close enough to do this.</span>")
@@ -2,56 +2,135 @@
// --------------------------------------------------------------------------------
// ----------------- TERROR SPIDERS: T3 MOTHER OF TERROR --------------------------
// --------------------------------------------------------------------------------
// -------------: ROLE: living schmuck bait
// -------------: AI: no special ai
// -------------: SPECIAL: spawns an ungodly number of spiderlings when killed
// -------------: TO FIGHT IT: don't! Just leave it alone! It is harmless by itself... but god help you if you aggro it.
// -------------: ROLE: support (team medic)
// -------------: AI: none (only effective under player control, alongside other player-controlled spiders)
// -------------: SPECIAL: picks up / carries spiderlings to prevent them being killed. Creates royal jellies to heal spiders.
// -------------: TO FIGHT IT: shoot it, it will die quickly
// -------------: SPRITES FROM: FoS, https://www.paradisestation.org/forum/profile/335-fos
/mob/living/simple_animal/hostile/poison/terror_spider/mother
name = "Mother of Terror spider"
desc = "An enormous spider. Hundreds of tiny spiderlings are crawling all over it. Their beady little eyes all stare at you. The horror!"
spider_role_summary = "Schmuck bait. Extremely weak in combat, but spawns many spiderlings when it dies."
desc = "An enormous spider. Tiny spiderlings are crawling all over it. Their beady little eyes all stare at you. The horror!"
spider_role_summary = "Carries spiderlings to protect them. Creates royal jelly that heals other spiders."
ai_target_method = TS_DAMAGE_SIMPLE
icon_state = "terror_mother"
icon_living = "terror_mother"
icon_dead = "terror_mother_dead"
maxHealth = 50
health = 50
maxHealth = 120 // same combat stats as an unboosted T1 gray. Very weak in combat.
health = 120
melee_damage_lower = 10
melee_damage_upper = 20
regen_points_per_tick = 2
regen_points_max = 400 // enough to lay 4 jellies, if fully charged
regen_points_per_kill = 200 // >2x normal, since they're food reprocessors
idle_ventcrawl_chance = 5
spider_tier = TS_TIER_3
spider_opens_doors = 2
web_type = null
var/canspawn = TRUE
var/spawn_count = 30
var/spawn_pc_stillborn = 50
web_type = /obj/structure/spider/terrorweb/mother
var/datum/action/innate/terrorspider/ventsmash/ventsmash_action
var/datum/action/innate/terrorspider/remoteview/remoteview_action
var/datum/action/innate/terrorspider/mother/royaljelly/royaljelly_action
var/datum/action/innate/terrorspider/mother/gatherspiderlings/gatherspiderlings_action
var/datum/action/innate/terrorspider/mother/incubateeggs/incubateeggs_action
var/jelly_cost = 100
/mob/living/simple_animal/hostile/poison/terror_spider/mother/New()
..()
ventsmash_action = new()
ventsmash_action.Grant(src)
remoteview_action = new()
remoteview_action.Grant(src)
royaljelly_action = new()
royaljelly_action.Grant(src)
gatherspiderlings_action = new()
gatherspiderlings_action.Grant(src)
incubateeggs_action = new()
incubateeggs_action.Grant(src)
/mob/living/simple_animal/hostile/poison/terror_spider/mother/death(gibbed)
if(can_die())
if(spider_awaymission && !is_away_level(z))
canspawn = FALSE
if(degenerate)
canspawn = FALSE
if(canspawn)
canspawn = FALSE
for(var/i in 0 to spawn_count)
var/obj/structure/spider/spiderling/terror_spiderling/S = new /obj/structure/spider/spiderling/terror_spiderling(get_turf(src))
if(prob(spawn_pc_stillborn))
S.stillborn = 1
S.grow_as = pick(/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)
S.amount_grown = 50 // double speed growth
visible_message("<span class='userdanger'>[src] breaks apart, the many spiders on its back scurrying everywhere!</span>")
degenerate = TRUE
return ..()
DropSpiderlings()
. = ..()
/mob/living/simple_animal/hostile/poison/terror_spider/mother/Destroy()
canspawn = FALSE
/mob/living/simple_animal/hostile/poison/terror_spider/mother/Stat()
..()
// Provides a status panel indicator, showing mothers how many regen points they have.
if(statpanel("Status") && ckey && stat == CONSCIOUS)
stat(null, "Regeneration Points: [regen_points]")
/mob/living/simple_animal/hostile/poison/terror_spider/mother/examine(mob/user)
. = ..()
if(!key || stat == DEAD)
return
if(!isobserver(user) && !isterrorspider(user))
return
. += "<span class='notice'>[p_they(TRUE)] is carrying [length(contents)] spiderlings.</span>"
/mob/living/simple_animal/hostile/poison/terror_spider/mother/proc/DoCreateJelly()
// Mothers create jellies, which other terrors eat to get regeneration points, just like they get from wrapping corpses.
// Jellies are essentially health packs that provide healing over time.
if(regen_points < jelly_cost)
to_chat(src, "<span class='danger'>You only have [regen_points] of the [jelly_cost] regeneration points you need to do this.</span>")
return
var/turf/mylocation = get_turf(src)
if(isspaceturf(mylocation))
to_chat(src, "<span class='danger'>Cannot secrete jelly in space.</span>")
return
visible_message("<span class='notice'>[src] begins to secrete royal jelly.</span>")
if(do_after(src, 100, target = loc))
if(loc != mylocation)
return
new /obj/structure/spider/royaljelly(loc)
regen_points -= jelly_cost
/mob/living/simple_animal/hostile/poison/terror_spider/mother/consume_jelly(obj/structure/spider/royaljelly/J)
// Jellies give more regeneration points to the spider who eats them than they cost the mother to create.
// This makes them cost-efficient. But it also means we can't let mothers eat jellies, or they could keep cycling them for infinite points.
to_chat(src, "<span class='warning'>Mothers cannot consume royal jelly.</span>")
return
/mob/living/simple_animal/hostile/poison/terror_spider/mother/proc/PickupSpiderlings()
// Mothers can pick up spiderlings, carrying them on their back and stopping them from wandering into trouble.
var/pickup_count = 0
for(var/obj/structure/spider/spiderling/terror_spiderling/S in orange(2, src))
var/turf/T = get_turf(S)
new /obj/effect/temp_visual/heal(T)
S.movement_disabled = TRUE
S.forceMove(src)
pickup_count++
if(pickup_count)
to_chat(src, "<span class='notice'>You pick up [pickup_count] spiderling(s), storing them safely on your back.")
else
to_chat(src, "<span class='warning'>There are no spiderlings close enough for you to pick up.")
/mob/living/simple_animal/hostile/poison/terror_spider/mother/proc/DropSpiderlings()
// Called when a mother dies.
var/turf/T = get_turf(src)
for(var/obj/structure/spider/spiderling/terror_spiderling/S in src)
S.movement_disabled = FALSE
S.forceMove(T)
S.immediate_ventcrawl = TRUE
/mob/living/simple_animal/hostile/poison/terror_spider/mother/proc/IncubateEggs()
// Mothers can spend regen points to make existing eggs mature faster.
// This lets mothers save the spiderlings from eggs that would otherwise be lost when a nest is about to get wiped out.
if(regen_points < 50)
to_chat(src, "<span class='danger'>You only have [regen_points] of the 50 regeneration points required to do this.</span>")
return
for(var/obj/structure/spider/eggcluster/terror_eggcluster/C in orange(0, src))
var/turf/T = get_turf(C)
new /obj/effect/temp_visual/heal(T)
C.amount_grown += 25
regen_points -= 25
to_chat(src, "<span class='notice'>You warm [C], encouraging faster growth.")
return
to_chat(src, "<span class='warning'>The 'incubate eggs' ability can only be used on top of existing eggs.")
/obj/structure/spider/terrorweb/mother
name = "mother web"
desc = "This web is coated in pheromones which prevent spiderlings from passing it."
/obj/structure/spider/terrorweb/mother/CanPass(atom/movable/mover, turf/target)
if(istype(mover, /obj/structure/spider/spiderling/terror_spiderling))
return FALSE
return ..()
@@ -50,12 +50,15 @@
var/datum/action/innate/terrorspider/queen/queensense/queensense_action
var/datum/action/innate/terrorspider/queen/queeneggs/queeneggs_action
var/datum/action/innate/terrorspider/ventsmash/ventsmash_action
var/datum/action/innate/terrorspider/remoteview/remoteview_action
/mob/living/simple_animal/hostile/poison/terror_spider/queen/New()
..()
ventsmash_action = new()
ventsmash_action.Grant(src)
remoteview_action = new()
remoteview_action.Grant(src)
grant_queen_subtype_abilities()
spider_myqueen = src
if(spider_awaymission)
@@ -316,7 +319,7 @@
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.
return list(TS_DESC_PRINCE, TS_DESC_PRINCESS, TS_DESC_MOTHER)
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))
@@ -20,6 +20,7 @@
var/spider_awaymission = FALSE
var/frustration = 0
var/debug_ai_choices = FALSE
var/movement_disabled = FALSE
/obj/structure/spider/spiderling/terror_spiderling/New()
..()
@@ -81,6 +82,25 @@
new /obj/effect/temp_visual/cult/sparks(T) // red sparks, this is an unsafe area, I won't go here unless fleeing something worse
/obj/structure/spider/spiderling/terror_spiderling/process()
var/turf/T = get_turf(src)
amount_grown += rand(0,2)
if(amount_grown >= 100)
if(spider_awaymission && !is_away_level(T.z))
stillborn = TRUE
if(stillborn)
if(amount_grown >= 300)
// Fake spiderlings stick around for awhile, just to be spooky.
qdel(src)
else
if(!grow_as)
grow_as = pick(/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)
var/mob/living/simple_animal/hostile/poison/terror_spider/S = new grow_as(T)
S.spider_myqueen = spider_myqueen
S.spider_mymother = spider_mymother
S.enemies = enemies
qdel(src)
if(movement_disabled)
return
if(travelling_in_vent)
if(isturf(loc))
travelling_in_vent = 0
@@ -90,6 +110,8 @@
frustration = 0
var/list/vents = list()
for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in entry_vent.parent.other_atmosmch)
if(temp_vent.welded) // no point considering a vent we can't even use
continue
vents.Add(temp_vent)
if(!vents.len)
entry_vent = null
@@ -155,23 +177,7 @@
entry_vent = v
walk_to(src, entry_vent, 1)
break
if(isturf(loc))
amount_grown += rand(0,2)
if(amount_grown >= 100)
if(spider_awaymission && !is_away_level(z))
stillborn = TRUE
if(stillborn)
if(amount_grown >= 300)
// Fake spiderlings stick around for awhile, just to be spooky.
qdel(src)
else
if(!grow_as)
grow_as = pick(/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)
var/mob/living/simple_animal/hostile/poison/terror_spider/S = new grow_as(loc)
S.spider_myqueen = spider_myqueen
S.spider_mymother = spider_mymother
S.enemies = enemies
qdel(src)
// --------------------------------------------------------------------------------
@@ -244,3 +250,8 @@
if(spider_growinstantly)
S.amount_grown = 250
qdel(src)
/obj/structure/spider/royaljelly
name = "royal jelly"
desc = "A pulsating mass of slime, jelly, blood, and or liquified human organs considered delicious and highly nutritious by terror spiders."
icon_state = "spiderjelly"
@@ -83,6 +83,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
var/regen_points_per_tick = 1 // gain one regen point per tick
var/regen_points_per_kill = 90 // gain extra regen points if you kill something
var/regen_points_per_hp = 3 // every X regen points = 1 health point you can regen
var/regen_points_per_jelly = 120 // gain a ton of regen points if you eat a jelly
// desired: 20hp/minute unmolested, 40hp/min on food boost, assuming one tick every 2 seconds
// 90/kill means bonus 30hp/kill regenerated over the next 1-2 minutes
@@ -184,6 +185,8 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
visible_message("<span class='notice'>[src] harmlessly nuzzles [target].</span>")
T.CheckFaction()
CheckFaction()
else if(istype(target, /obj/structure/spider/royaljelly))
consume_jelly(target)
else if(istype(target, /obj/structure/spider)) // Prevents destroying coccoons (exploit), eggs (horrible misclick), etc
to_chat(src, "Destroying things created by fellow spiders would not help us.")
else if(istype(target, /obj/machinery/door/firedoor))
@@ -219,6 +222,18 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
/mob/living/simple_animal/hostile/poison/terror_spider/proc/spider_specialattack(mob/living/carbon/human/L, poisonable)
L.attack_animal(src)
/mob/living/simple_animal/hostile/poison/terror_spider/proc/consume_jelly(obj/structure/spider/royaljelly/J)
if(regen_points_per_tick >= regen_points_per_hp)
to_chat(src, "<span class='warning'>Your spider type would not get any benefit from consuming royal jelly.</span>")
return
if(regen_points > 200)
to_chat(src, "<span class='warning'>You aren't hungry for jelly right now.</span>")
return
to_chat(src, "<span class='notice'>You consume the royal jelly! Regeneration speed increased!</span>")
regen_points += regen_points_per_jelly
fed++
qdel(J)
// --------------------------------------------------------------------------------
// --------------------- TERROR SPIDERS: PROC OVERRIDES ---------------------------
// --------------------------------------------------------------------------------
@@ -424,4 +439,32 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
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>")
/mob/living/simple_animal/hostile/poison/terror_spider/proc/DoRemoteView()
if(!isturf(loc))
// This check prevents spiders using this ability while inside an atmos pipe, which will mess up their vision
to_chat(src, "<span class='warning'>You must be standing on a floor to do this.</span>")
return
if(client && (client.eye != client.mob))
reset_perspective()
return
if(health != maxHealth)
to_chat(src, "<span class='warning'>You must be at full health to do this!</span>")
return
var/list/targets = list()
targets += src // ensures that self is always at top of the list
for(var/thing in GLOB.ts_spiderlist)
var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing
if(T.stat == DEAD)
continue
if(T.spider_awaymission != spider_awaymission)
continue
targets |= T // we use |= instead of += to avoid adding src to the list twice
var/mob/living/L = input("Choose a terror to watch.", "Selection") in targets
if(istype(L))
reset_perspective(L)
/mob/living/simple_animal/hostile/poison/terror_spider/adjustHealth(amount, updating_health = TRUE)
if(client && (client.eye != client.mob) && ismob(client.eye)) // the ismob check is required because client.eye can = atmos machines if a spider is in the vent
to_chat(src, "<span class='warning'>Cancelled remote view due to being under attack!</span>")
reset_perspective()
. = ..()