diff --git a/code/ATMOSPHERICS/components/unary_devices/vent_pump.dm b/code/ATMOSPHERICS/components/unary_devices/vent_pump.dm index 299d0c20e22..a2ba4429ffa 100644 --- a/code/ATMOSPHERICS/components/unary_devices/vent_pump.dm +++ b/code/ATMOSPHERICS/components/unary_devices/vent_pump.dm @@ -61,6 +61,7 @@ /obj/machinery/atmospherics/unary/vent_pump/New() ..() + all_vent_pumps += src icon = null initial_loc = get_area(loc) area_uid = initial_loc.uid @@ -426,6 +427,7 @@ return ..() /obj/machinery/atmospherics/unary/vent_pump/Destroy() + all_vent_pumps -= src if(initial_loc) initial_loc.air_vent_info -= id_tag initial_loc.air_vent_names -= id_tag diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm index 600dac2f273..091ecd40dbb 100644 --- a/code/_globalvars/lists/objects.dm +++ b/code/_globalvars/lists/objects.dm @@ -23,6 +23,7 @@ var/global/list/rcd_list = list() //list of Rapid Construction Devices. var/global/list/apcs = list() var/global/list/air_alarms = list() var/global/list/power_monitors = list() +var/global/list/all_vent_pumps = list() var/global/list/navbeacons = list() //list of all bot nagivation beacons, used for patrolling. var/global/list/deliverybeacons = list() //list of all MULEbot delivery beacons. diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index 2e76bcea6a2..631b621528f 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -523,6 +523,13 @@ if(ticker.mode.greyshirts.len) dat += check_role_table("Greyshirts", ticker.mode.greyshirts) + if(ts_spiderlist.len) + var/list/spider_minds = list() + for(var/mob/living/simple_animal/hostile/poison/terror_spider/S in ts_spiderlist) + if(S.ckey) + spider_minds += S.mind + dat += check_role_table("Terror Spiders", spider_minds) + dat += "" usr << browse(dat, "window=roundstatus;size=400x500") else diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm index deaa1b85aa8..1a2a4e897cb 100644 --- a/code/modules/events/event_container.dm +++ b/code/modules/events/event_container.dm @@ -185,6 +185,7 @@ var/list/event_last_fired = list() new /datum/event_meta(EVENT_LEVEL_MAJOR, "Abductor Visit", /datum/event/abductor, 80, is_one_shot = 1), new /datum/event_meta/alien(EVENT_LEVEL_MAJOR, "Alien Infestation", /datum/event/alien_infestation, 0, list(ASSIGNMENT_SECURITY = 30), 1), new /datum/event_meta(EVENT_LEVEL_MAJOR, "Traders", /datum/event/traders, 0, is_one_shot = 1), + new /datum/event_meta(EVENT_LEVEL_MAJOR, "Terror Spiders", /datum/event/spider_terror, 0, is_one_shot = 1) ) diff --git a/code/modules/events/spider_terror.dm b/code/modules/events/spider_terror.dm new file mode 100644 index 00000000000..ba636867b35 --- /dev/null +++ b/code/modules/events/spider_terror.dm @@ -0,0 +1,44 @@ + +/datum/event/spider_terror + announceWhen = 400 + var/spawncount = 1 + +/datum/event/spider_terror/setup() + announceWhen = rand(announceWhen, announceWhen + 50) + spawncount = 1 + +/datum/event/spider_infestation/announce() + command_announcement.Announce("Confirmed outbreak of level 3 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/effects/siren.ogg') + +/datum/event/spider_terror/start() + + var/list/vents = list() + for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in all_vent_pumps) + if(is_station_level(temp_vent.loc.z) && !temp_vent.welded) + if(temp_vent.parent.other_atmosmch.len > 50) + vents += temp_vent + + var/spider_type + var/infestation_type = pick(1, 2, 3, 4) + switch(infestation_type) + if(1) + spider_type = /mob/living/simple_animal/hostile/poison/terror_spider/green + spawncount = pick(2,3) + if(2) + spider_type = /mob/living/simple_animal/hostile/poison/terror_spider/white + spawncount = 1 + if(3) + spider_type = /mob/living/simple_animal/hostile/poison/terror_spider/prince + spawncount = 1 + if(4) + spider_type = /mob/living/simple_animal/hostile/poison/terror_spider/queen + spawncount = 1 + + while((spawncount >= 1) && vents.len) + var/obj/vent = pick(vents) + var/obj/effect/spider/spiderling/terror_spiderling/S = new(vent.loc) + S.name = "evil-looking spiderling" + S.grow_as = spider_type + S.amount_grown = 75 + vents -= vent + spawncount-- \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/__defines.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/__defines.dm index fafd30a4ae4..bea086c3ee6 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/__defines.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/__defines.dm @@ -4,8 +4,20 @@ #define MOVING_TO_TARGET 3 #define SPINNING_COCOON 4 +#define TS_DESC_RED "Red - Assault" +#define TS_DESC_GRAY "Gray - Ambush" +#define TS_DESC_GREEN "Green - Nurse" +#define TS_DESC_WHITE "White - Infect" +#define TS_DESC_BLACK "Black - Poison" +#define TS_DESC_PURPLE "Purple - Guard" +#define TS_DESC_PRINCE "Prince - WAR" +#define TS_DESC_MOTHER "Mother - HORROR" +#define TS_DESC_QUEEN "Queen - LEADER" + #define TS_TIER_1 1 #define TS_TIER_2 2 #define TS_TIER_3 3 #define TS_TIER_4 4 -#define TS_TIER_5 5 \ No newline at end of file +#define TS_TIER_5 5 + +#define isterrorspider(A) (istype((A), /mob/living/simple_animal/hostile/poison/terror_spider)) \ No newline at end of file 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 2111f350b0b..91ff4cbb53e 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 @@ -1,4 +1,4 @@ - +// ---------- ACTIONS FOR ALL SPIDERS /datum/action/innate/terrorspider/web name = "Web" @@ -19,17 +19,84 @@ user.FindWrapTarget() user.DoWrap() +// ---------- GREEN ACTIONS + +/datum/action/innate/terrorspider/greeneggs + name = "Lay Green Eggs" + icon_icon = 'icons/effects/effects.dmi' + button_icon_state = "eggs" + +/datum/action/innate/terrorspider/greeneggs/Activate() + var/mob/living/simple_animal/hostile/poison/terror_spider/green/user = owner + user.DoLayGreenEggs() + +// ---------- PRINCE ACTIONS + +/datum/action/innate/terrorspider/princesmash + name = "Smash Welded Vent" + icon_icon = 'icons/atmos/vent_pump.dmi' + button_icon_state = "map_vent" + +/datum/action/innate/terrorspider/princesmash/Activate() + var/mob/living/simple_animal/hostile/poison/terror_spider/prince/user = owner + user.DoPrinceSmash() + + +// ---------- QUEEN ACTIONS + +/datum/action/innate/terrorspider/queen/queennest + name = "Nest" + icon_icon = 'icons/mob/terrorspider.dmi' + button_icon_state = "terror_queen" + +/datum/action/innate/terrorspider/queen/queennest/Activate() + var/mob/living/simple_animal/hostile/poison/terror_spider/queen/user = owner + user.NestMode() + +/datum/action/innate/terrorspider/queen/queensense + name = "Hive Sense" + icon_icon = 'icons/mob/actions.dmi' + button_icon_state = "mindswap" + +/datum/action/innate/terrorspider/queen/queensense/Activate() + var/mob/living/simple_animal/hostile/poison/terror_spider/queen/user = owner + user.DoHiveSense() + +/datum/action/innate/terrorspider/queen/queeneggs + name = "Lay Queen Eggs" + icon_icon = 'icons/effects/effects.dmi' + button_icon_state = "eggs" + +/datum/action/innate/terrorspider/queen/queeneggs/Activate() + 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() // ---------- WEB /mob/living/simple_animal/hostile/poison/terror_spider/proc/Web() + var/turf/mylocation = loc visible_message("[src] begins to secrete a sticky substance.") if(do_after(src, 40, target = loc)) - var/obj/effect/spider/terrorweb/T = locate() in get_turf(src) - if(T) - to_chat(src, "There is already a web here.") + if(loc != mylocation) + return + else if(istype(loc, /turf/space)) + to_chat(src, "Webs cannot be spun in space.") else - new /obj/effect/spider/terrorweb(loc) + var/obj/effect/spider/terrorweb/T = locate() in get_turf(src) + if(T) + to_chat(src, "There is already a web here.") + else + var/obj/effect/spider/terrorweb/W = new /obj/effect/spider/terrorweb(loc) + W.creator_ckey = ckey /obj/effect/spider/terrorweb name = "terror web" @@ -39,6 +106,7 @@ density = 0 // prevents it blocking all movement health = 20 // two welders, or one laser shot (15 for the normal spider webs) icon_state = "stickyweb1" + var/creator_ckey = null /obj/effect/spider/terrorweb/New() @@ -50,12 +118,17 @@ /obj/effect/spider/terrorweb/CanPass(atom/movable/mover, turf/target) if(istype(mover, /mob/living/simple_animal/hostile/poison/terror_spider)) return 1 + if(istype(mover, /obj/item/projectile/terrorqueenspit)) + return 1 if(isliving(mover)) if(prob(80)) to_chat(mover, "You get stuck in [src] for a moment.") var/mob/living/M = mover M.Stun(4) // 8 seconds. M.Weaken(4) // 8 seconds. + if(iscarbon(mover)) + spawn(70) + qdel(src) return 1 else return 0 @@ -64,7 +137,12 @@ return ..() - +/obj/effect/spider/terrorweb/bullet_act(var/obj/item/projectile/Proj) + if(Proj.damage_type != BRUTE && Proj.damage_type != BURN) + visible_message("[src] is undamaged by [Proj]!") + // Webs don't care about disablers, tasers, etc. Or toxin damage. They're organic, but not alive. + else + ..() // ---------- WRAP @@ -73,12 +151,12 @@ if(!cocoon_target) var/list/choices = list() for(var/mob/living/L in oview(1,src)) - if(Adjacent(L)) + if(Adjacent(L) && !L.anchored) if(L.stat == DEAD) choices += L for(var/obj/O in oview(1,src)) if(Adjacent(O) && !O.anchored) - if(!istype(O, /obj/effect/spider/terrorweb) && !istype(O, /obj/effect/spider/cocoon)) + if(!istype(O, /obj/effect/spider/terrorweb) && !istype(O, /obj/effect/spider/cocoon) && !istype(O, /obj/effect/spider/spiderling/terror_spiderling)) choices += O if(choices.len) cocoon_target = input(src,"What do you wish to cocoon?") in null|choices @@ -87,6 +165,9 @@ /mob/living/simple_animal/hostile/poison/terror_spider/proc/DoWrap() if(cocoon_target && busy != SPINNING_COCOON) + if(cocoon_target.anchored) + cocoon_target = null + return busy = SPINNING_COCOON visible_message("[src] begins to secrete a sticky substance around [cocoon_target].") stop_automated_movement = 1 @@ -125,3 +206,18 @@ busy = 0 stop_automated_movement = 0 + +/mob/living/simple_animal/hostile/poison/terror_spider/prince/proc/DoPrinceSmash() + for(var/obj/machinery/atmospherics/unary/vent_pump/P in view(1,src)) + if(P.welded) + P.welded = 0 + P.update_icon() + visible_message("[src] smashes the welded cover off [P]!") + return + for(var/obj/machinery/atmospherics/unary/vent_scrubber/C in view(1,src)) + if(C.welded) + C.welded = 0 + C.update_icon() + visible_message("[src] smashes the welded cover off [C]!") + return + to_chat(src, "There is no unwelded vent close enough to do this.") \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/black.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/black.dm index 68d25a29492..93add83a261 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/black.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/black.dm @@ -10,7 +10,7 @@ /mob/living/simple_animal/hostile/poison/terror_spider/black name = "Black Terror spider" - desc = "An ominous-looking spider, black as the darkest night, and with merciless eyes and a blood-red hourglass pattern on its back." + desc = "An ominous-looking spider, black as the darkest night. It has merciless eyes, and a blood-red hourglass pattern on its back." spider_role_summary = "Hit-and-run attacker with extremely venomous bite." icon_state = "terror_widow" @@ -27,11 +27,11 @@ /mob/living/simple_animal/hostile/poison/terror_spider/black/spider_specialattack(mob/living/carbon/human/L, poisonable) if(!poisonable) return ..() - if(L.reagents.has_reagent("terror_black_toxin", 50)) + if(L.reagents.has_reagent("terror_black_toxin", 100)) return ..() var/inject_target = pick("chest", "head") if(L.stunned || L.can_inject(null, 0, inject_target, 0)) - L.reagents.add_reagent("terror_black_toxin", 15) // inject our special poison + L.reagents.add_reagent("terror_black_toxin", 30) // inject our special poison visible_message("[src] buries its long fangs deep into the [inject_target] of [target]!") else visible_message("[src] bites [target], but cannot inject venom into their [inject_target]!") 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 8ad926a8729..8c43cc6b1a0 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 @@ -1,3 +1,4 @@ + // Terror Spider, Black, Deadly Venom /datum/reagent/terror_black_toxin @@ -8,26 +9,44 @@ metabolization_rate = 0.1 /datum/reagent/terror_black_toxin/on_mob_life(mob/living/M) - if(volume < 15) - // bitten once, die slowly. Easy to survive a single bite - just go to medbay. - // total damage: 2/tick, human health 150 until crit, = 75 ticks, = 150 seconds = 2.5 minutes to get to medbay. - M.adjustToxLoss(2) // same damage/tick as tabun cycle 0 to 60 - else if(volume < 30) - // bitten twice, die more quickly, muscle cramps make movement difficult. Call medics immediately. - // total damage: 4, human health 150 until crit, = 37.5 ticks, = 75s = 1m15s until death - M.adjustToxLoss(4) - M.Confused(3) + if(volume < 30) + // bitten once, die very slowly. Easy to survive a single bite - just go to medbay. + // total damage: 1/tick, human health 150 until crit, = 150 ticks, = 300 seconds = 5 minutes to get to medbay. + M.adjustToxLoss(1) + else if(volume < 60) + // bitten twice, die slowly. Get to medbay. + // total damage: 2/tick, human health 150 until crit, = 75 ticks, = 150 seconds = 2.5 minutes to get some medical treatment. + M.adjustToxLoss(2) M.EyeBlurry(3) - else if(volume < 45) - // bitten thrice, die very quickly, severe muscle cramps make movement very difficult. Even calling for help probably won't save you. - // total damage: 8, human health 150 until crit, = 18.75 ticks, = 37s until death - M.adjustToxLoss(8) // a bit worse than coiine + 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 + M.adjustToxLoss(4) // a bit worse than coiine M.Confused(6) M.EyeBlurry(6) else // bitten 4 or more times, whole body goes into shock/death - // total damage: 12, human health 150 until crit, = 12.5 ticks, = 25s until death - M.adjustToxLoss(12) + // total damage: 8, human health 150 until crit, = 18.75 ticks, = 37s until death + M.adjustToxLoss(8) M.EyeBlurry(6) M.Paralyse(5) ..() + + + +// Terror Spider, Queen Toxin + +/datum/reagent/terror_queen_toxin + name = "Terror Queen venom" + id = "terror_queen_toxin" + description = "A royally potent venom." + color = "#CF3600" + metabolization_rate = 2 + +/datum/reagent/terror_queen_toxin/on_mob_life(mob/living/M as mob) + if(!M) + M = holder.my_atom + // make them hallucinate a lot, like a changeling sting + M.hallucination = min(400, M.hallucination+50) + + diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/ghost.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/ghost.dm index 06703cc2106..ddfbf598fc7 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/ghost.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/ghost.dm @@ -13,15 +13,15 @@ return var/error_on_humanize = "" var/humanize_prompt = "Take direct control of [src]?" - humanize_prompt += "Role: [spider_role_summary]" + humanize_prompt += " Role: [spider_role_summary]" if(user.ckey in ts_ckey_blacklist) error_on_humanize = "You are not able to control any terror spider this round." - else if(!ai_playercontrol_allowingeneral) - error_on_humanize = "Terror spiders cannot currently be player-controlled." else if(spider_awaymission) error_on_humanize = "Terror spiders that are part of an away mission cannot be controlled by ghosts." else if(!ai_playercontrol_allowtype) error_on_humanize = "This specific type of terror spider is not player-controllable." + else if(degenerate) + error_on_humanize = "Dying spiders are not player-controllable." else if(stat == DEAD) error_on_humanize = "Dead spiders are not player-controllable." if(jobban_isbanned(user, "Syndicate") || jobban_isbanned(user, "alien")) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/gray.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/gray.dm index 42c16cc7666..04ee2b97d25 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/gray.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/gray.dm @@ -18,11 +18,8 @@ health = 120 melee_damage_lower = 10 melee_damage_upper = 20 - ventcrawler = 1 move_to_delay = 5 // normal speed stat_attack = 1 // ensures they will target people in crit, too! - environment_smash = 1 - /mob/living/simple_animal/hostile/poison/terror_spider/gray/spider_specialattack(mob/living/carbon/human/L, poisonable) if(!poisonable) 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 new file mode 100644 index 00000000000..56265386686 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/green.dm @@ -0,0 +1,60 @@ + +// -------------------------------------------------------------------------------- +// ----------------- TERROR SPIDERS: T1 GREEN TERROR ------------------------------ +// -------------------------------------------------------------------------------- +// -------------: ROLE: reproduction +// -------------: SPECIAL: can also create webs, web normal objects, etc +// -------------: TO FIGHT IT: kill it however you like - just don't die to it! +// -------------: SPRITES FROM: FoS, http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=386 + +/mob/living/simple_animal/hostile/poison/terror_spider/green + name = "Green Terror spider" + desc = "An ominous-looking green spider. It has a small egg-sac attached to it, and dried blood stains on its carapace." + spider_role_summary = "Average melee spider that webs its victims and lays more spider eggs" + + icon_state = "terror_green" + icon_living = "terror_green" + icon_dead = "terror_green_dead" + maxHealth = 120 + health = 120 + melee_damage_lower = 10 + melee_damage_upper = 20 + var/feedings_to_lay = 2 + + var/datum/action/innate/terrorspider/greeneggs/greeneggs_action + + +/mob/living/simple_animal/hostile/poison/terror_spider/green/New() + ..() + greeneggs_action = new() + greeneggs_action.Grant(src) + +/mob/living/simple_animal/hostile/poison/terror_spider/green/proc/DoLayGreenEggs() + var/obj/effect/spider/eggcluster/E = locate() in get_turf(src) + if(E) + to_chat(src, "There is already a cluster of eggs here!") + else if(fed < feedings_to_lay) + to_chat(src, "You must wrap more prey before you can do this!") + else + visible_message("[src] begins to lay a cluster of eggs.") + if(prob(33)) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/red, 1, 1) + else if(prob(50)) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/gray, 1, 1) + else + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/green, 1, 1) + fed -= feedings_to_lay + +/mob/living/simple_animal/hostile/poison/terror_spider/green/spider_specialattack(mob/living/carbon/human/L, poisonable) + if(!poisonable) + ..() + return + var/inject_target = pick("chest","head") + if(L.stunned || L.can_inject(null,0,inject_target,0)) + if(L.eye_blurry < 60) + L.AdjustEyeBlurry(10) + // instead of having a venom that only lasts seconds, we just add the eyeblur directly. + visible_message("[src] buries its fangs deep into the [inject_target] of [target]!") + else + visible_message("[src] bites [target], but cannot inject venom into their [inject_target]!") + L.attack_animal(src) \ No newline at end of file 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 new file mode 100644 index 00000000000..eda1836a968 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/hive.dm @@ -0,0 +1,43 @@ + +// All terror spider code that relates to queen ruling over a hive + + +/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 ts_spiderlist) + if(T.spider_awaymission != spider_awaymission) + continue + hsline = "* [T] in [get_area(T)], " + if(T.stat == DEAD) + hsline += "DEAD" + else + hsline += "health [T.health] / [T.maxHealth], " + if(T.ckey) + hsline += " *Player Controlled* " + else + hsline += " AI " + to_chat(src,hsline) + + +/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 ts_spiderlist) + 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 ts_spiderlist) + if(T.stat != DEAD && !T.spider_placed && spider_awaymission == T.spider_awaymission) + if(T.type == specific_type) + numspiders += 1 + for(var/obj/effect/spider/eggcluster/terror_eggcluster/E in ts_egg_list) + if(E.spiderling_type == specific_type && E.z == z) + numspiders += E.spiderling_number + for(var/obj/effect/spider/spiderling/terror_spiderling/L in ts_spiderling_list) + if(!L.stillborn && L.grow_as == specific_type && L.z == z) + numspiders += 1 + return numspiders + diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/mother.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/mother.dm new file mode 100644 index 00000000000..634948d1a58 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/mother.dm @@ -0,0 +1,45 @@ + +// -------------------------------------------------------------------------------- +// ----------------- TERROR SPIDERS: T3 MOTHER OF TERROR -------------------------- +// -------------------------------------------------------------------------------- +// -------------: ROLE: living schmuck bait +// -------------: 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. +// -------------: SPRITES FROM: FoS, http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=386 + +/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." + + icon_state = "terror_gray2" + icon_living = "terror_gray2" + icon_dead = "terror_gray2_dead" + maxHealth = 50 + health = 50 + melee_damage_lower = 10 + melee_damage_upper = 20 + move_to_delay = 5 + + spider_tier = TS_TIER_3 + spider_opens_doors = 2 + + var/canspawn = 1 + +/mob/living/simple_animal/hostile/poison/terror_spider/mother/death(gibbed) + if(canspawn) + canspawn = 0 + for(var/i=0, i<30, i++) + var/obj/effect/spider/spiderling/terror_spiderling/S = new /obj/effect/spider/spiderling/terror_spiderling(get_turf(src)) + S.grow_as = pick(/mob/living/simple_animal/hostile/poison/terror_spider/red, /mob/living/simple_animal/hostile/poison/terror_spider/gray) + if(prob(66)) + S.stillborn = 1 + else if(prob(10)) + S.grow_as = pick(/mob/living/simple_animal/hostile/poison/terror_spider/black, /mob/living/simple_animal/hostile/poison/terror_spider/green) + visible_message("[src] breaks apart, the many spiders on its back scurrying everywhere!") + degenerate = 1 + ..() + +/mob/living/simple_animal/hostile/poison/terror_spider/mother/Destroy() + canspawn = 0 + return ..() \ No newline at end of file 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 669449a6ae3..5a3a746e1a9 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 @@ -11,20 +11,34 @@ /mob/living/simple_animal/hostile/poison/terror_spider/prince name = "Prince of Terror spider" desc = "An enormous, terrifying spider. It looks like it is judging everything it sees. Its hide seems armored, and it bears the scars of many battles." - spider_role_summary = "Boss-level terror spider. Lightning bruiser. Capable of taking on a squad by itself." + spider_role_summary = "Miniboss terror spider. Lightning bruiser." + icon_state = "terror_allblack" icon_living = "terror_allblack" icon_dead = "terror_allblack_dead" - maxHealth = 400 // 20 laser shots. - health = 400 - melee_damage_lower = 15 - melee_damage_upper = 25 - move_to_delay = 5 - ventcrawler = 1 + + maxHealth = 600 // 30 laser shots + health = 600 + regen_points_per_hp = 6 // double the normal - IE halved regen speed + + melee_damage_lower = 20 + melee_damage_upper = 30 + move_to_delay = 4 // faster than normal + + ventcrawler = 0 + environment_smash = 3 + loot = list(/obj/item/clothing/accessory/medal) spider_tier = TS_TIER_3 spider_opens_doors = 2 + var/datum/action/innate/terrorspider/princesmash/princesmash_action + + +/mob/living/simple_animal/hostile/poison/terror_spider/prince/New() + ..() + princesmash_action = new() + princesmash_action.Grant(src) /mob/living/simple_animal/hostile/poison/terror_spider/prince/spider_specialattack(mob/living/carbon/human/L) if(prob(15)) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/purple.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/purple.dm new file mode 100644 index 00000000000..14515567f4a --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/purple.dm @@ -0,0 +1,87 @@ + +// -------------------------------------------------------------------------------- +// ----------------- TERROR SPIDERS: T2 PURPLE TERROR ----------------------------- +// -------------------------------------------------------------------------------- +// -------------: ROLE: guarding queen nests +// -------------: SPECIAL: chance to stun on hit +// -------------: TO FIGHT IT: shoot it from range, bring friends! +// -------------: SPRITES FROM: FoS, http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=386 + +/mob/living/simple_animal/hostile/poison/terror_spider/purple + name = "Purple Terror spider" + desc = "An ominous-looking purple spider. It looks about warily, as if waiting for something." + spider_role_summary = "Guards the nest of the Queen of Terror." + + icon_state = "terror_purple" + icon_living = "terror_purple" + icon_dead = "terror_purple_dead" + maxHealth = 200 + health = 200 + melee_damage_lower = 15 + melee_damage_upper = 25 + move_to_delay = 6 + + spider_tier = TS_TIER_2 + spider_opens_doors = 2 + + ventcrawler = 0 + environment_smash = 3 + + var/dcheck_counter = 0 + var/queen_visible = 1 + var/cycles_noqueen = 0 + + +/mob/living/simple_animal/hostile/poison/terror_spider/purple/spider_specialattack(mob/living/carbon/human/L, poisonable) + if(cycles_noqueen < 6 && prob(10)) + visible_message("[src] rams into [L], knocking them to the floor!") + L.Weaken(5) + L.Stun(5) + else + ..() + + +/mob/living/simple_animal/hostile/poison/terror_spider/purple/Life() + ..() + if(!degenerate && spider_myqueen) + if(dcheck_counter >= 10) + dcheck_counter = 0 + purple_distance_check() + else + dcheck_counter++ + + +/mob/living/simple_animal/hostile/poison/terror_spider/purple/proc/purple_distance_check() + if(spider_myqueen) + var/mob/living/simple_animal/hostile/poison/terror_spider/queen/Q = spider_myqueen + if(Q) + if(Q.stat == DEAD) + spider_myqueen = null + degenerate = 1 + to_chat(src,"Your Queen has died! Her power no longer sustains you!") + return + queen_visible = 0 + for(var/mob/living/M in view(src, vision_range)) + if(M == Q) + queen_visible = 1 + break + if(queen_visible) + cycles_noqueen = 0 + if(spider_debug) + to_chat(src,"Queen visible.") + else + cycles_noqueen++ + if(spider_debug) + to_chat(src,"Queen NOT visible. Cycles: [cycles_noqueen].") + if(cycles_noqueen == 3) + // one minute without queen sighted + to_chat(src,"You wonder where your Queen is.") + else if(cycles_noqueen == 6) + // two minutes without queen sighted + to_chat(src,"Without your Queen in sight, you feel yourself getting weaker...") + else if(cycles_noqueen >= 9) + // three minutes without queen sighted, kill them. + degenerate = 1 + to_chat(src,"Your link to your Queen has been broken! Your life force starts to drain away!") + melee_damage_lower = 5 + melee_damage_upper = 10 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 new file mode 100644 index 00000000000..37c92264ebd --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm @@ -0,0 +1,222 @@ + +// -------------------------------------------------------------------------------- +// ----------------- TERROR SPIDERS: T4 QUEEN OF TERROR --------------------------- +// -------------------------------------------------------------------------------- +// -------------: ROLE: gamma-level threat to the whole station, like a blob +// -------------: 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. +// -------------: SPRITES FROM: FoS, http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=386 + +/mob/living/simple_animal/hostile/poison/terror_spider/queen + name = "Queen of Terror spider" + desc = "An enormous, terrifying spider. Its egg sac is almost as big as its body, and teeming with spider eggs!" + spider_role_summary = "Commander of the spider forces. Lays eggs, directs the brood." + + icon_state = "terror_queen" + icon_living = "terror_queen" + icon_dead = "terror_queen_dead" + maxHealth = 200 + health = 200 + melee_damage_lower = 10 + melee_damage_upper = 20 + move_to_delay = 15 // yeah, this is very slow, but + ventcrawler = 1 + var/spider_spawnfrequency = 1200 // 120 seconds + var/spider_spawnfrequency_stable = 1200 // 120 seconds. Spawnfrequency is set to this on ai spiders once nest setup is complete. + var/spider_lastspawn = 0 + var/nestfrequency = 150 // 15 seconds + var/lastnestsetup = 0 + var/neststep = 0 + var/hasnested = 0 + var/spider_max_per_nest = 20 // above this, queen stops spawning more, and declares war. + + var/canlay = 0 // main counter for egg-laying ability! # = num uses, incremented at intervals + var/spider_can_fakelings = 3 // spawns defective spiderlings that don't grow up, used to freak out crew, atmosphere + + force_threshold = 18 // outright immune to anything of force under 18, this means welders can't hurt it, only guns can + + ranged = 1 + retreat_distance = 5 + minimum_distance = 5 + projectilesound = 'sound/weapons/pierce.ogg' + projectiletype = /obj/item/projectile/terrorqueenspit + + spider_tier = TS_TIER_4 + spider_opens_doors = 2 + loot = list(/obj/item/clothing/accessory/medal) + + 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 + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/New() + ..() + queennest_action = new() + queennest_action.Grant(src) + spider_myqueen = src + if(spider_awaymission) + spider_growinstantly = 1 + spider_spawnfrequency = 150 + + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/Life() + ..() + if(stat != DEAD) + if(ckey && canlay < 12 && hasnested) // max 12 eggs worth stored at any one time, realistically that's tons. + if(world.time > (spider_lastspawn + spider_spawnfrequency)) + canlay++ + spider_lastspawn = world.time + if(canlay == 1) + to_chat(src, "You are able to lay eggs again.") + 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.") + + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/death(gibbed) + if(!hasdied) + // 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 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 + ..() + +/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) + hasnested = 1 + ventcrawler = 0 + environment_smash = 3 + 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 player_list) + if(H.z != src.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(!hasnested) + to_chat(src, "You must nest before doing this.") + return + if(canlay < 1) + var/remainingtime = round(((spider_lastspawn + spider_spawnfrequency) - world.time) / 10, 1) + if(remainingtime > 0) + to_chat(src, "Too soon to attempt that again. Wait another [num2text(remainingtime)] seconds.") + 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 >= 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/eggtype = input("What kind of eggs?") as null|anything in eggtypes + 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, 0) + else if(eggtype == TS_DESC_PRINCE) + canlay -= 12 + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/prince, 1, 0) + return + var/numlings = 1 + if(eggtype != TS_DESC_PURPLE) + if(canlay >= 5) + numlings = input("How many in the batch?") as null|anything in list(1, 2, 3, 4, 5) + else if(canlay >= 3) + numlings = input("How many in the batch?") as null|anything in list(1, 2, 3) + else if(canlay == 2) + numlings = input("How many in the batch?") as null|anything in list(1, 2) + if(eggtype == null || numlings == null) + to_chat(src, "Cancelled.") + return + //spider_lastspawn = world.time // don't think we actually need this, if queen is laying manually canlay controls her rate. + canlay -= numlings + if(eggtype == TS_DESC_RED) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/red, numlings, 1) + else if(eggtype == TS_DESC_GRAY) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/gray, numlings, 1) + else if(eggtype == TS_DESC_GREEN) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/green, numlings, 1) + else if(eggtype == TS_DESC_BLACK) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/black, numlings, 1) + else if(eggtype == TS_DESC_PURPLE) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, numlings, 0) + else + to_chat(src, "Unrecognized egg type.") + + + +/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!") + for(var/obj/machinery/light/L in orange(light_range, src)) + if(L.on && prob(light_chance)) + L.broken() + for(var/obj/machinery/camera/C in orange(camera_range, src)) + if(C.status && prob(camera_chance)) + C.toggle_cam(src, 0) + + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/QueenFakeLings() + if(spider_can_fakelings) + spider_can_fakelings-- + var/numlings = 15 + for(var/i in 1 to numlings) + var/obj/effect/spider/spiderling/terror_spiderling/S = new /obj/effect/spider/spiderling/terror_spiderling(get_turf(src)) + S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/red + S.stillborn = 1 + S.name = "Evil-Looking Spiderling" + S.desc = "It moves very quickly, hisses loudly for its size... and has disproportionately large fangs. Hopefully it does not grow up..." + if(!spider_can_fakelings) + queenfakelings_action.Remove(src) + else + to_chat(src, "You have run out of uses of this ability.") + + + +/obj/item/projectile/terrorqueenspit + name = "poisonous spit" + damage = 0 + icon_state = "toxin" + damage_type = TOX + + +/obj/item/projectile/terrorqueenspit/on_hit(mob/living/carbon/target) + if(istype(target, /mob)) + var/mob/living/L = target + if(L.reagents) + if(L.can_inject(null, 0, "chest", 0)) + L.reagents.add_reagent("terror_queen_toxin", 15) + if(!istype(L, /mob/living/simple_animal/hostile/poison/terror_spider)) + L.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 new file mode 100644 index 00000000000..cf5a17647e2 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/reproduction.dm @@ -0,0 +1,179 @@ + +// -------------------------------------------------------------------------------- +// ----------------- TERROR SPIDERS: SPIDERLINGS (USED BY GREEN, WHITE, QUEEN AND MOTHER TYPES) +// -------------------------------------------------------------------------------- + +/obj/effect/spider/spiderling/terror_spiderling + name = "spiderling" + desc = "A fast-moving tiny spider, prone to making aggressive hissing sounds. Hope it doesn't grow up." + icon_state = "spiderling" + anchored = 0 + layer = 2.75 + health = 3 + var/stillborn = 0 + faction = list("terrorspiders") + var/spider_myqueen = null + var/use_vents = 1 + + +/obj/effect/spider/spiderling/terror_spiderling/New() + ..() + ts_spiderling_list += src + + +/obj/effect/spider/spiderling/terror_spiderling/Destroy() + ts_spiderling_list -= src + return ..() + +/obj/effect/spider/spiderling/terror_spiderling/Bump(atom/A) + if(istype(A, /obj/structure/table)) + forceMove(A.loc) + else if(istype(A, /obj/machinery/recharge_station)) + qdel(src) + else + ..() + + +/obj/effect/spider/spiderling/terror_spiderling/process() + if(travelling_in_vent) + if(isturf(loc)) + travelling_in_vent = 0 + entry_vent = null + else if(entry_vent) + if(get_dist(src, entry_vent) <= 1) + var/list/vents = list() + for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in entry_vent.parent.other_atmosmch) + vents.Add(temp_vent) + if(!vents.len) + entry_vent = null + return + var/obj/machinery/atmospherics/unary/vent_pump/exit_vent = pick(vents) + if(prob(50)) + visible_message("[src] scrambles into the ventillation ducts!", "You hear something squeezing through the ventilation ducts.") + var/original_location = loc + spawn(rand(20,60)) + forceMove(exit_vent) + var/travel_time = round(get_dist(loc, exit_vent.loc) / 2) + spawn(travel_time) + if(!exit_vent || exit_vent.welded) + forceMove(original_location) + entry_vent = null + return + if(prob(50)) + audible_message("You hear something squeezing through the ventilation ducts.") + spawn(travel_time) + if(!exit_vent || exit_vent.welded) + forceMove(original_location) + entry_vent = null + return + forceMove(exit_vent.loc) + entry_vent = null + var/area/new_area = get_area(loc) + if(new_area) + new_area.Entered(src) + else if(prob(33)) + var/list/nearby = oview(10, src) + if(nearby.len) + var/target_atom = pick(nearby) + walk_to(src, target_atom) + else if(prob(10) && use_vents) + for(var/obj/machinery/atmospherics/unary/vent_pump/v in view(7,src)) + if(!v.welded) + entry_vent = v + walk_to(src, entry_vent, 1) + break + if(isturf(loc)) + amount_grown += rand(0,2) + if(amount_grown >= 100) + if(stillborn) + die() + 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.faction = faction + S.spider_myqueen = spider_myqueen + S.master_commander = master_commander + qdel(src) + + +// -------------------------------------------------------------------------------- +// ----------------- TERROR SPIDERS: EGGS (USED BY NURSE AND QUEEN TYPES) --------- +// -------------------------------------------------------------------------------- + +/mob/living/simple_animal/hostile/poison/terror_spider/proc/DoLayTerrorEggs(lay_type, lay_number, lay_crawl) + stop_automated_movement = 1 + var/obj/effect/spider/eggcluster/terror_eggcluster/C = new /obj/effect/spider/eggcluster/terror_eggcluster(get_turf(src)) + C.spiderling_type = lay_type + C.spiderling_number = lay_number + C.spiderling_ventcrawl = lay_crawl + C.faction = faction + C.spider_myqueen = spider_myqueen + C.master_commander = master_commander + if(spider_growinstantly) + C.amount_grown = 250 + C.spider_growinstantly = 1 + spawn(10) + stop_automated_movement = 0 + + +/obj/effect/spider/eggcluster/terror_eggcluster + 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 + faction = list("terrorspiders") + var/spider_myqueen = null + var/spiderling_type = null + var/spiderling_number = 1 + var/spiderling_ventcrawl = 1 + + +/obj/effect/spider/eggcluster/terror_eggcluster/New() + ..() + ts_egg_list += src + spawn(50) + if(spiderling_type == /mob/living/simple_animal/hostile/poison/terror_spider/red) + name = "red terror eggs" + else if(spiderling_type == /mob/living/simple_animal/hostile/poison/terror_spider/gray) + name = "gray terror eggs" + else if(spiderling_type == /mob/living/simple_animal/hostile/poison/terror_spider/green) + name = "green terror eggs" + else if(spiderling_type == /mob/living/simple_animal/hostile/poison/terror_spider/black) + name = "black terror eggs" + else if(spiderling_type == /mob/living/simple_animal/hostile/poison/terror_spider/purple) + name = "purple terror eggs" + else if(spiderling_type == /mob/living/simple_animal/hostile/poison/terror_spider/white) + name = "white terror eggs" + else if(spiderling_type == /mob/living/simple_animal/hostile/poison/terror_spider/mother) + name = "mother of terror eggs" + else if(spiderling_type == /mob/living/simple_animal/hostile/poison/terror_spider/prince) + name = "prince of terror eggs" + else if(spiderling_type == /mob/living/simple_animal/hostile/poison/terror_spider/queen) + name = "queen of terror eggs" + + +/obj/effect/spider/eggcluster/terror_eggcluster/Destroy() + ts_egg_list -= src + return ..() + +/obj/effect/spider/eggcluster/terror_eggcluster/process() + amount_grown += rand(0,2) + if(amount_grown >= 100) + var/num = spiderling_number + for(var/i=0, i spider_tier) visible_message("[src] bows in respect for the terrifying presence of [target].") @@ -163,10 +167,15 @@ var/global/list/ts_spiderlist = list() spider_specialattack(G,can_poison) else G.attack_animal(src) + else if(istype(target, /obj/structure/alien/resin)) + var/obj/structure/alien/resin/E = target + do_attack_animation(E) + E.health -= rand(melee_damage_lower, melee_damage_upper) + E.healthcheck() else target.attack_animal(src) -/mob/living/simple_animal/hostile/poison/terror_spider/proc/spider_specialattack(mob/living/carbon/human/L, var/poisonable) +/mob/living/simple_animal/hostile/poison/terror_spider/proc/spider_specialattack(mob/living/carbon/human/L, poisonable) L.attack_animal(src) @@ -195,6 +204,8 @@ var/global/list/ts_spiderlist = list() msgs += "It has many injuries." else if(health > (maxHealth*0.25)) msgs += "It is barely clinging on to life!" + if(degenerate) + msgs += "It appears to be dying." else if(health < maxHealth && regen_points > regen_points_per_kill) msgs += "It appears to be regenerating quickly." if(killcount >= 1) @@ -206,7 +217,8 @@ var/global/list/ts_spiderlist = list() ..() ts_spiderlist += src add_language("Spider Hivemind") - add_language("Galactic Common") + if(spider_tier >= TS_TIER_2) + add_language("Galactic Common") default_language = all_languages["Spider Hivemind"] web_action = new() @@ -215,6 +227,7 @@ var/global/list/ts_spiderlist = list() wrap_action.Grant(src) name += " ([rand(1, 1000)])" + real_name = name msg_terrorspiders("[src] has grown in [get_area(src)].") if(is_away_level(z)) spider_awaymission = 1 @@ -233,7 +246,7 @@ var/global/list/ts_spiderlist = list() 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) - else if(ai_playercontrol_allowingeneral && ai_playercontrol_allowtype) + 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, attack_not_jump = 1) @@ -250,6 +263,8 @@ var/global/list/ts_spiderlist = list() visible_message("\The dead body of the [src] decomposes!") gib() else + if(degenerate > 0) + adjustToxLoss(rand(1,10)) if(regen_points < regen_points_max) regen_points += regen_points_per_tick if((bruteloss > 0) || (fireloss > 0)) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/white.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/white.dm new file mode 100644 index 00000000000..32d48a80264 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/white.dm @@ -0,0 +1,41 @@ + +// -------------------------------------------------------------------------------- +// ----------------- TERROR SPIDERS: T2 WHITE TERROR ------------------------------ +// -------------------------------------------------------------------------------- +// -------------: ROLE: stealthy reproduction +// -------------: AI: injects a venom that makes you grow spiders in your body, then retreats +// -------------: SPECIAL: stuns you on first attack - vulnerable to groups while it does this +// -------------: TO FIGHT IT: blast it before it can get away +// -------------: SPRITES FROM: FoS, http://nanotrasen.se/phpBB3/memberlist.php?mode=viewprofile&u=386 + +/mob/living/simple_animal/hostile/poison/terror_spider/white + name = "White Terror spider" + desc = "An ominous-looking white spider, its ghostly eyes and vicious-looking fangs are the stuff of nightmares." + spider_role_summary = "Rare, bite-and-run spider that infects hosts with spiderlings" + + icon_state = "terror_white" + icon_living = "terror_white" + icon_dead = "terror_white_dead" + maxHealth = 100 + health = 100 + melee_damage_lower = 5 + melee_damage_upper = 15 + move_to_delay = 4 + spider_tier = TS_TIER_2 + loot = list(/obj/item/clothing/accessory/medal) + +/mob/living/simple_animal/hostile/poison/terror_spider/white/spider_specialattack(mob/living/carbon/human/L, poisonable) + if(!poisonable) + ..() + return + var/inject_target = pick("chest","head") + L.attack_animal(src) + if(L.stunned || L.paralysis || L.can_inject(null,0,inject_target,0)) + if(!IsInfected(L)) + visible_message("[src] buries its long fangs deep into the [inject_target] of [L]!") + new /obj/item/organ/internal/body_egg/terror_eggs(L) + +/mob/living/simple_animal/hostile/poison/terror_spider/proc/IsInfected(mob/living/carbon/C) // Terror AI requires this + if(C.get_int_organ(/obj/item/organ/internal/body_egg)) + return 1 + return 0 diff --git a/code/modules/surgery/organs/parasites.dm b/code/modules/surgery/organs/parasites.dm index 61e72743464..b3f274c3838 100644 --- a/code/modules/surgery/organs/parasites.dm +++ b/code/modules/surgery/organs/parasites.dm @@ -1,3 +1,6 @@ + +// Traitor-only space spider eggs + /obj/item/organ/internal/body_egg/spider_eggs name = "spider eggs" icon = 'icons/effects/effects.dmi' @@ -34,3 +37,82 @@ M.reagents.del_reagent("spidereggs") //purge all remaining spider eggs reagent if caught, in time. qdel(src) //We don't want people re-implanting these for near instant gibbings. return null + + + +// Terror Spiders - white spider infection + +/obj/item/organ/internal/body_egg/terror_eggs + name = "terror eggs" + icon = 'icons/effects/effects.dmi' + icon_state = "eggs" + var/current_cycle = 0 + var/awaymission_infection = 0 + var/alternate_ending = 0 + +/obj/item/organ/internal/body_egg/terror_eggs/on_life() + current_cycle += 1 + if(owner.health < -25) + to_chat(owner,"You feel a strange, blissful senstation.") + owner.adjustBruteLoss(-5) + owner.adjustFireLoss(-5) + owner.adjustToxLoss(-5) + // the spider eggs secrete stimulants to keep their host alive until they hatch + switch(current_cycle) + if(1) // immediately + to_chat(owner,"Your spider bite wound hurts horribly! ") + if(istype(get_area(owner), /area/awaycontent) || istype(get_area(owner), /area/awaymission/)) + awaymission_infection = 1 + if(15) // 30 seconds... enough time for the nerve agent to kick in, the pain to be blocked, and healing to begin + to_chat(owner,"The pain has faded, and stopped bleeding, though the skin around it has turned black.") + owner.adjustBruteLoss(-10) + if(60) // 2 minutes... the point where the venom uses and accellerates the healing process, to feed the eggs + to_chat(owner,"Your bite wound has completely sealed up, though the skin is still black. You feel significantly better.") + owner.adjustBruteLoss(-20) + if(120) // 4 minutes... where the eggs are developing, and the wound is turning into a hatching site, but invisibly + to_chat(owner,"The black flesh around your old spider bite wound has started to peel off.") + if(150) // 5 minutes... where the victim realizes something is wrong - this is not a normal wound + to_chat(owner,"The black flesh around your spider bite wound has cracked, and started to split open!") + if(165) // 5m 30s + to_chat(owner,"The black flesh splits open completely, revealing a cluster of small black oval shapes inside you, shapes that seem to be moving!") + if(180) // 6m + if(awaymission_infection && is_away_level(owner.z)) + // we started in the awaymission, we ended on the station. + // To prevent someone bringing an infection back, we're going to trigger an alternate, equally-bad result here. + // Actually, let's make it slightly worse... just to discourage people from bringing back infections. + alternate_ending = 1 + to_chat(owner,"The shapes extend tendrils out of your wound... no... those are legs! SPIDER LEGS! You have spiderlings growing inside you! You scratch at the wound, but it just aggrivates them - they swarm out of the wound, biting you all over!") + owner.visible_message("[owner] flails around on the floor as spiderlings erupt from their skin and swarm all over them! ") + owner.Stun(20) + owner.Weaken(20) + // yes, this is a long stun - that's intentional. Gotta give the spiderlings time to escape. + var/obj/effect/spider/spiderling/terror_spiderling/S1 = new(get_turf(owner)) + S1.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/red + S1.name = "red spiderling" + if(prob(50)) + S1.stillborn = 1 + var/obj/effect/spider/spiderling/terror_spiderling/S2 = new(get_turf(owner)) + S2.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/gray + S2.name = "gray spiderling" + if(prob(50)) + S2.stillborn = 1 + var/obj/effect/spider/spiderling/terror_spiderling/S3 = new(get_turf(owner)) + S3.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/green + S3.name = "green spiderling" + if(prob(50)) + S3.stillborn = 1 + if(alternate_ending) + S1.stillborn = 1 + S2.stillborn = 1 + S3.stillborn = 1 + owner.gib() + else + owner.adjustToxLoss(rand(100,180)) // normal case, range: 100-180, average 140, almost crit (150). + if(190) // 6m 30s + to_chat(owner,"The spiderlings are gone. Your wound, though, looks worse than ever. Remnants of tiny spider eggs, and dead spiders, inside your flesh. Disgusting.") + qdel(src) + +/obj/item/organ/internal/body_egg/terror_eggs/remove(var/mob/living/carbon/M, var/special = 0) + ..() + qdel(src) // prevent people re-implanting them into others + return null diff --git a/paradise.dme b/paradise.dme index 2c8c24688fa..3012b8503cd 100644 --- a/paradise.dme +++ b/paradise.dme @@ -1299,6 +1299,7 @@ #include "code\modules\events\slaughterevent.dm" #include "code\modules\events\spacevine.dm" #include "code\modules\events\spider_infestation.dm" +#include "code\modules\events\spider_terror.dm" #include "code\modules\events\spontaneous_appendicitis.dm" #include "code\modules\events\tear.dm" #include "code\modules\events\traders.dm" @@ -1691,9 +1692,16 @@ #include "code\modules\mob\living\simple_animal\hostile\terror_spiders\chem.dm" #include "code\modules\mob\living\simple_animal\hostile\terror_spiders\ghost.dm" #include "code\modules\mob\living\simple_animal\hostile\terror_spiders\gray.dm" +#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\green.dm" +#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\hive.dm" +#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\mother.dm" #include "code\modules\mob\living\simple_animal\hostile\terror_spiders\prince.dm" +#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\purple.dm" +#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\queen.dm" #include "code\modules\mob\living\simple_animal\hostile\terror_spiders\red.dm" +#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\reproduction.dm" #include "code\modules\mob\living\simple_animal\hostile\terror_spiders\terror_spiders.dm" +#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\white.dm" #include "code\modules\mob\new_player\login.dm" #include "code\modules\mob\new_player\logout.dm" #include "code\modules\mob\new_player\new_player.dm"