diff --git a/code/__DEFINES/ai/monsters.dm b/code/__DEFINES/ai/monsters.dm index a42a780bd58..25074998059 100644 --- a/code/__DEFINES/ai/monsters.dm +++ b/code/__DEFINES/ai/monsters.dm @@ -326,3 +326,7 @@ #define BB_TURTLE_FLORA_TARGET "turtle_flora_target" #define BB_GUNMIMIC_GUN_EMPTY "BB_GUNMIMIC_GUN_EMPTY" + +//snails +///snails retreat ability +#define BB_SNAIL_RETREAT_ABILITY "snail_retreat_ability" diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index fd3a962d7a5..6e16d0639ca 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -1493,4 +1493,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Demolition modifier when hitting this object is inverted (ie, 1 / demolition) #define TRAIT_INVERTED_DEMOLITION "demolition_inverted" +/// Trait given when we escape into our shell +#define TRAIT_SHELL_RETREATED "shell_retreated" // END TRAIT DEFINES diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 70f1c86195f..4f12cd32dfc 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -493,6 +493,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_SELF_AWARE" = TRAIT_SELF_AWARE, "TRAIT_SETTLER" = TRAIT_SETTLER, "TRAIT_SHAVED" = TRAIT_SHAVED, + "TRAIT_SHELL_RETREATED" = TRAIT_SHELL_RETREATED, "TRAIT_SHIFTY_EYES" = TRAIT_SHIFTY_EYES, "TRAIT_SHOCKIMMUNE" = TRAIT_SHOCKIMMUNE, "TRAIT_SIGHT_BYPASS" = TRAIT_SIGHT_BYPASS, diff --git a/code/controllers/subsystem/minor_mapping.dm b/code/controllers/subsystem/minor_mapping.dm index cdd4d66e695..93abdcc9d10 100644 --- a/code/controllers/subsystem/minor_mapping.dm +++ b/code/controllers/subsystem/minor_mapping.dm @@ -1,4 +1,3 @@ -#define PROB_MOUSE_SPAWN 98 #define PROB_SPIDER_REPLACEMENT 50 SUBSYSTEM_DEF(minor_mapping) @@ -8,6 +7,12 @@ SUBSYSTEM_DEF(minor_mapping) /datum/controller/subsystem/atoms, ) flags = SS_NO_FIRE + ///a list of vermin we pick from to spawn. + var/list/vermin_chances = list( + /mob/living/basic/mouse = 80, + /mob/living/basic/snail = 18, + /mob/living/basic/regal_rat/controlled = 2, + ) /datum/controller/subsystem/minor_mapping/Initialize() // This whole subsystem just introduces a lot of odd confounding variables into unit test situations, @@ -30,14 +35,14 @@ SUBSYSTEM_DEF(minor_mapping) continue to_spawn-- - if(HAS_TRAIT(SSstation, STATION_TRAIT_SPIDER_INFESTATION) && prob(PROB_SPIDER_REPLACEMENT)) - new /mob/living/basic/spider/maintenance(proposed_turf) - return - if (prob(PROB_MOUSE_SPAWN)) - new /mob/living/basic/mouse(proposed_turf) + var/picked_path + if(HAS_TRAIT(SSstation, STATION_TRAIT_SPIDER_INFESTATION) && prob(PROB_SPIDER_REPLACEMENT)) + picked_path = /mob/living/basic/spider/maintenance else - new /mob/living/basic/regal_rat/controlled(proposed_turf) + picked_path = pick_weight(vermin_chances) + + new picked_path(proposed_turf) /// Returns true if a mouse won't die if spawned on this turf /datum/controller/subsystem/minor_mapping/proc/valid_mouse_turf(turf/open/proposed_turf) @@ -91,5 +96,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/target_retaliate.dm b/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm index 042ccb2310c..775fd3367d1 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm @@ -56,6 +56,10 @@ enemies_list += potential_target if(!length(enemies_list)) + + if(existing_target) + controller.clear_blackboard_key(target_key) + return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED var/atom/new_target = pick_final_target(controller, enemies_list) diff --git a/code/game/objects/effects/spawners/random/trash.dm b/code/game/objects/effects/spawners/random/trash.dm index 96c4e09c108..d48b156a550 100644 --- a/code/game/objects/effects/spawners/random/trash.dm +++ b/code/game/objects/effects/spawners/random/trash.dm @@ -45,6 +45,7 @@ /obj/item/reagent_containers/cup/soda_cans/grey_bull = 1, /obj/effect/spawner/random/engineering/tool = 1, /mob/living/basic/mouse = 1, + /mob/living/basic/snail = 1, /obj/item/food/grown/cannabis = 1, /obj/item/reagent_containers/cup/rag = 1, /obj/effect/spawner/random/entertainment/drugs= 1, diff --git a/code/modules/events/vent_clog.dm b/code/modules/events/vent_clog.dm index bd990e98c34..93bc2fc900a 100644 --- a/code/modules/events/vent_clog.dm +++ b/code/modules/events/vent_clog.dm @@ -79,6 +79,7 @@ /mob/living/basic/cockroach, /mob/living/basic/spider/maintenance, /mob/living/basic/mouse, + /mob/living/basic/snail, ) return pick(mob_list) diff --git a/code/modules/experisci/experiment/experiments.dm b/code/modules/experisci/experiment/experiments.dm index 213a90a47ea..01fa0e88dba 100644 --- a/code/modules/experisci/experiment/experiments.dm +++ b/code/modules/experisci/experiment/experiments.dm @@ -32,7 +32,7 @@ description = "A scientist needs vermin to test on, use the cytology equipment to grow some of these simple critters!" total_requirement = 3 max_requirement_per_type = 2 - possible_types = list(/mob/living/basic/cockroach, /mob/living/basic/mouse) + possible_types = list(/mob/living/basic/cockroach, /mob/living/basic/mouse, /mob/living/basic/snail) /datum/experiment/scanning/random/cytology/medium name = "Advanced Cytology Scanning Experiment" diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 567d2c8962a..31144776055 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -59,6 +59,8 @@ var/being_pollinated = FALSE ///The light level on the tray tile var/light_level = 0 + ///our snail overlay, if any + var/obj/effect/overlay/vis_effect/snail/our_snail /obj/machinery/hydroponics/Initialize(mapload) //ALRIGHT YOU DEGENERATES. YOU HAD REAGENT HOLDERS FOR AT LEAST 4 YEARS AND NONE OF YOU MADE HYDROPONICS TRAYS HOLD NUTRIENT CHEMS INSTEAD OF USING "Points". @@ -212,6 +214,16 @@ . = ..() if(!QDELETED(src) && gone == myseed) set_seed(null, FALSE) + if(!istype(gone, /obj/item/clothing/head/mob_holder/snail)) + return + var/obj/item/clothing/head/mob_holder/snail_object = gone + if(snail_object.held_mob) + UnregisterSignal(snail_object.held_mob, list( + COMSIG_LIVING_DEATH, + COMSIG_MOVABLE_ATTEMPTED_MOVE, + )) + QDEL_NULL(our_snail) + /obj/machinery/hydroponics/constructable/attackby(obj/item/I, mob/living/user, list/modifiers) if (!user.combat_mode) @@ -313,6 +325,9 @@ /obj/machinery/hydroponics/process(seconds_per_tick) var/needs_update = FALSE // Checks if the icon needs updating so we don't redraw empty trays every time + if(!isnull(our_snail)) + handle_snail() + if(self_sustaining) if(powered()) adjust_waterlevel(rand(1,2) * seconds_per_tick * 0.5) @@ -646,6 +661,17 @@ /obj/machinery/hydroponics/proc/adjust_pestlevel(amt) set_pestlevel(clamp(pestlevel + amt, 0, MAX_TRAY_PESTS), FALSE) +/obj/machinery/hydroponics/proc/remove_snail(mob/source) + SIGNAL_HANDLER + + var/atom/movable/mob_holder = source.loc + mob_holder.forceMove(drop_location()) + +/obj/machinery/hydroponics/proc/handle_snail() + if(prob(15)) + our_snail.handle_animation() //our snail waddles throughout the tray + if(prob(5)) + adjust_weedlevel(-2) /** * Adjust Weeds. @@ -1110,11 +1136,17 @@ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN var/warning = tgui_alert(user, "Are you sure you wish to empty the tray's nutrient beaker?","Empty Tray Nutrients?", list("Yes", "No")) if(warning == "Yes" && user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - reagents.clear_reagents() - to_chat(user, span_warning("You empty [src]'s nutrient tank.")) + empty_tray(user) update_appearance() return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/machinery/hydroponics/proc/empty_tray(mob/user) + reagents.clear_reagents() + for(var/obj/item/clothing/head/mob_holder/snail/possible_snail in contents) + possible_snail.forceMove(drop_location()) + to_chat(user, span_warning("You empty [src]'s nutrient tank.")) + /** * Update Tray Proc * Handles plant harvesting on the tray side, by clearing the seed, names, description, and dead stat. @@ -1243,6 +1275,17 @@ plant_health = add_output_port("Plant Health", PORT_TYPE_NUMBER) reagents_level = add_output_port("Reagents Level", PORT_TYPE_NUMBER) +/obj/machinery/hydroponics/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) + . = ..() + if(!istype(arrived, /obj/item/clothing/head/mob_holder/snail)) + return + our_snail = new + vis_contents += our_snail + our_snail.layer = layer + 0.01 + var/obj/item/clothing/head/mob_holder/snail = arrived + RegisterSignals(snail.held_mob, list(COMSIG_MOVABLE_ATTEMPTED_MOVE, COMSIG_LIVING_DEATH), PROC_REF(remove_snail)) //rip + + /obj/item/circuit_component/hydroponics/register_usb_parent(atom/movable/parent) . = ..() if(istype(parent, /obj/machinery/hydroponics)) diff --git a/code/modules/hydroponics/snail_overlay.dm b/code/modules/hydroponics/snail_overlay.dm new file mode 100644 index 00000000000..39baa290cfc --- /dev/null +++ b/code/modules/hydroponics/snail_overlay.dm @@ -0,0 +1,22 @@ +#define SNAIL_MOVEMENT_DISTANCE 5 +#define SNAIL_MOVEMENT_TIME 10 SECONDS + +/obj/effect/overlay/vis_effect/snail + name = "snail" + vis_flags = VIS_INHERIT_PLANE + icon = 'icons/obj/service/hydroponics/equipment.dmi' + icon_state = "snail_hydrotray" + ///are we currently walking? + var/is_waddling = FALSE + +/obj/effect/overlay/vis_effect/snail/proc/handle_animation() + if(is_waddling) + return + is_waddling = TRUE + var/movement_direction = pixel_x >= 0 ? -1 : 1 + transform = transform.Scale(-1, 1) //face the other direction + animate(src, pixel_x = movement_direction * SNAIL_MOVEMENT_DISTANCE, time = SNAIL_MOVEMENT_TIME) + addtimer(VARSET_CALLBACK(src, is_waddling, FALSE), SNAIL_MOVEMENT_TIME) + +#undef SNAIL_MOVEMENT_DISTANCE +#undef SNAIL_MOVEMENT_TIME diff --git a/code/modules/mob/living/basic/snails/snail.dm b/code/modules/mob/living/basic/snails/snail.dm new file mode 100644 index 00000000000..c1e6ffc8e73 --- /dev/null +++ b/code/modules/mob/living/basic/snails/snail.dm @@ -0,0 +1,104 @@ +/mob/living/basic/snail + name = "snail" + desc = "Is petting this thing sanitary?" + icon_state = "snail" + icon_living = "snail" + icon_dead = "snail_dead" + base_icon_state = "snail" + held_state = "snail" + head_icon = 'icons/mob/clothing/head/pets_head.dmi' + icon = 'icons/mob/simple/pets.dmi' + butcher_results = list(/obj/item/food/meat/slab/bugmeat = 1) + mob_biotypes = MOB_ORGANIC + health = 30 + maxHealth = 30 + speed = 6 + verb_say = "gurgles" + verb_ask = "gurgles curiously" + can_be_held = TRUE + verb_exclaim = "gurgles loudly" + verb_yell = "gurgles loudly" + worn_slot_flags = ITEM_SLOT_HEAD + faction = list(FACTION_NEUTRAL, FACTION_MAINT_CREATURES) + ai_controller = /datum/ai_controller/basic_controller/snail + +/mob/living/basic/snail/Initialize(mapload) + . = ..() + var/static/list/loc_connections = list(COMSIG_ATOM_ENTERED = PROC_REF(on_entered)) + AddElement(/datum/element/connect_loc, loc_connections) + var/static/list/eatable_food = list( + /obj/item/food/grown, + /obj/item/food/appleslice, + ) + + var/static/list/innate_actions = list( + /datum/action/cooldown/mob_cooldown/shell_retreat = BB_SNAIL_RETREAT_ABILITY, + ) + + grant_actions_by_list(innate_actions) + AddElement(/datum/element/ai_retaliate) + ai_controller.set_blackboard_key(BB_BASIC_FOODS, typecacheof(eatable_food)) + AddElement(/datum/element/basic_eating, food_types = eatable_food) + create_reagents(100, REAGENT_HOLDER_ALIVE) + RegisterSignal(reagents, COMSIG_REAGENTS_HOLDER_UPDATED, PROC_REF(on_reagents_update)) + +/mob/living/basic/snail/proc/on_entered(datum/source, obj/effect/decal/cleanable/food/salt/potential_salt) + SIGNAL_HANDLER + if(istype(potential_salt)) + on_salt_exposure() //immediately perish + +/mob/living/basic/snail/proc/on_reagents_update(datum/source) + SIGNAL_HANDLER + if(reagents.has_reagent(/datum/reagent/consumable/salt)) + on_salt_exposure() + +/mob/living/basic/snail/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change) + . = ..() + if(!isturf(loc)) + return + if(locate(/obj/effect/decal/cleanable/food/salt) in loc.contents) + on_salt_exposure() + +/mob/living/basic/snail/proc/on_salt_exposure() + if(stat == DEAD) + return + visible_message( + span_danger("[src] shows a strong reaction after tasting some salt!"), + span_userdanger("You show a strong reaction after tasting some salt."), + ) + apply_damage(500) //ouch + + +/mob/living/basic/snail/mob_pickup(mob/living/user) + var/obj/item/clothing/head/mob_holder/snail/holder = new(get_turf(src), src, held_state, head_icon, held_lh, held_rh, worn_slot_flags) + var/display_message = "[user] [HAS_TRAIT(src, TRAIT_MOVE_FLOATING) ? "scoops up [src]" : "peels [src] off the ground"]!" + user.visible_message(span_warning(display_message)) + user.put_in_hands(holder) + + +/mob/living/basic/snail/update_icon_state() + if(stat != DEAD) + icon_state = HAS_TRAIT(src, TRAIT_SHELL_RETREATED) ? "[base_icon_state]_shell" : "[base_icon_state][(faction.Find(FACTION_RAT)) ? "_maints" : ""]" + return ..() + +///snail's custom holder object +/obj/item/clothing/head/mob_holder/snail + +/obj/item/clothing/head/mob_holder/snail/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(!istype(interacting_with, /obj/machinery/hydroponics)) + return NONE + + . = ITEM_INTERACT_BLOCKING + if(held_mob.stat == DEAD) + user.balloon_alert(user, "it's dead!") + return + + if(locate(type) in interacting_with) + user.balloon_alert(user, "already has snail!") + return + + if(!do_after(user, 2 SECONDS, interacting_with)) + return + + forceMove(interacting_with) + return ITEM_INTERACT_SUCCESS diff --git a/code/modules/mob/living/basic/snails/snail_ability.dm b/code/modules/mob/living/basic/snails/snail_ability.dm new file mode 100644 index 00000000000..7d59f00cce4 --- /dev/null +++ b/code/modules/mob/living/basic/snails/snail_ability.dm @@ -0,0 +1,31 @@ +/datum/action/cooldown/mob_cooldown/shell_retreat + name = "Shell Retreat" + desc = "Retreat to your shell!" + cooldown_time = 5 SECONDS + click_to_activate = FALSE + button_icon = 'icons/mob/simple/pets.dmi' + button_icon_state = "snail_shell" + +/datum/action/cooldown/mob_cooldown/shell_retreat/Activate(atom/target) + . = ..() + HAS_TRAIT(owner, TRAIT_SHELL_RETREATED) ? unretreat_from_shell() : retreat_into_shell() + +/datum/action/cooldown/mob_cooldown/shell_retreat/proc/unretreat_from_shell() + SIGNAL_HANDLER + + owner.visible_message( + span_danger("[owner] slowly pops its head out of its shell!"), + span_userdanger("You pop your head out of your shell."), + ) + REMOVE_TRAIT(owner, TRAIT_SHELL_RETREATED, REF(src)) + UnregisterSignal(owner, list(COMSIG_MOVABLE_ATTEMPTED_MOVE, COMSIG_LIVING_DEATH)) + owner.update_appearance(UPDATE_ICON_STATE) + +/datum/action/cooldown/mob_cooldown/shell_retreat/proc/retreat_into_shell() + owner.visible_message( + span_danger("[owner] quickly escapes into its shell!"), + span_userdanger("You hide in your shell.."), + ) + RegisterSignals(owner, list(COMSIG_LIVING_DEATH, COMSIG_MOVABLE_ATTEMPTED_MOVE), PROC_REF(unretreat_from_shell)) + ADD_TRAIT(owner, TRAIT_SHELL_RETREATED, REF(src)) + owner.update_appearance(UPDATE_ICON_STATE) diff --git a/code/modules/mob/living/basic/snails/snail_ai.dm b/code/modules/mob/living/basic/snails/snail_ai.dm new file mode 100644 index 00000000000..07e81d6f23b --- /dev/null +++ b/code/modules/mob/living/basic/snails/snail_ai.dm @@ -0,0 +1,67 @@ +/datum/ai_controller/basic_controller/snail + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee, + /datum/ai_planning_subtree/use_mob_ability/snail_retreat, + /datum/ai_planning_subtree/find_food, + /datum/ai_planning_subtree/find_and_hunt_target/snail_people, + ) + +/datum/ai_planning_subtree/find_and_hunt_target/snail_people + target_key = BB_LOW_PRIORITY_HUNTING_TARGET + finding_behavior = /datum/ai_behavior/find_hunt_target/snail_people + hunting_behavior = /datum/ai_behavior/hunt_target/snail_people + hunt_targets = list( + /mob/living/carbon, + ) + hunt_range = 5 + hunt_chance = 45 + +/datum/ai_behavior/find_hunt_target/snail_people + action_cooldown = 1 MINUTES + behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION + +/datum/ai_behavior/find_hunt_target/snail_people/valid_dinner(mob/living/source, mob/living/carbon/potential_snail, radius, datum/ai_controller/controller, seconds_per_tick) + if(!istype(potential_snail)) + return FALSE + if(potential_snail.stat != CONSCIOUS) + return FALSE + if(!is_species(potential_snail, /datum/species/snail)) + return FALSE + return can_see(source, potential_snail, radius) + +/datum/ai_behavior/hunt_target/snail_people + always_reset_target = TRUE + +/datum/ai_behavior/hunt_target/snail_people/target_caught(mob/living/hunter, atom/hunted) + hunter.manual_emote("Celebrates around [hunted]!") + hunter.SpinAnimation(speed = 1, loops = 3) + +/datum/ai_planning_subtree/use_mob_ability/snail_retreat + ability_key = BB_SNAIL_RETREAT_ABILITY + finish_planning = TRUE + +/datum/ai_planning_subtree/use_mob_ability/snail_retreat/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/shell_retreated = HAS_TRAIT(controller.pawn, TRAIT_SHELL_RETREATED) + var/has_target = controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET) + if((has_target && shell_retreated) || (!has_target && !shell_retreated)) + return + return ..() + + +/datum/ai_controller/basic_controller/snail/trash + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, + ) + + planning_subtrees = list( + /datum/ai_planning_subtree/pet_planning, + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + ) diff --git a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm index 7f5abe60bbe..8ed312ce7b3 100644 --- a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm +++ b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm @@ -99,7 +99,7 @@ */ /datum/action/cooldown/mob_cooldown/riot/proc/riot() var/uplifted_mice = FALSE - for (var/mob/living/basic/mouse/nearby_mouse in oview(owner, range)) + for(var/mob/living/basic/mouse/nearby_mouse in oview(owner, range)) uplifted_mice = convert_mouse(nearby_mouse) || uplifted_mice if (uplifted_mice) owner.visible_message(span_warning("[owner] commands their army to action, mutating them into rats!")) @@ -120,6 +120,13 @@ owner.visible_message(span_warning("[owner] commands their army to action, mutating them into trash frogs!")) return + var/uplifted_snail = FALSE + for(var/mob/living/basic/snail/nearby_snail in oview(owner, range)) + uplifted_snail = convert_snail(nearby_snail, converted_check_list) || uplifted_snail + if(uplifted_snail) + owner.visible_message(span_warning("[owner] commands their army to action, mutating them into death snails!")) + return + var/rat_cap = CONFIG_GET(number/ratcap) if (LAZYLEN(SSmobs.cheeserats) >= rat_cap) to_chat(owner,span_warning("There's too many mice on this station to beckon a new one! Find them first!")) @@ -210,6 +217,27 @@ make_minion(nearby_frog, crazy_frog_desc, minion_commands) return TRUE +/datum/action/cooldown/mob_cooldown/riot/proc/convert_snail(mob/living/basic/snail/nearby_snail, list/converted_check_list) + // No need to convert when not on the same team. + if(faction_check(nearby_snail.faction, converted_check_list) || nearby_snail.stat == DEAD) + return FALSE + + + nearby_snail.icon_state = "[nearby_snail.base_icon_state]_maints" + nearby_snail.icon_living = "[nearby_snail.base_icon_state]_maints" + nearby_snail.icon_dead = "[nearby_snail.base_icon_state]_maints_dead" + nearby_snail.maxHealth += 10 + nearby_snail.health += 10 + nearby_snail.melee_damage_lower += 5 + nearby_snail.melee_damage_upper += 8 + nearby_snail.can_be_held = FALSE + nearby_snail.obj_damage += 8 + nearby_snail.fully_replace_character_name(nearby_snail.name, "trash [nearby_snail.name]") + nearby_snail.ai_controller = new /datum/ai_controller/basic_controller/snail/trash(nearby_snail) + make_minion(nearby_snail, " ...This one doesn't look as timid.", mouse_commands) + nearby_snail.update_appearance() + return TRUE + // Command you can give to a mouse to make it kill someone /datum/pet_command/attack/mouse speech_commands = list("attack", "sic", "kill", "cheese em") diff --git a/icons/mob/clothing/head/pets_head.dmi b/icons/mob/clothing/head/pets_head.dmi index 454bfca31ca..93ba284ec5c 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/pets.dmi b/icons/mob/simple/pets.dmi index 512a48e813b..ba1a98e3f95 100644 Binary files a/icons/mob/simple/pets.dmi and b/icons/mob/simple/pets.dmi differ diff --git a/icons/obj/service/hydroponics/equipment.dmi b/icons/obj/service/hydroponics/equipment.dmi index be9d9d4eeaf..d2939bde7ff 100644 Binary files a/icons/obj/service/hydroponics/equipment.dmi and b/icons/obj/service/hydroponics/equipment.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 16fdd0709de..060c0d285ac 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -4412,6 +4412,7 @@ #include "code\modules\hydroponics\plant_genes.dm" #include "code\modules\hydroponics\seed_extractor.dm" #include "code\modules\hydroponics\seeds.dm" +#include "code\modules\hydroponics\snail_overlay.dm" #include "code\modules\hydroponics\unique_plant_genes.dm" #include "code\modules\hydroponics\beekeeping\bee_smoker.dm" #include "code\modules\hydroponics\beekeeping\beebox.dm" @@ -5189,6 +5190,9 @@ #include "code\modules\mob\living\basic\slime\ai\controller.dm" #include "code\modules\mob\living\basic\slime\ai\pet_command.dm" #include "code\modules\mob\living\basic\slime\ai\subtrees.dm" +#include "code\modules\mob\living\basic\snails\snail.dm" +#include "code\modules\mob\living\basic\snails\snail_ability.dm" +#include "code\modules\mob\living\basic\snails\snail_ai.dm" #include "code\modules\mob\living\basic\space_fauna\ant.dm" #include "code\modules\mob\living\basic\space_fauna\cat_surgeon.dm" #include "code\modules\mob\living\basic\space_fauna\faithless.dm"