diff --git a/code/__DEFINES/ai.dm b/code/__DEFINES/ai.dm index f6d1768d725..78dde256424 100644 --- a/code/__DEFINES/ai.dm +++ b/code/__DEFINES/ai.dm @@ -221,6 +221,11 @@ ///some behaviors that check current_target also set this on deep crit mobs #define BB_BASIC_MOB_EXECUTION_TARGET "BB_basic_execution_target" +///Targetting keys for something to run away from, if you need to store this separately from current target +#define BB_BASIC_MOB_FLEE_TARGET "BB_basic_flee_target" +#define BB_BASIC_MOB_FLEE_TARGET_HIDING_LOCATION "BB_basic_flee_target_hiding_location" +#define BB_FLEE_TARGETTING_DATUM "flee_targetting_datum" + ///List of mobs who have damaged us #define BB_BASIC_MOB_RETALIATE_LIST "BB_basic_mob_shitlist" @@ -238,12 +243,18 @@ ///Current partner target #define BB_BABIES_TARGET "BB_babies_target" -///Bileworm AI keys +// Bileworm AI keys #define BB_BILEWORM_SPEW_BILE "BB_bileworm_spew_bile" #define BB_BILEWORM_RESURFACE "BB_bileworm_resurface" #define BB_BILEWORM_DEVOUR "BB_bileworm_devour" -/// Fugu AI Keys +// Spider AI keys +/// Key where we store a turf to put webs on +#define BB_SPIDER_WEB_TARGET "BB_spider_web_target" +/// Key where we store the web-spinning ability +#define BB_SPIDER_WEB_ACTION "BB_spider_web_action" +// Fugu AI keys +/// Key where we store the inflating ability #define BB_FUGU_INFLATE "BB_fugu_inflate" diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 4ddf1d4b31f..98f0f3b3daa 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -940,6 +940,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define STATION_TRAIT_BIGGER_PODS "station_trait_bigger_pods" #define STATION_TRAIT_SMALLER_PODS "station_trait_smaller_pods" #define STATION_TRAIT_BIRTHDAY "station_trait_birthday" +#define STATION_TRAIT_SPIDER_INFESTATION "station_trait_spider_infestation" ///From the market_crash event #define MARKET_CRASH_EVENT_TRAIT "crashed_market_event" diff --git a/code/controllers/subsystem/minor_mapping.dm b/code/controllers/subsystem/minor_mapping.dm index 5b2c17cf802..73371932e04 100644 --- a/code/controllers/subsystem/minor_mapping.dm +++ b/code/controllers/subsystem/minor_mapping.dm @@ -1,4 +1,5 @@ #define PROB_MOUSE_SPAWN 98 +#define PROB_SPIDER_REPLACEMENT 50 SUBSYSTEM_DEF(minor_mapping) name = "Minor Mapping" @@ -13,15 +14,20 @@ SUBSYSTEM_DEF(minor_mapping) place_satchels() return SS_INIT_SUCCESS -/datum/controller/subsystem/minor_mapping/proc/trigger_migration(num_mice=10) +/// Spawns some critters on exposed wires, usually but not always mice +/datum/controller/subsystem/minor_mapping/proc/trigger_migration(to_spawn=10) var/list/exposed_wires = find_exposed_wires() var/turf/open/proposed_turf - while((num_mice > 0) && exposed_wires.len) + while((to_spawn > 0) && exposed_wires.len) proposed_turf = pick_n_take(exposed_wires) if (!valid_mouse_turf(proposed_turf)) continue - num_mice-- + to_spawn-- + if(HAS_TRAIT(SSstation, STATION_TRAIT_SPIDER_INFESTATION) && prob(PROB_SPIDER_REPLACEMENT)) + new /mob/living/basic/giant_spider/maintenance(proposed_turf) + return + if (prob(PROB_MOUSE_SPAWN)) new /mob/living/basic/mouse(proposed_turf) else @@ -74,3 +80,4 @@ SUBSYSTEM_DEF(minor_mapping) return shuffle(suitable) #undef PROB_MOUSE_SPAWN +#undef PROB_SPIDER_REPLACEMENT diff --git a/code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm index ef72743a5f5..f62bb5699c7 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm @@ -2,14 +2,24 @@ /datum/ai_planning_subtree/flee_target /// Behaviour to execute in order to flee var/flee_behaviour = /datum/ai_behavior/run_away_from_target + /// Blackboard key in which to store selected target + var/target_key = BB_BASIC_MOB_CURRENT_TARGET + /// Blackboard key in which to store selected target's hiding place + var/hiding_place_key = BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION /datum/ai_planning_subtree/flee_target/SelectBehaviors(datum/ai_controller/controller, delta_time) . = ..() if (!controller.blackboard[BB_BASIC_MOB_FLEEING]) return - var/datum/weakref/weak_target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] + var/datum/weakref/weak_target = controller.blackboard[target_key] var/atom/target = weak_target?.resolve() if(!target || QDELETED(target)) return - controller.queue_behavior(flee_behaviour, BB_BASIC_MOB_CURRENT_TARGET, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + controller.queue_behavior(flee_behaviour, target_key, hiding_place_key) return SUBTREE_RETURN_FINISH_PLANNING //we gotta get out of here. + +/// Try to escape from your current target, without performing any other actions. +/// Reads from some fleeing-specific targetting keys rather than the current mob target. +/datum/ai_planning_subtree/flee_target/from_flee_key + target_key = BB_BASIC_MOB_FLEE_TARGET + hiding_place_key = BB_BASIC_MOB_FLEE_TARGET_HIDING_LOCATION diff --git a/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm b/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm index ff92435765e..2fb4dc858f4 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm @@ -1,9 +1,23 @@ /// Sets the BB target to a mob which you can see and who has recently attacked you /datum/ai_planning_subtree/target_retaliate + /// Blackboard key which tells us how to select valid targets + var/targetting_datum_key = BB_TARGETTING_DATUM + /// Blackboard key in which to store selected target + var/target_key = BB_BASIC_MOB_CURRENT_TARGET + /// Blackboard key in which to store selected target's hiding place + var/hiding_place_key = BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION /datum/ai_planning_subtree/target_retaliate/SelectBehaviors(datum/ai_controller/controller, delta_time) . = ..() - controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list, BB_BASIC_MOB_RETALIATE_LIST, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list, BB_BASIC_MOB_RETALIATE_LIST, target_key, targetting_datum_key, hiding_place_key) + +/// Places a mob which you can see and who has recently attacked you into some 'run away from this' AI keys +/// Can use a different targetting datum than you use to select attack targets +/// Not required if fleeing is the only target behaviour or uses the same target datum +/datum/ai_planning_subtree/target_retaliate/to_flee + targetting_datum_key = BB_FLEE_TARGETTING_DATUM + target_key = BB_BASIC_MOB_FLEE_TARGET + hiding_place_key = BB_BASIC_MOB_FLEE_TARGET_HIDING_LOCATION /** * Picks a target from a provided list of atoms who have been pissing you off diff --git a/code/datums/ai/basic_mobs/targetting_datums/basic_targetting_datum.dm b/code/datums/ai/basic_mobs/targetting_datums/basic_targetting_datum.dm index db93c68a7e8..004f3d8f59b 100644 --- a/code/datums/ai/basic_mobs/targetting_datums/basic_targetting_datum.dm +++ b/code/datums/ai/basic_mobs/targetting_datums/basic_targetting_datum.dm @@ -82,3 +82,31 @@ /datum/targetting_datum/basic/ignore_faction/faction_check(mob/living/living_mob, mob/living/the_target) return FALSE + +/// Subtype which searches for mobs of a size relative to ours +/datum/targetting_datum/basic/of_size + /// If true, we will return mobs which are smaller than us. If false, larger. + var/find_smaller = TRUE + /// If true, we will return mobs which are the same size as us. + var/inclusive = TRUE + +/datum/targetting_datum/basic/of_size/can_attack(mob/living/owner, atom/target) + if(!isliving(target)) + return FALSE + . = ..() + if(!.) + return FALSE + + var/mob/living/mob_target = target + if(inclusive && owner.mob_size == mob_target.mob_size) + return TRUE + if(owner.mob_size > mob_target.mob_size) + return find_smaller + return !find_smaller + +// This is just using the default values but the subtype makes it clearer +/datum/targetting_datum/basic/of_size/ours_or_smaller + +/datum/targetting_datum/basic/of_size/larger + find_smaller = FALSE + inclusive = FALSE diff --git a/code/datums/ai/idle_behaviors/idle_random_walk.dm b/code/datums/ai/idle_behaviors/idle_random_walk.dm index 69a236ba831..a8e3a81d128 100644 --- a/code/datums/ai/idle_behaviors/idle_random_walk.dm +++ b/code/datums/ai/idle_behaviors/idle_random_walk.dm @@ -5,6 +5,8 @@ /datum/idle_behavior/idle_random_walk/perform_idle_behavior(delta_time, datum/ai_controller/controller) . = ..() var/mob/living/living_pawn = controller.pawn + if(LAZYLEN(living_pawn.do_afters)) + return if(DT_PROB(walk_chance, delta_time) && (living_pawn.mobility_flags & MOBILITY_MOVE) && isturf(living_pawn.loc) && !living_pawn.pulledby) var/move_dir = pick(GLOB.alldirs) diff --git a/code/datums/elements/tiny_mob_hunter.dm b/code/datums/elements/tiny_mob_hunter.dm new file mode 100644 index 00000000000..b2a12e7e1ef --- /dev/null +++ b/code/datums/elements/tiny_mob_hunter.dm @@ -0,0 +1,31 @@ +/// Deals bonus brute damage to smaller mobs +/datum/element/tiny_mob_hunter + element_flags = ELEMENT_BESPOKE + argument_hash_start_idx = 2 + /// Will apply bonus to mobs this size or smaller + var/target_size + /// Additional damage to apply + var/bonus_damage + +/datum/element/tiny_mob_hunter/Attach(datum/target, target_size = MOB_SIZE_TINY, bonus_damage = 10) + . = ..() + if(!isanimal_or_basicmob(target)) // No post-attack signal for carbons, you can add one if you really want to put this on one + return ELEMENT_INCOMPATIBLE + + src.target_size = target_size + src.bonus_damage = bonus_damage + RegisterSignal(target, COMSIG_HOSTILE_POST_ATTACKINGTARGET, PROC_REF(on_attacked_target)) + +/datum/element/tiny_mob_hunter/Detach(datum/target) + UnregisterSignal(target, COMSIG_HOSTILE_POST_ATTACKINGTARGET) + return ..() + +/// Applies a bonus following the attack +/datum/element/tiny_mob_hunter/proc/on_attacked_target(mob/living/hunter, atom/target) + SIGNAL_HANDLER + if (!isliving(target)) + return + var/mob/living/prey = target + if (prey.mob_size > target_size) + return + prey.apply_damage(bonus_damage, BRUTE, hunter.zone_selected) diff --git a/code/datums/station_traits/neutral_traits.dm b/code/datums/station_traits/neutral_traits.dm index 10a9ca4412b..4ad5bc8f5f7 100644 --- a/code/datums/station_traits/neutral_traits.dm +++ b/code/datums/station_traits/neutral_traits.dm @@ -16,6 +16,13 @@ // This station trait modifies the atmosphere, which is too far past the time admins are able to revert it can_revert = FALSE +/datum/station_trait/spider_infestation + name = "Spider Infestation" + trait_type = STATION_TRAIT_NEUTRAL + weight = 5 + report_message = "We have introduced a natural countermeasure to reduce the number of rodents on board your station." + trait_to_give = STATION_TRAIT_SPIDER_INFESTATION + /datum/station_trait/unique_ai name = "Unique AI" trait_type = STATION_TRAIT_NEUTRAL diff --git a/code/modules/events/scrubber_clog.dm b/code/modules/events/scrubber_clog.dm index 4e982ff05b5..aaa80b58705 100644 --- a/code/modules/events/scrubber_clog.dm +++ b/code/modules/events/scrubber_clog.dm @@ -65,8 +65,9 @@ /datum/round_event/scrubber_clog/proc/get_mob() var/static/list/mob_list = list( - /mob/living/basic/mouse, /mob/living/basic/cockroach, + /mob/living/basic/giant_spider/maintenance, + /mob/living/basic/mouse, /mob/living/simple_animal/butterfly, ) return pick(mob_list) diff --git a/code/modules/mob/living/basic/space_fauna/giant_spider/giant_spider.dm b/code/modules/mob/living/basic/space_fauna/giant_spider/giant_spider.dm index 7cef5c6bc69..81fc08af989 100644 --- a/code/modules/mob/living/basic/space_fauna/giant_spider/giant_spider.dm +++ b/code/modules/mob/living/basic/space_fauna/giant_spider/giant_spider.dm @@ -73,6 +73,7 @@ var/datum/action/cooldown/lay_web/webbing = new web_type(src) webbing.webbing_time *= web_speed webbing.Grant(src) + ai_controller.blackboard[BB_SPIDER_WEB_ACTION] = WEAKREF(webbing) /mob/living/basic/giant_spider/Login() . = ..() diff --git a/code/modules/mob/living/basic/space_fauna/giant_spider/giant_spider_ai.dm b/code/modules/mob/living/basic/space_fauna/giant_spider/giant_spider_ai.dm index ca7b8cce21c..6838f3ba1ab 100644 --- a/code/modules/mob/living/basic/space_fauna/giant_spider/giant_spider_ai.dm +++ b/code/modules/mob/living/basic/space_fauna/giant_spider/giant_spider_ai.dm @@ -1,4 +1,4 @@ -/// For now, essentially just a Simple Hostile but room for expansion +/// Attacks people it can see, spins webs if it can't see anything to attack. /datum/ai_controller/basic_controller/giant_spider blackboard = list( BB_TARGETTING_DATUM = new /datum/targetting_datum/basic(), @@ -13,6 +13,8 @@ /datum/ai_planning_subtree/attack_obstacle_in_path, /datum/ai_planning_subtree/basic_melee_attack_subtree, /datum/ai_planning_subtree/random_speech/insect, // Space spiders are taxonomically insects not arachnids, don't DM me + /datum/ai_planning_subtree/find_unwebbed_turf, + /datum/ai_planning_subtree/spin_web, ) /// Giant spider which won't attack structures @@ -21,9 +23,11 @@ /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/basic_melee_attack_subtree, /datum/ai_planning_subtree/random_speech/insect, + /datum/ai_planning_subtree/find_unwebbed_turf, + /datum/ai_planning_subtree/spin_web, ) -/// Used by Araneus, who only attacks those who attack first +/// Used by Araneus, who only attacks those who attack first. He is house-trained and will not web up the HoS office. /datum/ai_controller/basic_controller/giant_spider/retaliate blackboard = list( BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/ignore_faction(), @@ -35,3 +39,22 @@ /datum/ai_planning_subtree/basic_melee_attack_subtree, /datum/ai_planning_subtree/random_speech/insect, ) + +/// Retaliates, hunts other maintenance creatures, runs away from larger attackers, and spins webs. +/datum/ai_controller/basic_controller/giant_spider/pest + blackboard = list( + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/of_size/ours_or_smaller(), // Hunt mobs our size + BB_FLEE_TARGETTING_DATUM = new /datum/targetting_datum/basic/of_size/larger(), // Run away from mobs bigger than we are + BB_BASIC_MOB_FLEEING = TRUE, + ) + idle_behavior = /datum/idle_behavior/idle_random_walk + + planning_subtrees = list( + /datum/ai_planning_subtree/target_retaliate/to_flee, + /datum/ai_planning_subtree/flee_target/from_flee_key, + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + /datum/ai_planning_subtree/random_speech/insect, + /datum/ai_planning_subtree/find_unwebbed_turf, + /datum/ai_planning_subtree/spin_web, + ) diff --git a/code/modules/mob/living/basic/space_fauna/giant_spider/spider_abilities/web.dm b/code/modules/mob/living/basic/space_fauna/giant_spider/spider_abilities/web.dm index 45e44a3e4f1..2ac43bb5487 100644 --- a/code/modules/mob/living/basic/space_fauna/giant_spider/spider_abilities/web.dm +++ b/code/modules/mob/living/basic/space_fauna/giant_spider/spider_abilities/web.dm @@ -55,7 +55,7 @@ if(do_after(owner, webbing_time, target = spider_turf, interaction_key = DOAFTER_SOURCE_SPIDER) && owner.loc == spider_turf) plant_web(spider_turf, web) else - owner.balloon_alert(owner, "interrupted!") + owner?.balloon_alert(owner, "interrupted!") // Null check because we might have been interrupted via being disintegrated build_all_button_icons() /// Creates a web in the current turf diff --git a/code/modules/mob/living/basic/space_fauna/giant_spider/spider_subtrees.dm b/code/modules/mob/living/basic/space_fauna/giant_spider/spider_subtrees.dm new file mode 100644 index 00000000000..dd11ceef92c --- /dev/null +++ b/code/modules/mob/living/basic/space_fauna/giant_spider/spider_subtrees.dm @@ -0,0 +1,91 @@ +/// Search for a nearby location to put webs on +/datum/ai_planning_subtree/find_unwebbed_turf + +/datum/ai_planning_subtree/find_unwebbed_turf/SelectBehaviors(datum/ai_controller/controller, delta_time) + controller.queue_behavior(/datum/ai_behavior/find_unwebbed_turf) + +/// Find an unwebbed nearby turf and store it +/datum/ai_behavior/find_unwebbed_turf + action_cooldown = 5 SECONDS + /// Where do we store the target data + var/target_key = BB_SPIDER_WEB_TARGET + /// How far do we look for unwebbed turfs? + var/scan_range = 3 + +/datum/ai_behavior/find_unwebbed_turf/perform(delta_time, datum/ai_controller/controller) + . = ..() + var/mob/living/spider = controller.pawn + var/datum/weakref/weak_target = controller.blackboard[target_key] + var/atom/current_target = weak_target?.resolve() + if (current_target && !(locate(/obj/structure/spider/stickyweb) in current_target)) + finish_action(controller, succeeded = FALSE) // Already got a target + return + + controller.blackboard[target_key] = null + var/turf/our_turf = get_turf(spider) + if (is_valid_web_turf(our_turf)) + controller.blackboard[target_key] = WEAKREF(our_turf) + finish_action(controller, succeeded = TRUE) + return + + var/list/potential_turfs = list() + for(var/turf/turf_in_view in oview(scan_range, our_turf)) + if (!is_valid_web_turf(turf_in_view)) + continue + potential_turfs += turf_in_view + + if (!length(potential_turfs)) + finish_action(controller, succeeded = FALSE) + return + + controller.blackboard[target_key] = WEAKREF(get_closest_atom(/turf/, potential_turfs, our_turf)) + finish_action(controller, succeeded = TRUE) + +/datum/ai_behavior/find_unwebbed_turf/proc/is_valid_web_turf(turf/target_turf, mob/living/spider) + if (locate(/obj/structure/spider/stickyweb) in target_turf) + return FALSE + return !target_turf.is_blocked_turf(source_atom = spider) + +/// Run the spin web behaviour if we have an ability to use for it +/datum/ai_planning_subtree/spin_web + /// Key where the web spinning action is stored + var/action_key = BB_SPIDER_WEB_ACTION + /// Key where the target turf is stored + var/target_key = BB_SPIDER_WEB_TARGET + +/datum/ai_planning_subtree/spin_web/SelectBehaviors(datum/ai_controller/controller, delta_time) + var/datum/weakref/weak_action = controller.blackboard[action_key] + var/datum/action/cooldown/using_action = weak_action?.resolve() + var/datum/weakref/weak_target = controller.blackboard[target_key] + var/turf/target_turf = weak_target?.resolve() + if (!using_action || !target_turf) + return + controller.queue_behavior(/datum/ai_behavior/spin_web, action_key, target_key) + return SUBTREE_RETURN_FINISH_PLANNING + +/// Move to an unwebbed nearby turf and web it up +/datum/ai_behavior/spin_web + action_cooldown = 15 SECONDS // We don't want them doing this too quickly + required_distance = 0 + behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION + +/datum/ai_behavior/spin_web/setup(datum/ai_controller/controller, action_key, target_key) + var/datum/weakref/weak_action = controller.blackboard[action_key] + var/datum/action/cooldown/web_action = weak_action?.resolve() + var/datum/weakref/weak_target = controller.blackboard[target_key] + var/turf/target_turf = weak_target?.resolve() + if (!web_action || !target_turf) + return FALSE + + set_movement_target(controller, target_turf) + return ..() + +/datum/ai_behavior/spin_web/perform(delta_time, datum/ai_controller/controller, action_key, target_key) + . = ..() + var/datum/weakref/weak_action = controller.blackboard[action_key] + var/datum/action/cooldown/web_action = weak_action?.resolve() + finish_action(controller, succeeded = web_action?.Trigger(), action_key = action_key, target_key = target_key) + +/datum/ai_behavior/spin_web/finish_action(datum/ai_controller/controller, succeeded, action_key, target_key) + controller.blackboard[target_key] = null + return ..() diff --git a/code/modules/mob/living/basic/space_fauna/giant_spider/spider_variants.dm b/code/modules/mob/living/basic/space_fauna/giant_spider/spider_variants.dm index 67493cd1aed..e82c04f221e 100644 --- a/code/modules/mob/living/basic/space_fauna/giant_spider/spider_variants.dm +++ b/code/modules/mob/living/basic/space_fauna/giant_spider/spider_variants.dm @@ -1,5 +1,5 @@ /** - * # Spider Hunter + * ### Spider Hunter * A subtype of the giant spider which is faster, has toxin injection, but less health and damage. * This spider is only slightly slower than a human. */ @@ -19,7 +19,7 @@ menu_description = "Fast spider variant specializing in catching running prey and toxin injection, but has less health and damage." /** - * # Spider Nurse + * ### Spider Nurse * * A subtype of the giant spider which specializes in support skills. * Nurses can place down webbing in a quarter of the time that other species can and can wrap other spiders' wounds, healing them. @@ -56,7 +56,7 @@ ) /** - * # Tarantula + * ### Tarantula * * A subtype of the giant spider which specializes in pure strength and staying power. * Is slowed down when not on webbing, but can lunge to throw off attackers and possibly to stun them. @@ -97,7 +97,7 @@ charge.Trigger(target = atom_target) /** - * # Spider Viper + * ### Spider Viper * * A subtype of the giant spider which specializes in speed and poison. * Injects a deadlier toxin than other spiders, moves extremely fast, but has a limited amount of health. @@ -120,7 +120,7 @@ menu_description = "Assassin spider variant with an unmatched speed and very deadly poison, but has very low amount of health and damage." /** - * # Spider Broodmother + * ### Spider Broodmother * * A subtype of the giant spider which is the crux of a spider horde, and the way which it grows. * Has very little offensive capabilities but can lay eggs at any time to create more basic spiders. @@ -161,7 +161,7 @@ not_hivemind_talk.Grant(src) /** - * # Giant Ice Spider + * ### Giant Ice Spider * * A subtype of the giant spider which is immune to temperature damage, unlike its normal counterpart. * Currently unused in the game unless spawned by admins. @@ -176,7 +176,7 @@ menu_description = "Versatile ice spider variant for frontline combat with high health and damage. Immune to temperature damage." /** - * # Ice Nurse Spider + * ### Ice Nurse Spider * * A temperature-proof nurse spider. Also unused. */ @@ -190,7 +190,7 @@ menu_description = "Support ice spider variant specializing in healing their brethren and placing webbings very swiftly, but has very low amount of health and deals low damage. Immune to temperature damage." /** - * # Ice Hunter Spider + * ### Ice Hunter Spider * * A temperature-proof hunter with chilling venom. Also unused. */ @@ -205,7 +205,7 @@ menu_description = "Fast ice spider variant specializing in catching running prey and frost oil injection, but has less health and damage. Immune to temperature damage." /** - * # Scrawny Hunter Spider + * ### Scrawny Hunter Spider * * A hunter spider that trades damage for health, unable to smash enviroments. * Used as a minor threat in abandoned places, such as areas in maintenance or a ruin. @@ -221,7 +221,7 @@ ai_controller = /datum/ai_controller/basic_controller/giant_spider/weak /** - * # Scrawny Tarantula + * ### Scrawny Tarantula * * A weaker version of the Tarantula, unable to smash enviroments. * Used as a moderately strong but slow threat in abandoned places, such as areas in maintenance or a ruin. @@ -237,7 +237,7 @@ ai_controller = /datum/ai_controller/basic_controller/giant_spider/weak /** - * # Scrawny Nurse Spider + * ### Scrawny Nurse Spider * * A weaker version of the nurse spider with reduced health, unable to smash enviroments. * Mainly used as a weak threat in abandoned places, such as areas in maintenance or a ruin. @@ -252,7 +252,7 @@ ai_controller = /datum/ai_controller/basic_controller/giant_spider/weak /** - * # Flesh Spider + * ### Flesh Spider * * A subtype of giant spider which only occurs from changelings. * Has the base stats of a hunter, but they can heal themselves and spin webs faster. @@ -291,7 +291,7 @@ return TRUE /** - * # Viper Spider (Wizard) + * ### Viper Spider (Wizard) * * A spider form for wizards. Has the viper spider's extreme speed and strong venom, with additional health and vent crawling abilities. */ @@ -306,7 +306,7 @@ ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) /** - * # Sergeant Araneus + * ### Sergeant Araneus * * This friendly arachnid hangs out in the HoS office on some space stations. Better trained than an average officer and does not attack except in self-defence. */ @@ -327,3 +327,42 @@ AddElement(/datum/element/pet_bonus, "chitters proudly!") AddElement(/datum/element/ai_retaliate) ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) + +/** + * ### Duct Spider + * + * A less giant spider which lives in the maintenance ducts and makes them annoying to traverse. + */ +/mob/living/basic/giant_spider/maintenance + name = "duct spider" + desc = "Nanotrasen's imported solution to mice, comes with its own problems." + icon_state = "maint_spider" + icon_living = "maint_spider" + icon_dead = "maint_spider_dead" + can_be_held = TRUE + mob_size = MOB_SIZE_TINY + held_w_class = WEIGHT_CLASS_TINY + worn_slot_flags = ITEM_SLOT_HEAD + head_icon = 'icons/mob/clothing/head/pets_head.dmi' + density = FALSE + pass_flags = PASSTABLE|PASSGRILLE|PASSMOB + gold_core_spawnable = FRIENDLY_SPAWN + maxHealth = 10 + health = 10 + melee_damage_lower = 1 + melee_damage_upper = 1 + speed = 0 + player_speed_modifier = 0 + web_speed = 0.25 + menu_description = "Fragile spider variant which is not good for much other than laying webs." + response_harm_continuous = "splats" + response_harm_simple = "splat" + ai_controller = /datum/ai_controller/basic_controller/giant_spider/pest + apply_spider_antag = FALSE + +/mob/living/basic/giant_spider/maintenance/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) + AddElement(/datum/element/web_walker, /datum/movespeed_modifier/duct_spider_web) + AddElement(/datum/element/ai_retaliate) + AddElement(/datum/element/tiny_mob_hunter) diff --git a/code/modules/movespeed/modifiers/mobs.dm b/code/modules/movespeed/modifiers/mobs.dm index 6eb1020d13e..b16b7174c45 100644 --- a/code/modules/movespeed/modifiers/mobs.dm +++ b/code/modules/movespeed/modifiers/mobs.dm @@ -97,6 +97,9 @@ /datum/movespeed_modifier/tarantula_web multiplicative_slowdown = 5 +/datum/movespeed_modifier/duct_spider_web + multiplicative_slowdown = 1 + /datum/movespeed_modifier/gravity blacklisted_movetypes = FLOATING variable = TRUE diff --git a/icons/mob/clothing/head/pets_head.dmi b/icons/mob/clothing/head/pets_head.dmi index 387f51d9b55..19ce9ec4675 100644 Binary files a/icons/mob/clothing/head/pets_head.dmi and b/icons/mob/clothing/head/pets_head.dmi differ diff --git a/icons/mob/simple/animal.dmi b/icons/mob/simple/animal.dmi index a0928224bc8..8875c1f27c6 100644 Binary files a/icons/mob/simple/animal.dmi and b/icons/mob/simple/animal.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 0305d1b02ea..4868dedf11d 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1270,6 +1270,7 @@ #include "code\datums\elements\swabbable.dm" #include "code\datums\elements\temporary_atom.dm" #include "code\datums\elements\tenacious.dm" +#include "code\datums\elements\tiny_mob_hunter.dm" #include "code\datums\elements\tool_flash.dm" #include "code\datums\elements\trait_loc.dm" #include "code\datums\elements\turf_transparency.dm" @@ -3873,6 +3874,7 @@ #include "code\modules\mob\living\basic\space_fauna\carp\megacarp.dm" #include "code\modules\mob\living\basic\space_fauna\giant_spider\giant_spider.dm" #include "code\modules\mob\living\basic\space_fauna\giant_spider\giant_spider_ai.dm" +#include "code\modules\mob\living\basic\space_fauna\giant_spider\spider_subtrees.dm" #include "code\modules\mob\living\basic\space_fauna\giant_spider\spider_variants.dm" #include "code\modules\mob\living\basic\space_fauna\giant_spider\spider_abilities\hivemind.dm" #include "code\modules\mob\living\basic\space_fauna\giant_spider\spider_abilities\lay_eggs.dm"