diff --git a/code/__DEFINES/mob_defines.dm b/code/__DEFINES/mob_defines.dm index 722ff1172e6..39e0016bb4c 100644 --- a/code/__DEFINES/mob_defines.dm +++ b/code/__DEFINES/mob_defines.dm @@ -255,7 +255,7 @@ #define iscaterpillar(A) (istype((A), /mob/living/basic/nian_caterpillar)) #define ishostile(A) (istype((A), /mob/living/simple_animal/hostile)) #define isretaliate(A) (istype((A), /mob/living/simple_animal/hostile/retaliate)) -#define isterrorspider(A) (istype((A), /mob/living/simple_animal/hostile/poison/terror_spider)) +#define isterrorspider(A) (istype((A), /mob/living/simple_animal/hostile/poison/terror_spider) || istype((A), /mob/living/basic/spiderling/terror_spiderling)) #define isslaughterdemon(A) (istype((A), /mob/living/simple_animal/demon/slaughter)) #define isdemon(A) (istype((A), /mob/living/simple_animal/demon)) #define iscat(A) (istype((A), /mob/living/simple_animal/pet/cat)) diff --git a/code/datums/ai/basic_mobs/basic_subtrees/ventcrawl_find_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/ventcrawl_find_target.dm index 67dfc11e0ec..2a56c9cb934 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/ventcrawl_find_target.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/ventcrawl_find_target.dm @@ -1,4 +1,5 @@ /datum/ai_planning_subtree/ventcrawl_find_target + var/crawl_behavior = /datum/ai_behavior/find_ventcrawl_target /datum/ai_planning_subtree/ventcrawl_find_target/select_behaviors(datum/ai_controller/controller, seconds_per_tick) // We have a target already @@ -11,7 +12,7 @@ else vision_range = controller.blackboard[BB_VENT_SEARCH_RANGE] // Find a target - controller.queue_behavior(/datum/ai_behavior/find_ventcrawl_target, BB_VENTCRAWL_FINAL_TARGET, vision_range) + controller.queue_behavior(crawl_behavior, BB_VENTCRAWL_FINAL_TARGET, vision_range) return SUBTREE_RETURN_FINISH_PLANNING /datum/ai_behavior/find_ventcrawl_target diff --git a/code/datums/ai/basic_mobs/basic_subtrees/ventcrawl_subtree.dm b/code/datums/ai/basic_mobs/basic_subtrees/ventcrawl_subtree.dm index b590cf7067e..37f70dcfc60 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/ventcrawl_subtree.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/ventcrawl_subtree.dm @@ -1,4 +1,5 @@ /datum/ai_planning_subtree/ventcrawl + var/ventcrawl_finding_behavior = /datum/ai_behavior/find_and_set/ventcrawl /datum/ai_planning_subtree/ventcrawl/select_behaviors(datum/ai_controller/controller, seconds_per_tick) // we're in a pipe @@ -15,7 +16,7 @@ return SUBTREE_RETURN_FINISH_PLANNING // We dont have an exit vent, but we have a target. Let's find an exit vent near it. if(controller.blackboard_key_exists(BB_VENTCRAWL_FINAL_TARGET)) - controller.queue_behavior(/datum/ai_behavior/find_and_set/ventcrawl, BB_VENTCRAWL_EXIT, null, controller.blackboard[BB_VENT_SEARCH_RANGE]) + controller.queue_behavior(ventcrawl_finding_behavior, BB_VENTCRAWL_EXIT, null, controller.blackboard[BB_VENT_SEARCH_RANGE]) return // we dont have an set exit vent nor a final target... let's just get out of the pipe. controller.queue_behavior(/datum/ai_behavior/find_and_set/pipenet_vent, BB_VENTCRAWL_EXIT, null, controller.blackboard[BB_VENT_SEARCH_RANGE]) @@ -34,12 +35,15 @@ // we're far-away, lets try to find a ventcrawl path if(!controller.blackboard_key_exists(BB_VENTCRAWL_EXIT)) - controller.queue_behavior(/datum/ai_behavior/find_and_set/ventcrawl, BB_VENTCRAWL_EXIT, null, controller.blackboard[BB_VENT_SEARCH_RANGE], FALSE) + controller.queue_behavior(ventcrawl_finding_behavior, BB_VENTCRAWL_EXIT, null, controller.blackboard[BB_VENT_SEARCH_RANGE], FALSE) return // we found a path, lets take it! controller.queue_behavior(/datum/ai_behavior/interact_with_vent, BB_VENTCRAWL_ENTRANCE) return SUBTREE_RETURN_FINISH_PLANNING +/datum/ai_behavior/find_and_set/ventcrawl + var/list/searched_entry_types = list(/obj/machinery/atmospherics/unary/vent_pump, /obj/machinery/atmospherics/unary/vent_scrubber) + /** * This proc assumes that all ventcrawling creatures are omniscient. */ @@ -103,7 +107,7 @@ var/turf/current = popleft(open_set) closed_set |= current for(var/obj/machinery/atmospherics/atmos in current) - if(is_type_in_list(atmos, GLOB.ventcrawl_machinery) && atmos.can_crawl_through()) + if(is_type_in_list(atmos, searched_entry_types) && atmos.can_crawl_through()) vents |= atmos for(var/dir in GLOB.cardinal) @@ -166,6 +170,6 @@ controller.set_blackboard_key(BB_VENTCRAWL_IS_ENTERING, TRUE) L.handle_ventcrawl(vent) controller.set_blackboard_key(BB_VENTCRAWL_IS_ENTERING, FALSE) - if(controller.pawn.loc != vent) + if(QDELETED(controller) || controller.pawn.loc != vent) return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED diff --git a/code/game/gamemodes/miniantags/abduction/gland.dm b/code/game/gamemodes/miniantags/abduction/gland.dm index 1ea43104dbb..e69656bf740 100644 --- a/code/game/gamemodes/miniantags/abduction/gland.dm +++ b/code/game/gamemodes/miniantags/abduction/gland.dm @@ -257,7 +257,7 @@ /obj/item/organ/internal/heart/gland/spiderman/trigger() to_chat(owner, "You feel something crawling in your skin.") owner.faction |= "spiders" - var/obj/structure/spider/spiderling/S = new(owner.loc) + var/mob/living/basic/spiderling/S = new(owner.loc) S.master_commander = owner /obj/item/organ/internal/heart/gland/egg diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm index b249101a70d..877fd464316 100644 --- a/code/game/objects/effects/spiders.dm +++ b/code/game/objects/effects/spiders.dm @@ -76,160 +76,13 @@ if(amount_grown >= 100) var/num = rand(3, 12) for(var/i in 1 to num) - var/obj/structure/spider/spiderling/S = new /obj/structure/spider/spiderling(loc) + var/mob/living/basic/spiderling/S = new /mob/living/basic/spiderling(loc) S.faction = faction.Copy() S.master_commander = master_commander if(player_spiders) S.player_spiders = TRUE qdel(src) -/obj/structure/spider/spiderling - name = "spiderling" - desc = "It never stays still for long." - icon_state = "spiderling" - anchored = FALSE - layer = 2.75 - max_integrity = 3 - var/amount_grown = 0 - var/grow_as = null - var/obj/machinery/atmospherics/unary/vent_pump/entry_vent - var/travelling_in_vent = FALSE - var/player_spiders = FALSE - var/list/faction = list("spiders") - var/selecting_player = 0 - -/obj/structure/spider/spiderling/Initialize(mapload) - . = ..() - pixel_x = rand(6,-6) - pixel_y = rand(6,-6) - START_PROCESSING(SSobj, src) - AddComponent(/datum/component/swarming) - AddComponent(/datum/component/event_tracker, EVENT_TERROR_SPIDERS) - ADD_TRAIT(src, TRAIT_EDIBLE_BUG, "edible_bug") // Normally this is just used for mobs, but spiderlings are kind of that... - -/obj/structure/spider/spiderling/Destroy() - STOP_PROCESSING(SSobj, src) - // Cancel our movement. - GLOB.move_manager.stop_looping(src) - entry_vent = null - if(amount_grown < 100) - new /obj/effect/decal/cleanable/spiderling_remains(get_turf(src)) - return ..() - -/obj/structure/spider/spiderling/Bump(atom/user) - if(istype(user, /obj/structure/table)) - loc = user.loc - else - ..() - -/obj/structure/spider/spiderling/process() - if(travelling_in_vent) - if(isturf(loc)) - travelling_in_vent = FALSE - 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(!length(vents)) - entry_vent = null - return - var/obj/machinery/atmospherics/unary/vent_pump/exit_vent = pick(vents) - if(prob(50)) - visible_message("[src] scrambles into the ventilation ducts!", \ - "You hear something squeezing through the ventilation ducts.") - - spawn(rand(20,60)) - loc = exit_vent - var/travel_time = round(get_dist(loc, exit_vent.loc) / 2) - spawn(travel_time) - - if(!exit_vent || exit_vent.welded) - loc = entry_vent - entry_vent = null - return - - if(prob(50)) - audible_message("You hear something squeezing through the ventilation ducts.") - sleep(travel_time) - - if(!exit_vent || exit_vent.welded) - loc = entry_vent - entry_vent = null - return - loc = exit_vent.loc - entry_vent = null - var/area/new_area = get_area(loc) - if(new_area) - new_area.Entered(src) - //================= - - else if(prob(33)) - if(random_skitter() && prob(40)) - visible_message("[src] skitters[pick(" away"," around","")].") - else if(prob(10)) - //ventcrawl! - for(var/obj/machinery/atmospherics/unary/vent_pump/v in view(7,src)) - if(!v.welded) - entry_vent = v - GLOB.move_manager.home_onto(src, entry_vent, 1, 10) - break - if(isturf(loc)) - amount_grown += rand(0,2) - if(amount_grown >= 100) - if(SSmobs.xenobiology_mobs > MAX_GOLD_CORE_MOBS && HAS_TRAIT(src, TRAIT_XENOBIO_SPAWNED)) - qdel(src) - return - if(!grow_as) - grow_as = pick(typesof(/mob/living/basic/giant_spider) - list(/mob/living/basic/giant_spider/hunter/infestation_spider, /mob/living/basic/giant_spider/araneus)) - var/mob/living/basic/giant_spider/S = new grow_as(loc) - S.faction = faction.Copy() - S.master_commander = master_commander - if(HAS_TRAIT(src, TRAIT_XENOBIO_SPAWNED)) - ADD_TRAIT(S, TRAIT_XENOBIO_SPAWNED, "xenobio") - SSmobs.xenobiology_mobs++ - if(player_spiders && !selecting_player) - selecting_player = 1 - spawn() - var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a giant spider?", ROLE_SENTIENT, TRUE, source = S) - - if(length(candidates) && !QDELETED(S)) - var/mob/C = pick(candidates) - if(C) - S.key = C.key - dust_if_respawnable(C) - if(S.master_commander) - to_chat(S, "You are a spider who is loyal to [S.master_commander], obey [S.master_commander]'s every order and assist [S.master_commander.p_them()] in completing [S.master_commander.p_their()] goals at any cost.") - qdel(src) - -/obj/structure/spider/spiderling/proc/random_skitter() - var/list/available_turfs = list() - for(var/turf/simulated/S in oview(10, src)) - // no !isspaceturf check needed since /turf/simulated is not a subtype of /turf/space - if(S.density) - continue - available_turfs += S - if(!length(available_turfs)) - return FALSE - GLOB.move_manager.home_onto(src, pick(available_turfs), 1, 10) - return TRUE - -/obj/structure/spider/spiderling/decompile_act(obj/item/matter_decompiler/C, mob/user) - if(!isdrone(user)) - user.visible_message("[user] sucks [src] into its decompiler. There's a horrible crunching noise.", \ - "It's a bit of a struggle, but you manage to suck [src] into your decompiler. It makes a series of visceral crunching noises.") - C.stored_comms["metal"] += 2 - C.stored_comms["glass"] += 1 - qdel(src) - return TRUE - return ..() - -/obj/effect/decal/cleanable/spiderling_remains - name = "spiderling remains" - desc = "Green squishy mess." - icon_state = "greenshatter" - /obj/structure/spider/cocoon name = "cocoon" desc = "Something wrapped in silky spider web." diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index fe334c45d30..136423bd8cb 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -496,7 +496,7 @@ for(var/obj/structure/spider/eggcluster/terror_eggcluster/E in GLOB.ts_egg_list) if(is_station_level(E.z)) count_eggs += E.spiderling_number - for(var/obj/structure/spider/spiderling/terror_spiderling/L in GLOB.ts_spiderling_list) + for(var/mob/living/basic/spiderling/terror_spiderling/L in GLOB.ts_spiderling_list) if(!L.stillborn && is_station_level(L.z)) count_spiderlings += 1 count_infected = length(GLOB.ts_infected_list) diff --git a/code/modules/events/infestation.dm b/code/modules/events/infestation.dm index c908e831a11..e83031b49c9 100644 --- a/code/modules/events/infestation.dm +++ b/code/modules/events/infestation.dm @@ -64,7 +64,7 @@ max_number = 6 vermstring = "lizards" if(VERM_SPIDERS) - spawn_types = list(/obj/structure/spider/spiderling) + spawn_types = list(/mob/living/basic/spiderling) max_number = 3 vermstring = "spiders" var/amount_to_spawn = rand(2, max_number) @@ -73,7 +73,7 @@ amount_to_spawn-- if(vermin == VERM_SPIDERS) - var/obj/structure/spider/spiderling/S = new(T) + var/mob/living/basic/spiderling/S = new(T) S.amount_grown = -1 else var/spawn_type = pick(spawn_types) diff --git a/code/modules/events/spider_infestation.dm b/code/modules/events/spider_infestation.dm index 3e846a8a6b1..1b687fc631c 100644 --- a/code/modules/events/spider_infestation.dm +++ b/code/modules/events/spider_infestation.dm @@ -19,7 +19,7 @@ var/list/vents = get_valid_vent_spawns(exclude_mobs_nearby = TRUE) while(spawncount && length(vents)) var/obj/vent = pick_n_take(vents) - var/obj/structure/spider/spiderling/S = new(vent.loc) + var/mob/living/basic/spiderling/S = new(vent.loc) if(prob(66)) S.grow_as = /mob/living/basic/giant_spider/nurse spawncount-- diff --git a/code/modules/hydroponics/hydroponics_tray.dm b/code/modules/hydroponics/hydroponics_tray.dm index 42e38d2a97b..89553cf3949 100644 --- a/code/modules/hydroponics/hydroponics_tray.dm +++ b/code/modules/hydroponics/hydroponics_tray.dm @@ -500,7 +500,7 @@ log_game("[key_name(user)] caused spiderling pests to spawn in a hydro tray") visible_message("The pests seem to behave oddly...") for(var/i in 1 to 3) - var/obj/structure/spider/spiderling/S = new(get_turf(src)) + var/mob/living/basic/spiderling/S = new(get_turf(src)) S.grow_as = /mob/living/basic/giant_spider/hunter else to_chat(user, "The pests seem to behave oddly, but quickly settle down...") diff --git a/code/modules/mob/living/basic/friendly/lizard.dm b/code/modules/mob/living/basic/friendly/lizard.dm index 419246bc537..123fbe356fb 100644 --- a/code/modules/mob/living/basic/friendly/lizard.dm +++ b/code/modules/mob/living/basic/friendly/lizard.dm @@ -34,7 +34,7 @@ var/static/list/edibles = list( /mob/living/basic/butterfly, /mob/living/basic/cockroach, - /obj/structure/spider/spiderling + /mob/living/basic/spiderling ) /// Lizards start with a tail var/has_tail = TRUE diff --git a/code/modules/mob/living/basic/hostile/spiderlings.dm b/code/modules/mob/living/basic/hostile/spiderlings.dm new file mode 100644 index 00000000000..b34294856e0 --- /dev/null +++ b/code/modules/mob/living/basic/hostile/spiderlings.dm @@ -0,0 +1,172 @@ +/mob/living/basic/spiderling + name = "spiderling" + desc = "It never stays still for long." + icon_state = "spiderling" + icon_dead = "spiderling_dead" // Doesn't exist, because they splat. + density = FALSE + speed = -0.75 + move_resist = INFINITY // YOU CAN'T HANDLE ME LET ME BE FREE LET ME BE FREE LET ME BE FREE + speak_emote = list("hisses") + layer = 2.75 + basic_mob_flags = FLAMMABLE_MOB | DEL_ON_DEATH + pass_flags = PASSTABLE | PASSGRILLE | PASSMOB | PASSDOOR + mob_size = MOB_SIZE_TINY + ventcrawler = TRUE + melee_damage_lower = 1 + melee_damage_upper = 1 + health = 5 + maxHealth = 5 + faction = list("spiders") + attack_verb_simple = "bite" + attack_verb_continuous = "bites" + attack_sound = 'sound/weapons/bite.ogg' + can_hide = TRUE + ai_controller = /datum/ai_controller/basic_controller/spiderling + /// How grown up is the spider? + var/amount_grown = 0 + /// The mob the spiderling will grow into. null is giant spiders. + var/grow_as = null + /// Is the spider supposed to be player controlled? + var/player_spiders = FALSE + /// Are we selecting a player? + var/selecting_player = FALSE + +/mob/living/basic/spiderling/Initialize(mapload) + . = ..() + pixel_x = rand(6,-6) + pixel_y = rand(6,-6) + AddComponent(/datum/component/swarming) + AddElement(/datum/element/ai_retaliate) + ADD_TRAIT(src, TRAIT_EDIBLE_BUG, "edible_bug") + +/mob/living/basic/spiderling/Life(seconds, times_fired) + . = ..() + if(!isturf(loc)) + return + amount_grown += rand(0,2) + if(amount_grown < 100) + return + if(SSmobs.xenobiology_mobs > MAX_GOLD_CORE_MOBS && HAS_TRAIT(src, TRAIT_XENOBIO_SPAWNED)) + qdel(src) + return + if(!grow_as) + grow_as = pick(typesof(/mob/living/basic/giant_spider) - list(/mob/living/basic/giant_spider/hunter/infestation_spider, /mob/living/basic/giant_spider/araneus)) + var/mob/living/basic/giant_spider/S = new grow_as(loc) + S.faction = faction.Copy() + S.master_commander = master_commander + if(HAS_TRAIT(src, TRAIT_XENOBIO_SPAWNED)) + ADD_TRAIT(S, TRAIT_XENOBIO_SPAWNED, "xenobio") + SSmobs.xenobiology_mobs++ + if(!player_spiders) + qdel(src) + return + if(selecting_player) + return + selecting_player = TRUE + spawn() + var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a giant spider?", ROLE_SENTIENT, TRUE, source = S) + if(!length(candidates) || QDELETED(S)) + return + var/mob/C = pick(candidates) + if(C) + S.key = C.key + dust_if_respawnable(C) + if(S.master_commander) + to_chat(S, "You are a spider who is loyal to [S.master_commander], obey [S.master_commander]'s every order and assist [S.master_commander.p_them()] in completing [S.master_commander.p_their()] goals at any cost.") + qdel(src) + +/mob/living/basic/spiderling/death(gibbed) + if(!istype(loc, /obj/machinery/atmospherics)) + new /obj/effect/decal/cleanable/spiderling_remains(get_turf(src)) + . = ..() + +/mob/living/basic/spiderling/decompile_act(obj/item/matter_decompiler/C, mob/user) + if(isdrone(user)) + return ..() + user.visible_message("[user] sucks [src] into its decompiler. There's a horrible crunching noise.", \ + "It's a bit of a struggle, but you manage to suck [src] into your decompiler. It makes a series of visceral crunching noises.") + C.stored_comms["metal"] += 2 + C.stored_comms["glass"] += 1 + qdel(src) + return TRUE + +/obj/effect/decal/cleanable/spiderling_remains + name = "spiderling remains" + desc = "Green squishy mess." + icon_state = "greenshatter" + +// -------------------------------------------------------------------------------- +// ----------------- TERROR SPIDERS: SPIDERLINGS (USED BY GREEN, WHITE, QUEEN AND MOTHER TYPES) +// -------------------------------------------------------------------------------- + +/mob/living/basic/spiderling/terror_spiderling + desc = "A fast-moving tiny spider, prone to making aggressive hissing sounds. Hope it doesn't grow up." + speed = -1 + faction = list("terrorspiders") + var/stillborn = FALSE + var/mob/living/simple_animal/hostile/poison/terror_spider/queen/spider_myqueen = null + var/mob/living/simple_animal/hostile/poison/terror_spider/spider_mymother = null + var/list/enemies = list() + var/spider_awaymission = FALSE + +/mob/living/basic/spiderling/terror_spiderling/Initialize(mapload) + . = ..() + GLOB.ts_spiderling_list += src + if(is_away_level(z)) + spider_awaymission = TRUE + +/mob/living/basic/spiderling/terror_spiderling/death(gibbed) + GLOB.ts_spiderling_list -= src + return ..() + +/mob/living/basic/spiderling/terror_spiderling/Life(seconds, times_fired) + . = ..() + 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) + +/datum/ai_controller/basic_controller/spiderling + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/of_size/larger, // Run away from mobs bigger than we are + BB_VENT_SEARCH_RANGE = 10, + BB_VENTCRAWL_DELAY = 1 + ) + ai_movement = /datum/ai_movement/jps + idle_behavior = /datum/idle_behavior/idle_random_walk + + // We understand that vents are nice little hidey holes through epigenetic inheritance, so we'll use them. + planning_subtrees = list( + /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/basic_melee_attack_subtree/opportunistic, // Trapped! Bite the person trapping them. + /datum/ai_planning_subtree/simple_find_nearest_target_to_flee, + /datum/ai_planning_subtree/flee_target, + /datum/ai_planning_subtree/ventcrawl_find_target/spiderling, + /datum/ai_planning_subtree/ventcrawl/spiderling, + /datum/ai_planning_subtree/random_speech/insect, + ) + +/datum/ai_planning_subtree/ventcrawl_find_target/spiderling + crawl_behavior = /datum/ai_behavior/find_ventcrawl_target/spiderling + +/datum/ai_behavior/find_ventcrawl_target/spiderling + action_cooldown = 20 SECONDS + +/datum/ai_planning_subtree/ventcrawl/spiderling + ventcrawl_finding_behavior = /datum/ai_behavior/find_and_set/ventcrawl/spiderling + +/datum/ai_behavior/find_and_set/ventcrawl/spiderling + searched_entry_types = list(/obj/machinery/atmospherics/unary/vent_pump) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress_terror.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress_terror.dm index 90c09fa1dd6..50c40db56d7 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress_terror.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress_terror.dm @@ -82,7 +82,7 @@ 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!") for(var/obj/structure/spider/eggcluster/terror_eggcluster/T in GLOB.ts_egg_list) qdel(T) - for(var/obj/structure/spider/spiderling/terror_spiderling/T in GLOB.ts_spiderling_list) + for(var/mob/living/basic/spiderling/terror_spiderling/T in GLOB.ts_spiderling_list) qdel(T) to_chat(src, "All Terror Spiders, except yourself, will die off shortly.") 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 3ff6a579a7a..f0e7c93a913 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 @@ -57,7 +57,7 @@ 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 + var/mob/living/basic/spiderling/terror_spiderling/L = thing if(L.stillborn) continue if(check_mine && L.spider_myqueen != src) 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 index 8727ebd8fe0..57135749d75 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/mother.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/mother.dm @@ -97,10 +97,9 @@ /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)) + for(var/mob/living/basic/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) @@ -111,10 +110,8 @@ /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 + for(var/mob/living/basic/spiderling/terror_spiderling/S in src) 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. @@ -136,6 +133,6 @@ desc = "This web is coated in pheromones which prevent spiderlings from passing it." /obj/structure/spider/terrorweb/mother/CanPass(atom/movable/mover, border_dir) - if(istype(mover, /obj/structure/spider/spiderling/terror_spiderling)) + if(istype(mover, /mob/living/basic/spiderling/terror_spiderling)) return FALSE return ..() diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen_terror.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen_terror.dm index a96be22ea2f..fc57aee0bc5 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen_terror.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen_terror.dm @@ -112,7 +112,7 @@ 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 + var/mob/living/basic/spiderling/terror_spiderling/T = thing if(T.spider_myqueen && T.spider_myqueen == src) qdel(T) return ..() 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 718874daf44..8cc352095dc 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 @@ -1,171 +1,3 @@ - -// -------------------------------------------------------------------------------- -// ----------------- TERROR SPIDERS: SPIDERLINGS (USED BY GREEN, WHITE, QUEEN AND MOTHER TYPES) -// -------------------------------------------------------------------------------- - -/obj/structure/spider/spiderling/terror_spiderling - desc = "A fast-moving tiny spider, prone to making aggressive hissing sounds. Hope it doesn't grow up." - var/stillborn = FALSE - var/mob/living/simple_animal/hostile/poison/terror_spider/queen/spider_myqueen = null - var/mob/living/simple_animal/hostile/poison/terror_spider/spider_mymother = null - var/goto_mother = FALSE - var/ventcrawl_chance = 30 // 30% every process(), assuming 33% wander does not trigger - var/immediate_ventcrawl = TRUE - var/list/enemies = list() - var/spider_awaymission = FALSE - var/frustration = 0 - var/debug_ai_choices = FALSE - var/movement_disabled = FALSE - -/obj/structure/spider/spiderling/terror_spiderling/Initialize(mapload) - . = ..() - GLOB.ts_spiderling_list += src - if(is_away_level(z)) - spider_awaymission = TRUE - AddComponent(/datum/component/event_tracker, EVENT_TERROR_SPIDERS) - -/obj/structure/spider/spiderling/terror_spiderling/Destroy() - GLOB.ts_spiderling_list -= src - for(var/obj/structure/spider/spiderling/terror_spiderling/S in view(7, src)) - S.immediate_ventcrawl = TRUE - return ..() - -/obj/structure/spider/spiderling/terror_spiderling/Bump(obj/O) - if(istype(O, /obj/structure/table)) - forceMove(O.loc) - . = ..() - -/obj/structure/spider/spiderling/terror_spiderling/proc/score_surroundings(atom/A = src) - var/safety_score = 0 - var/turf/T = get_turf(A) - for(var/mob/living/L in viewers(T)) - if(isterrorspider(L)) - if(L.stat == DEAD) - safety_score-- - else - safety_score++ - if(spider_mymother && L == spider_mymother) - safety_score++ - else if(L.stat != DEAD) - safety_score-- - if(debug_ai_choices) - debug_visual(T, safety_score, A) - return safety_score - -/obj/structure/spider/spiderling/terror_spiderling/proc/debug_visual(turf/T, score, atom/A) - // This proc exists to help debug why spiderlings are making the ventcrawl AI choices they do. - // It won't be called unless you set the spiderling's debug_ai_choices to true. - if(debug_ai_choices && istype(T)) - if(A == src) - if(score > 0) - new /obj/effect/temp_visual/heart(T) // heart symbol, I am safe here, protected by a friendly spider - else if(score == 0) - new /obj/effect/temp_visual/heal(T) // white "+" symbol, I am neutral here - else - new /obj/effect/temp_visual/at_shield(T) // octagon symbol, I am unsafe here, I need to flee - else - if(score > 0) - new /obj/effect/temp_visual/telekinesis(T) // blue sparks, this is a safe area, I want to go here - else if(score == 0) - new /obj/effect/temp_visual/revenant(T) // purple sparks, this is a neutral area, an acceptable choice - else - 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 = FALSE - entry_vent = null - else if(entry_vent) - if(get_dist(src, entry_vent) <= 1) - 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(!length(vents)) - entry_vent = null - return - var/obj/machinery/atmospherics/unary/vent_pump/exit_vent = pick(vents) - if(spider_mymother && (goto_mother || prob(10))) - for(var/obj/machinery/atmospherics/unary/vent_pump/v in view(5, spider_mymother)) - if(!v.welded) - exit_vent = v - goto_mother = FALSE - if(!stillborn) - var/current_safety_score = score_surroundings(src) - var/new_safety_score = score_surroundings(exit_vent) - if(new_safety_score < current_safety_score) - // Try to find an alternative. - exit_vent = pick(vents) - new_safety_score = score_surroundings(exit_vent) - if(new_safety_score < current_safety_score) - // No alternative safe vent could be found. Abort. - entry_vent = null - return - 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 - frustration++ - GLOB.move_manager.move_to(src, entry_vent, 1) - if(frustration > 2) - entry_vent = null - else if(prob(33)) - random_skitter() - else if(immediate_ventcrawl || prob(ventcrawl_chance)) - immediate_ventcrawl = FALSE - if(!stillborn && !goto_mother) - var/safety_score = score_surroundings(src) - if(safety_score > 0) - // This area seems safe (friendly spiders present). Do not leave this area. - return - for(var/obj/machinery/atmospherics/unary/vent_pump/v in view(7,src)) - if(!v.welded) - entry_vent = v - GLOB.move_manager.move_to(src, entry_vent, 1) - break - - - // -------------------------------------------------------------------------------- // ----------------- TERROR SPIDERS: EGGS (USED BY NURSE AND QUEEN TYPES) --------- // -------------------------------------------------------------------------------- @@ -228,7 +60,7 @@ if(amount_grown >= 100) var/num = spiderling_number for(var/i=0, i[owner] bursts open! Holy fuck!") owner.gib() @@ -85,7 +85,7 @@ /obj/item/organ/internal/body_egg/terror_eggs/proc/hatch_egg() var/infection_completed = FALSE - var/obj/structure/spider/spiderling/terror_spiderling/S = new(get_turf(owner)) + var/mob/living/basic/spiderling/terror_spiderling/S = new(get_turf(owner)) switch(eggs_hatched) if(0) // 1st spiderling S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/gray @@ -98,7 +98,6 @@ if(4) // 5th S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/green infection_completed = TRUE - S.immediate_ventcrawl = TRUE eggs_hatched++ to_chat(owner, "A strange prickling sensation moves across your skin... then suddenly the whole world seems to spin around you!") owner.Paralyse(20 SECONDS) diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index 53ed7f1358c..42cbf73e3bd 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi index 6d932d6f184..59cd7d6f592 100644 Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ diff --git a/paradise.dme b/paradise.dme index 5401a014f2d..4530a2b0d5d 100644 --- a/paradise.dme +++ b/paradise.dme @@ -2512,9 +2512,10 @@ #include "code\modules\mob\living\basic\hostile\killertomato.dm" #include "code\modules\mob\living\basic\hostile\pirate.dm" #include "code\modules\mob\living\basic\hostile\skeleton_mob.dm" +#include "code\modules\mob\living\basic\hostile\spiderlings.dm" +#include "code\modules\mob\living\basic\hostile\soviet.dm" #include "code\modules\mob\living\basic\hostile\tree.dm" #include "code\modules\mob\living\basic\hostile\viscerator.dm" -#include "code\modules\mob\living\basic\hostile\soviet.dm" #include "code\modules\mob\living\basic\hostile\vox_raiders.dm" #include "code\modules\mob\living\basic\hostile\alien\alien_mob_ai.dm" #include "code\modules\mob\living\basic\hostile\alien\alien_mob_drone.dm"