diff --git a/_maps/RandomZLevels/SnowCabin.dmm b/_maps/RandomZLevels/SnowCabin.dmm index 9f46c1ecd7f..8e479798798 100644 --- a/_maps/RandomZLevels/SnowCabin.dmm +++ b/_maps/RandomZLevels/SnowCabin.dmm @@ -2673,7 +2673,7 @@ /obj/effect/turf_decal/weather/snow/corner{ dir = 4 }, -/mob/living/simple_animal/hostile/bear/snow{ +/mob/living/basic/bear/snow{ desc = "It's a polar bear, in space, but not actually in space. It's actually on a planet. This is a planet."; melee_damage_lower = 10; melee_damage_upper = 20; @@ -2847,7 +2847,7 @@ /turf/open/floor/plating/snowed/snow_cabin, /area/awaymission/cabin/snowforest/sovietsurface) "qn" = ( -/mob/living/simple_animal/hostile/bear/snow{ +/mob/living/basic/bear/snow{ desc = "It's a polar bear, in space, but not actually in space. It's actually on a planet. This is a planet."; melee_damage_lower = 10; melee_damage_upper = 20; @@ -4586,13 +4586,11 @@ /turf/open/misc/asteroid/snow/snow_cabin, /area/awaymission/cabin/caves) "Ml" = ( -/mob/living/simple_animal/hostile/bear/russian{ +/mob/living/basic/bear/russian{ desc = "He'll hold the line against you!"; light_range = 3; melee_damage_upper = 25; - name = "Artyom"; - speak = list("Blyat!","Rawr!","GRR!","Growl!"); - wander = 0 + name = "Artyom" }, /turf/open/misc/asteroid/snow/snow_cabin{ floor_variance = 0; @@ -5457,13 +5455,12 @@ /turf/open/floor/plating/snowed/smoothed, /area/awaymission/cabin/caves) "Yg" = ( -/mob/living/simple_animal/hostile/bear/snow{ +/mob/living/basic/bear/snow{ desc = "It's a polar bear, in space, but not actually in space. It's actually on a planet. This is a planet."; melee_damage_lower = 10; melee_damage_upper = 20; name = "fat space polar bear"; - speed = 3; - wander = 0 + speed = 3 }, /obj/effect/light_emitter{ set_cap = 3; diff --git a/_maps/RandomZLevels/snowdin.dmm b/_maps/RandomZLevels/snowdin.dmm index e62c99dd6f5..163c27e181e 100644 --- a/_maps/RandomZLevels/snowdin.dmm +++ b/_maps/RandomZLevels/snowdin.dmm @@ -8032,7 +8032,7 @@ /turf/open/floor/iron, /area/awaymission/snowdin/post/minipost) "AG" = ( -/mob/living/simple_animal/hostile/bear/snow, +/mob/living/basic/bear/snow, /turf/open/floor/plating/snowed/smoothed, /area/awaymission/snowdin/post/minipost) "AH" = ( @@ -8795,7 +8795,7 @@ /area/awaymission/snowdin/cave) "DY" = ( /obj/effect/turf_decal/weather/snow, -/mob/living/simple_animal/hostile/bear/snow, +/mob/living/basic/bear/snow, /turf/open/floor/iron/dark/snowdin, /area/awaymission/snowdin/cave) "Ea" = ( @@ -10130,7 +10130,7 @@ set_cap = 3; set_luminosity = 6 }, -/mob/living/simple_animal/hostile/bear/snow, +/mob/living/basic/bear/snow, /turf/open/misc/asteroid/snow, /area/awaymission/snowdin/outside) "Li" = ( @@ -10147,7 +10147,7 @@ /turf/open/floor/plating/snowed/smoothed, /area/awaymission/snowdin/post/minipost) "Lm" = ( -/mob/living/simple_animal/hostile/bear/snow, +/mob/living/basic/bear/snow, /turf/open/misc/asteroid/snow{ floor_variance = 0; icon_state = "snow_dug"; @@ -10459,7 +10459,7 @@ /area/awaymission/snowdin/cave/cavern) "MV" = ( /obj/item/shard, -/mob/living/simple_animal/hostile/bear/snow, +/mob/living/basic/bear/snow, /turf/open/misc/asteroid/snow{ floor_variance = 0; icon_state = "snow_dug"; @@ -11424,7 +11424,7 @@ /turf/open/floor/iron, /area/awaymission/snowdin/post/garage) "Sa" = ( -/mob/living/simple_animal/hostile/bear/snow, +/mob/living/basic/bear/snow, /turf/open/misc/asteroid/snow, /area/awaymission/snowdin/cave) "Sb" = ( @@ -11675,7 +11675,7 @@ /turf/open/floor/plating, /area/awaymission/snowdin/post/cavern2) "Tf" = ( -/mob/living/simple_animal/hostile/bear/snow, +/mob/living/basic/bear/snow, /turf/open/misc/asteroid/snow, /area/awaymission/snowdin/outside) "Tk" = ( @@ -11983,7 +11983,7 @@ /area/awaymission/snowdin/post/mining_main/mechbay) "Vi" = ( /obj/effect/decal/cleanable/blood/old, -/mob/living/simple_animal/hostile/bear/snow, +/mob/living/basic/bear/snow, /turf/open/misc/asteroid/snow, /area/awaymission/snowdin/cave) "Vl" = ( diff --git a/_maps/map_files/Basketball/soviet_bear.dmm b/_maps/map_files/Basketball/soviet_bear.dmm index abfdd460b71..5bc653974aa 100644 --- a/_maps/map_files/Basketball/soviet_bear.dmm +++ b/_maps/map_files/Basketball/soviet_bear.dmm @@ -535,14 +535,14 @@ /turf/open/floor/iron/dark/small, /area/centcom/basketball) "Om" = ( -/mob/living/simple_animal/hostile/bear/fightpit, +/mob/living/basic/bear/fightpit, /obj/effect/turf_decal/stripes/line{ dir = 1 }, /turf/open/floor/engine, /area/centcom/basketball) "OB" = ( -/mob/living/simple_animal/hostile/bear/fightpit, +/mob/living/basic/bear/fightpit, /turf/open/floor/engine, /area/centcom/basketball) "PU" = ( diff --git a/_maps/shuttles/emergency_russiafightpit.dmm b/_maps/shuttles/emergency_russiafightpit.dmm index 3b36da78acb..020b44e6e14 100644 --- a/_maps/shuttles/emergency_russiafightpit.dmm +++ b/_maps/shuttles/emergency_russiafightpit.dmm @@ -195,7 +195,7 @@ /area/shuttle/escape) "aN" = ( /obj/effect/decal/cleanable/blood/old, -/mob/living/simple_animal/hostile/bear/fightpit, +/mob/living/basic/bear/fightpit, /turf/open/floor/engine, /area/shuttle/escape) "aO" = ( @@ -232,7 +232,7 @@ /area/shuttle/escape) "aV" = ( /obj/item/kitchen/fork, -/mob/living/simple_animal/hostile/bear/fightpit, +/mob/living/basic/bear/fightpit, /turf/open/floor/engine, /area/shuttle/escape) "aW" = ( @@ -490,7 +490,7 @@ /area/shuttle/escape) "wo" = ( /obj/effect/decal/cleanable/blood/old, -/mob/living/simple_animal/hostile/bear/fightpit, +/mob/living/basic/bear/fightpit, /obj/machinery/light/small/red/dim/directional/east, /turf/open/floor/engine, /area/shuttle/escape) diff --git a/_maps/shuttles/hunter_russian.dmm b/_maps/shuttles/hunter_russian.dmm index f5f1acd4af7..e82db9f5e29 100644 --- a/_maps/shuttles/hunter_russian.dmm +++ b/_maps/shuttles/hunter_russian.dmm @@ -342,7 +342,7 @@ desc = "A large wood and steel-reinforced crate."; name = "voytek's crate" }, -/mob/living/simple_animal/hostile/bear{ +/mob/living/basic/bear{ desc = "A very friendly yet still extremely menacing space-bear. Comrade until the end."; name = "Voytek" }, diff --git a/code/__DEFINES/ai.dm b/code/__DEFINES/ai.dm index f9416fc3e21..43dee41e98a 100644 --- a/code/__DEFINES/ai.dm +++ b/code/__DEFINES/ai.dm @@ -337,3 +337,9 @@ #define BB_CURRENT_HOME "BB_current_home" ///the hydro we will pollinate #define BB_TARGET_HYDRO "BB_target_hydro" + +///bear keys +///the hive with honey that we will steal from +#define BB_FOUND_HONEY "BB_found_honey" +///the tree that we will climb +#define BB_CLIMBED_TREE "BB_climbed_tree" diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index ba6f054ab99..ee5248f9faf 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -176,3 +176,6 @@ /// From /obj/structure/geyser/attackby() : (obj/structure/geyser/geyser) #define COMSIG_LIVING_DISCOVERED_GEYSER "living_discovered_geyser" + +/// From /datum/ai/behavior/climb_tree/perform() : (mob/living/basic/living_pawn) +#define COMSIG_LIVING_CLIMB_TREE "living_climb_tree" diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/climb_tree.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/climb_tree.dm new file mode 100644 index 00000000000..bb901066025 --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/climb_tree.dm @@ -0,0 +1,34 @@ +/datum/ai_behavior/find_and_set/valid_tree + +/datum/ai_behavior/find_and_set/valid_tree/search_tactic(datum/ai_controller/controller, locate_path, search_range) + var/list/valid_trees = list() + for (var/obj/structure/flora/tree/tree_target in oview(search_range, controller.pawn)) + if(istype(tree_target, /obj/structure/flora/tree/dead)) //no died trees + continue + valid_trees += tree_target + + if(valid_trees.len) + return pick(valid_trees) + +/datum/ai_behavior/climb_tree + behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH + +/datum/ai_behavior/climb_tree/setup(datum/ai_controller/controller, target_key) + . = ..() + var/atom/target = controller.blackboard[target_key] + if(QDELETED(target)) + return FALSE + + set_movement_target(controller, target) + +/datum/ai_behavior/climb_tree/perform(seconds_per_tick, datum/ai_controller/controller, target_key) + . = ..() + var/obj/structure/flora/target_tree = controller.blackboard[target_key] + var/mob/living/basic/living_pawn = controller.pawn + SEND_SIGNAL(living_pawn, COMSIG_LIVING_CLIMB_TREE, target_tree) + finish_action(controller, TRUE, target_key) + +/datum/ai_behavior/climb_tree/finish_action(datum/ai_controller/controller, succeeded, target_key) + . = ..() + if(succeeded) + controller.clear_blackboard_key(target_key) diff --git a/code/datums/ai/basic_mobs/basic_subtrees/climb_tree.dm b/code/datums/ai/basic_mobs/basic_subtrees/climb_tree.dm new file mode 100644 index 00000000000..6827f3eee99 --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_subtrees/climb_tree.dm @@ -0,0 +1,17 @@ +/datum/ai_planning_subtree/climb_trees + ///chance to climb a tree + var/climb_chance = 35 + +/datum/ai_planning_subtree/climb_trees/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + + if(!SPT_PROB(climb_chance, seconds_per_tick)) + return + + var/obj/structure/flora/tree/target = controller.blackboard[BB_CLIMBED_TREE] + + if(QDELETED(target)) + controller.queue_behavior(/datum/ai_behavior/find_and_set/valid_tree, BB_CLIMBED_TREE, /obj/structure/flora/tree) + return + + controller.queue_behavior(/datum/ai_behavior/climb_tree, BB_CLIMBED_TREE) + return SUBTREE_RETURN_FINISH_PLANNING diff --git a/code/datums/ai/basic_mobs/basic_subtrees/speech_subtree.dm b/code/datums/ai/basic_mobs/basic_subtrees/speech_subtree.dm index 06ad6b37033..3032632771d 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/speech_subtree.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/speech_subtree.dm @@ -194,3 +194,8 @@ speech_chance = 5 speak = list("Gah Gah!", "NOOT NOOT!", "NOOT!", "Noot", "noot", "Prah!", "Grah!") emote_hear = list("squawks", "gakkers") + +/datum/ai_planning_subtree/random_speech/bear + speech_chance = 5 + emote_hear = list("rawrs.","grumbles.","grawls.", "stomps!") + emote_see = list("stares ferociously.") diff --git a/code/datums/components/tree_climber.dm b/code/datums/components/tree_climber.dm new file mode 100644 index 00000000000..b3c70153c71 --- /dev/null +++ b/code/datums/components/tree_climber.dm @@ -0,0 +1,89 @@ +/* + * A component given to mobs that can climb trees + */ +/datum/component/tree_climber + ///the distance to climb up and down + var/climbing_distance = 20 + ///the tree we are on + var/obj/current_tree + +/datum/component/tree_climber/Initialize(climbing_distance = 20) + if(!isliving(parent)) + return COMPONENT_INCOMPATIBLE + src.climbing_distance = climbing_distance + +/datum/component/tree_climber/RegisterWithParent() + RegisterSignals(parent, list(COMSIG_HOSTILE_PRE_ATTACKINGTARGET, COMSIG_LIVING_CLIMB_TREE), PROC_REF(climb_tree)) + RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + +/datum/component/tree_climber/UnregisterFromParent() + UnregisterSignal(parent, list(COMSIG_HOSTILE_PRE_ATTACKINGTARGET, COMSIG_LIVING_CLIMB_TREE, COMSIG_ATOM_EXAMINE)) + +/datum/component/tree_climber/Destroy() + if(current_tree) + handle_climb_tree(parent, current_tree) //remove mob from tree and handle deletion of signals + return ..() + +/datum/component/tree_climber/proc/climb_tree(mob/living/source, atom/target) + SIGNAL_HANDLER + + if(!istype(target, /obj/structure/flora/tree)) + return + + if(!can_climb_tree(target)) //check if another animal is on the tree + to_chat(source, span_warning("[target] is blocked!")) + return COMPONENT_HOSTILE_NO_ATTACK + + handle_climb_tree(source, target) + + if(current_tree) + source.forceMove(get_turf(current_tree)) + return COMPONENT_HOSTILE_NO_ATTACK + + var/list/possible_drops = get_adjacent_open_turfs(target) + for(var/turf/droploc as anything in possible_drops) + if(!droploc.is_blocked_turf(exclude_mobs = TRUE)) + continue + possible_drops -= droploc + if(possible_drops.len) + source.forceMove(pick(possible_drops)) + return COMPONENT_HOSTILE_NO_ATTACK + +/datum/component/tree_climber/proc/on_examine(datum/source, mob/user, list/examine_text) + SIGNAL_HANDLER + if(current_tree) + examine_text += "It is clinging to [current_tree]!" + +/datum/component/tree_climber/proc/can_climb_tree(obj/structure/flora/tree/target) + if(current_tree) + return TRUE + var/turf/tree_turf = get_turf(target) + if(locate(/mob/living) in tree_turf.contents) + return FALSE + return TRUE + +/datum/component/tree_climber/proc/handle_climb_tree(mob/living/climber, obj/structure/target_tree) + var/offset = current_tree ? -(climbing_distance) : climbing_distance + animate(climber, pixel_y = climber.pixel_y + offset, time = 2) + climber.Stun(2 SECONDS, ignore_canstun = TRUE) + if(current_tree) + remove_tree_signals() + current_tree = null + return + + current_tree = target_tree + register_tree_signals() + +/datum/component/tree_climber/proc/remove_from_tree() + SIGNAL_HANDLER + + handle_climb_tree(parent, current_tree) + +/datum/component/tree_climber/proc/register_tree_signals() + RegisterSignal(parent, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(remove_from_tree)) + RegisterSignal(current_tree, COMSIG_PREQDELETED, PROC_REF(remove_from_tree)) + +/datum/component/tree_climber/proc/remove_tree_signals() + UnregisterSignal(parent, COMSIG_MOVABLE_PRE_MOVE) + UnregisterSignal(current_tree, COMSIG_PREQDELETED) + diff --git a/code/datums/memory/_memory.dm b/code/datums/memory/_memory.dm index 9c4ae2d905b..808be225ef9 100644 --- a/code/datums/memory/_memory.dm +++ b/code/datums/memory/_memory.dm @@ -245,6 +245,7 @@ var/static/list/something_pool = list( /mob/living/basic/bat, + /mob/living/basic/bear, /mob/living/basic/butterfly, /mob/living/basic/carp, /mob/living/basic/carp/magic, @@ -270,7 +271,6 @@ /mob/living/basic/stickman, /mob/living/basic/stickman/dog, /mob/living/simple_animal/hostile/asteroid/basilisk/watcher, - /mob/living/simple_animal/hostile/bear, /mob/living/simple_animal/hostile/blob/blobbernaut/independent, /mob/living/simple_animal/hostile/gorilla, /mob/living/simple_animal/hostile/megafauna/dragon/lesser, diff --git a/code/game/objects/items/bear_armor.dm b/code/game/objects/items/bear_armor.dm new file mode 100644 index 00000000000..a951648d3d0 --- /dev/null +++ b/code/game/objects/items/bear_armor.dm @@ -0,0 +1,27 @@ +/obj/item/bear_armor + name = "pile of bear armor" + desc = "A scattered pile of various shaped armor pieces fitted for a bear, some duct tape, and a nail filer. Crude instructions \ + are written on the back of one of the plates in russian. This seems like an awful idea." + icon = 'icons/obj/device.dmi' + icon_state = "bear_armor_upgrade" + +/obj/item/bear_armor/afterattack(atom/target, mob/user, proximity_flag) + . = ..() + if(!proximity_flag) + return + if(!istype(target, /mob/living/basic/bear)) + return + var/mob/living/basic/bear/bear_target = target + if(bear_target.armored) + to_chat(user, span_warning("[bear_target] has already been armored up!")) + return + bear_target.armored = TRUE + bear_target.maxHealth += 60 + bear_target.health += 60 + bear_target.armour_penetration += 20 + bear_target.melee_damage_lower += 3 + bear_target.melee_damage_upper += 5 + bear_target.wound_bonus += 5 + bear_target.update_icons() + to_chat(user, span_info("You strap the armor plating to [bear_target] and sharpen [bear_target.p_their()] claws with the nail filer. This was a great idea.")) + qdel(src) diff --git a/code/modules/events/shuttle_loan/shuttle_loan_datum.dm b/code/modules/events/shuttle_loan/shuttle_loan_datum.dm index 5d69995035c..a69867cbcdf 100644 --- a/code/modules/events/shuttle_loan/shuttle_loan_datum.dm +++ b/code/modules/events/shuttle_loan/shuttle_loan_datum.dm @@ -180,11 +180,11 @@ spawn_list.Add(/mob/living/basic/syndicate/russian) spawn_list.Add(/mob/living/basic/syndicate/russian/ranged) //drops a mateba - spawn_list.Add(/mob/living/simple_animal/hostile/bear/russian) + spawn_list.Add(/mob/living/basic/bear/russian) if(prob(75)) spawn_list.Add(/mob/living/basic/syndicate/russian) if(prob(50)) - spawn_list.Add(/mob/living/simple_animal/hostile/bear/russian) + spawn_list.Add(/mob/living/basic/bear/russian) /datum/shuttle_loan_situation/spider_gift sender = "CentCom Diplomatic Corps" diff --git a/code/modules/events/vent_clog.dm b/code/modules/events/vent_clog.dm index 5b72ba3ac8c..87e692a787e 100644 --- a/code/modules/events/vent_clog.dm +++ b/code/modules/events/vent_clog.dm @@ -287,12 +287,12 @@ /datum/round_event/vent_clog/strange/get_mob() var/static/list/mob_list = list( + /mob/living/basic/bear, /mob/living/basic/cockroach/glockroach/mobroach, /mob/living/basic/lightgeist, /mob/living/basic/mothroach, /mob/living/basic/mushroom, /mob/living/basic/viscerator, - /mob/living/simple_animal/hostile/bear, /mob/living/simple_animal/hostile/retaliate/goose, //Janitors HATE geese. /mob/living/simple_animal/pet/gondola, ) diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm index 99af904eb73..6db5a39764c 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm @@ -161,7 +161,7 @@ /datum/reagent/blood = 50, /datum/reagent/teslium = 1 //To shock the whole thing into life ) - result = /mob/living/simple_animal/hostile/bear/butter + result = /mob/living/basic/bear/butter category = CAT_MISCFOOD /datum/crafting_recipe/food/crab_rangoon diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/basic/space_fauna/bear/_bear.dm similarity index 56% rename from code/modules/mob/living/simple_animal/hostile/bear.dm rename to code/modules/mob/living/basic/space_fauna/bear/_bear.dm index ecd5a8e9b00..414f28a1e9a 100644 --- a/code/modules/mob/living/simple_animal/hostile/bear.dm +++ b/code/modules/mob/living/basic/space_fauna/bear/_bear.dm @@ -1,5 +1,5 @@ //Space bears! -/mob/living/simple_animal/hostile/bear +/mob/living/basic/bear name = "space bear" desc = "You don't need to be faster than a space bear, you just need to outrun your crewmates." icon_state = "bear" @@ -7,24 +7,19 @@ icon_dead = "bear_dead" icon_gib = "bear_gib" mob_biotypes = MOB_ORGANIC|MOB_BEAST - speak = list("RAWR!","Rawr!","GRR!","Growl!") - speak_emote = list("growls", "roars") - emote_hear = list("rawrs.","grumbles.","grawls.") - emote_taunt = list("stares ferociously", "stomps") - speak_chance = 1 - taunt_chance = 25 - turns_per_move = 5 butcher_results = list(/obj/item/food/meat/slab/bear = 5, /obj/item/clothing/head/costume/bearpelt = 1) + response_help_continuous = "pets" response_help_simple = "pet" response_disarm_continuous = "gently pushes aside" response_disarm_simple = "gently push aside" + maxHealth = 60 health = 60 speed = 0 obj_damage = 60 - melee_damage_lower = 15 // i know it's like half what it used to be, but bears cause bleeding like crazy now so it works out + melee_damage_lower = 15 melee_damage_upper = 15 wound_bonus = -5 bare_wound_bonus = 10 // BEAR wound bonus am i right @@ -36,26 +31,23 @@ friendly_verb_continuous = "bear hugs" friendly_verb_simple = "bear hug" - //Space bears aren't affected by cold. - atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minbodytemp = 0 - maxbodytemp = 1500 - faction = list(FACTION_RUSSIAN) - footstep_type = FOOTSTEP_MOB_CLAW - + habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) + minimum_survivable_temperature = TCMB + maximum_survivable_temperature = T0C + 1500 + ai_controller = /datum/ai_controller/basic_controller/bear + /// is the bear wearing a armor? var/armored = FALSE -/mob/living/simple_animal/hostile/bear/Initialize(mapload) +/mob/living/basic/bear/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT) - add_cell_sample() - -/mob/living/simple_animal/hostile/bear/add_cell_sample() + AddElement(/datum/element/ai_retaliate) + AddComponent(/datum/component/tree_climber, climbing_distance = 15) AddElement(/datum/element/swabable, CELL_LINE_TABLE_BEAR, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) -/mob/living/simple_animal/hostile/bear/Login() +/mob/living/basic/bear/Login() . = ..() if(!. || !client) return FALSE @@ -64,26 +56,37 @@ can_buckle = TRUE buckle_lying = 0 -/mob/living/simple_animal/hostile/bear/update_icons() +/mob/living/basic/bear/update_icons() ..() if(armored) add_overlay("armor_bear") +/mob/living/basic/bear/proc/extract_combs(obj/structure/beebox/hive) + if(!length(hive.honeycombs)) + return + var/obj/item/food/honeycomb/honey_food = pick_n_take(hive.honeycombs) + if(isnull(honey_food)) + return + honey_food.forceMove(get_turf(src)) + //SPACE BEARS! SQUEEEEEEEE~ OW! FUCK! IT BIT MY HAND OFF!! -/mob/living/simple_animal/hostile/bear/hudson +/mob/living/basic/bear/hudson name = "Hudson" gender = MALE desc = "Feared outlaw, this guy is one bad news bear." //I'm sorry... -/mob/living/simple_animal/hostile/bear/snow +/mob/living/basic/bear/snow name = "space polar bear" icon_state = "snowbear" icon_living = "snowbear" icon_dead = "snowbear_dead" desc = "It's a polar bear, in space, but not actually in space." - weather_immunities = list(TRAIT_SNOWSTORM_IMMUNE) -/mob/living/simple_animal/hostile/bear/russian +/mob/living/basic/bear/snow/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_SNOWSTORM_IMMUNE, INNATE_TRAIT) + +/mob/living/basic/bear/russian name = "combat bear" desc = "A ferocious brown bear decked out in armor plating, a red star with yellow outlining details the shoulder plating." icon_state = "combatbear" @@ -97,35 +100,10 @@ armour_penetration = 20 health = 120 maxHealth = 120 - armored = TRUE gold_core_spawnable = HOSTILE_SPAWN + armored = TRUE -/obj/item/bear_armor - name = "pile of bear armor" - desc = "A scattered pile of various shaped armor pieces fitted for a bear, some duct tape, and a nail filer. Crude instructions \ - are written on the back of one of the plates in russian. This seems like an awful idea." - icon = 'icons/obj/device.dmi' - icon_state = "bear_armor_upgrade" - -/obj/item/bear_armor/afterattack(atom/target, mob/user, proximity_flag) - . = ..() - if(istype(target, /mob/living/simple_animal/hostile/bear) && proximity_flag) - var/mob/living/simple_animal/hostile/bear/A = target - if(A.armored) - to_chat(user, span_warning("[A] has already been armored up!")) - return - A.armored = TRUE - A.maxHealth += 60 - A.health += 60 - A.armour_penetration += 20 - A.melee_damage_lower += 3 - A.melee_damage_upper += 5 - A.wound_bonus += 5 - A.update_icons() - to_chat(user, span_info("You strap the armor plating to [A] and sharpen [A.p_their()] claws with the nail filer. This was a great idea.")) - qdel(src) - -/mob/living/simple_animal/hostile/bear/butter //The mighty companion to Cak. Several functions used from it. +/mob/living/basic/bear/butter //The mighty companion to Cak. Several functions used from it. name = "Terrygold" icon_state = "butterbear" icon_living = "butterbear" @@ -147,23 +125,23 @@ attack_verb_simple = "slap" attack_verb_continuous = "slaps" -/mob/living/simple_animal/hostile/bear/butter/add_cell_sample() - return //You cannot grow a real bear from butter. +/mob/living/basic/bear/butter/Initialize(mapload) + . = ..() -/mob/living/simple_animal/hostile/bear/butter/Life(seconds_per_tick = SSMOBS_DT, times_fired) //Heals butter bear really fast when he takes damage. - if(stat) - return - if(health < maxHealth) - heal_overall_damage(5 * seconds_per_tick) //Fast life regen, makes it hard for you to get eaten to death. + AddComponent(/datum/component/regenerator,\ + regeneration_delay = 1 SECONDS,\ + health_per_second = 5,\ + outline_colour = COLOR_YELLOW,\ + ) -/mob/living/simple_animal/hostile/bear/butter/attack_hand(mob/living/user, list/modifiers) //Borrowed code from Cak, feeds people if they hit you. More nutriment but less vitamin to represent BUTTER. - ..() +/mob/living/basic/bear/butter/attack_hand(mob/living/user, list/modifiers) //Borrowed code from Cak, feeds people if they hit you. More nutriment but less vitamin to represent BUTTER. + . = ..() if(user.combat_mode && user.reagents && !stat) user.reagents.add_reagent(/datum/reagent/consumable/nutriment, 1) user.reagents.add_reagent(/datum/reagent/consumable/nutriment/vitamin, 0.1) -/mob/living/simple_animal/hostile/bear/butter/CheckParts(list/parts) //Borrowed code from Cak, allows the brain used to actually control the bear. - ..() +/mob/living/basic/bear/butter/CheckParts(list/parts) //Borrowed code from Cak, allows the brain used to actually control the bear. + . = ..() var/obj/item/organ/internal/brain/candidate = locate(/obj/item/organ/internal/brain) in contents if(!candidate || !candidate.brainmob || !candidate.brainmob.mind) return @@ -179,11 +157,14 @@ to_chat(src, span_notice("Your name is now [new_name]!")) name = new_name -/mob/living/simple_animal/hostile/bear/butter/AttackingTarget() //Makes the butter bear's attacks against vertical targets slip said targets +/mob/living/basic/bear/butter/UnarmedAttack(atom/target, proximity_flag, list/modifiers) //Makes the butter bear's attacks against vertical targets slip said targets . = ..() - if(isliving(target)) //we don't check for . here, since attack_animal() (and thus AttackingTarget()) will return false if your damage dealt is 0 - var/mob/living/L = target - if((L.body_position == STANDING_UP)) - L.Knockdown(20) - playsound(loc, 'sound/misc/slip.ogg', 15) - L.visible_message(span_danger("[L] slips on [src]'s butter!")) + if(!. || !isliving(target)) + return + var/mob/living/victim = target + if((victim.body_position != STANDING_UP)) + return + victim.Knockdown(20) + playsound(loc, 'sound/misc/slip.ogg', 15) + victim.visible_message(span_danger("[victim] slips on [src]'s butter!")) + diff --git a/code/modules/mob/living/basic/space_fauna/bear/bear_ai_behavior.dm b/code/modules/mob/living/basic/space_fauna/bear/bear_ai_behavior.dm new file mode 100644 index 00000000000..6e716ddf411 --- /dev/null +++ b/code/modules/mob/living/basic/space_fauna/bear/bear_ai_behavior.dm @@ -0,0 +1,30 @@ +/datum/ai_behavior/basic_melee_attack/bear + action_cooldown = 2 SECONDS + +/datum/ai_behavior/find_hunt_target/find_hive + +/datum/ai_behavior/find_hunt_target/find_hive/valid_dinner(mob/living/source, obj/structure/beebox/hive, radius) + if(!length(hive.honeycombs)) + return FALSE + return can_see(source, hive, radius) + +/datum/ai_behavior/hunt_target/find_hive + always_reset_target = TRUE + +/datum/ai_behavior/hunt_target/find_hive/target_caught(mob/living/hunter, obj/structure/beebox/hive_target) + var/datum/callback/callback = CALLBACK(hunter, TYPE_PROC_REF(/mob/living/basic/bear, extract_combs), hive_target) + callback.Invoke() + +/datum/ai_behavior/find_hunt_target/find_honeycomb + +/datum/ai_behavior/find_hunt_target/find_honeycomb/setup(datum/ai_controller/controller, ability_key, target_key) + var/mob/living/living_pawn = controller.pawn + if(living_pawn.pulling) //we already pulling a honey + return FALSE + return TRUE + +/datum/ai_behavior/hunt_target/find_honeycomb + always_reset_target = TRUE + +/datum/ai_behavior/hunt_target/find_honeycomb/target_caught(mob/living/hunter, obj/item/food/honeycomb/food_target) + hunter.start_pulling(food_target) diff --git a/code/modules/mob/living/basic/space_fauna/bear/bear_ai_subtree.dm b/code/modules/mob/living/basic/space_fauna/bear/bear_ai_subtree.dm new file mode 100644 index 00000000000..244c600d89f --- /dev/null +++ b/code/modules/mob/living/basic/space_fauna/bear/bear_ai_subtree.dm @@ -0,0 +1,33 @@ +/datum/ai_controller/basic_controller/bear + blackboard = list( + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic, + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/basic_melee_attack_subtree/bear, + /datum/ai_planning_subtree/climb_trees, + /datum/ai_planning_subtree/find_and_hunt_target/find_hive, + /datum/ai_planning_subtree/find_and_hunt_target/find_honeycomb, + /datum/ai_planning_subtree/random_speech/bear, + ) + +/datum/ai_planning_subtree/basic_melee_attack_subtree/bear + melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/bear + +/datum/ai_planning_subtree/find_and_hunt_target/find_hive + target_key = BB_FOUND_HONEY + hunting_behavior = /datum/ai_behavior/hunt_target/find_hive + finding_behavior = /datum/ai_behavior/find_hunt_target/find_hive + hunt_targets = list(/obj/structure/beebox) + hunt_range = 10 + +/datum/ai_planning_subtree/find_and_hunt_target/find_honeycomb + target_key = BB_LOW_PRIORITY_HUNTING_TARGET + hunting_behavior = /datum/ai_behavior/hunt_target/find_honeycomb + finding_behavior = /datum/ai_behavior/find_hunt_target/find_honeycomb + hunt_targets = list(/obj/item/food/honeycomb) + hunt_range = 10 diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 5d719891da8..0673411d395 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1408,6 +1408,7 @@ if(WABBAJACK_ANIMAL) var/picked_animal = pick( /mob/living/basic/bat, + /mob/living/basic/bear, /mob/living/basic/butterfly, /mob/living/basic/carp, /mob/living/basic/carp/magic, @@ -1432,7 +1433,6 @@ /mob/living/basic/stickman, /mob/living/basic/stickman/dog, /mob/living/simple_animal/hostile/asteroid/basilisk/watcher, - /mob/living/simple_animal/hostile/bear, /mob/living/simple_animal/hostile/blob/blobbernaut/independent, /mob/living/simple_animal/hostile/gorilla, /mob/living/simple_animal/hostile/megafauna/dragon/lesser, diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 6ced60af0d3..56ff1cfae2a 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -390,7 +390,7 @@ return TRUE if(ispath(MP, /mob/living/basic/mouse)) return TRUE - if(ispath(MP, /mob/living/simple_animal/hostile/bear)) + if(ispath(MP, /mob/living/basic/bear)) return TRUE if(ispath(MP, /mob/living/simple_animal/parrot)) return TRUE //Parrots are no longer unfinished! -Nodrak diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm index bdd8c1713dd..155985ad3a0 100644 --- a/code/modules/research/experimentor.dm +++ b/code/modules/research/experimentor.dm @@ -639,6 +639,7 @@ to_chat(user, message) var/static/list/valid_animals = list( + /mob/living/basic/bear, /mob/living/basic/bee, /mob/living/basic/butterfly, /mob/living/basic/carp, @@ -648,7 +649,6 @@ /mob/living/basic/pet/dog/corgi, /mob/living/basic/pet/dog/pug, /mob/living/basic/pet/fox, - /mob/living/simple_animal/hostile/bear, /mob/living/simple_animal/parrot/natural, /mob/living/simple_animal/pet/cat, ) diff --git a/code/modules/research/xenobiology/vatgrowing/samples/cell_lines/common.dm b/code/modules/research/xenobiology/vatgrowing/samples/cell_lines/common.dm index 1e0cedc5bfa..1e78c4dbfca 100644 --- a/code/modules/research/xenobiology/vatgrowing/samples/cell_lines/common.dm +++ b/code/modules/research/xenobiology/vatgrowing/samples/cell_lines/common.dm @@ -167,7 +167,7 @@ /datum/reagent/medicine/insulin = -2) //depletes hunny. virus_suspectibility = 2 - resulting_atoms = list(/mob/living/simple_animal/hostile/bear = 1) + resulting_atoms = list(/mob/living/basic/bear = 1) /datum/micro_organism/cell_line/carp desc = "Cyprinid cells" diff --git a/code/modules/shuttle/special.dm b/code/modules/shuttle/special.dm index bcb6984777e..5c1e21c56fb 100644 --- a/code/modules/shuttle/special.dm +++ b/code/modules/shuttle/special.dm @@ -411,7 +411,7 @@ alarm_beep() return ..() -/mob/living/simple_animal/hostile/bear/fightpit +/mob/living/basic/bear/fightpit name = "fight pit bear" desc = "This bear's trained through ancient Russian secrets to fear the walls of its glass prison." environment_smash = ENVIRONMENT_SMASH_NONE diff --git a/code/modules/unit_tests/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm index b14f37fcade..dd9fdba2f09 100644 --- a/code/modules/unit_tests/simple_animal_freeze.dm +++ b/code/modules/unit_tests/simple_animal_freeze.dm @@ -90,12 +90,6 @@ /mob/living/simple_animal/hostile/asteroid/polarbear, /mob/living/simple_animal/hostile/asteroid/polarbear/lesser, /mob/living/simple_animal/hostile/asteroid/wolf, - /mob/living/simple_animal/hostile/bear, - /mob/living/simple_animal/hostile/bear/butter, - /mob/living/simple_animal/hostile/bear/fightpit, - /mob/living/simple_animal/hostile/bear/hudson, - /mob/living/simple_animal/hostile/bear/russian, - /mob/living/simple_animal/hostile/bear/snow, /mob/living/simple_animal/hostile/big_legion, /mob/living/simple_animal/hostile/blob, /mob/living/simple_animal/hostile/blob/blobbernaut, diff --git a/tgstation.dme b/tgstation.dme index 4d276957148..451b65ce2f4 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -775,6 +775,7 @@ #include "code\datums\ai\bane\bane_subtrees.dm" #include "code\datums\ai\basic_mobs\base_basic_controller.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\basic_attacking.dm" +#include "code\datums\ai\basic_mobs\basic_ai_behaviors\climb_tree.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\find_parent.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\nearest_targetting.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\pick_up_item.dm" @@ -788,6 +789,7 @@ #include "code\datums\ai\basic_mobs\basic_ai_behaviors\ventcrawling.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\write_on_paper.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\attack_obstacle_in_path.dm" +#include "code\datums\ai\basic_mobs\basic_subtrees\climb_tree.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\find_food.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\find_paper_and_write.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\find_parent.dm" @@ -1064,6 +1066,7 @@ #include "code\datums\components\toggle_suit.dm" #include "code\datums\components\transforming.dm" #include "code\datums\components\trapdoor.dm" +#include "code\datums\components\tree_climber.dm" #include "code\datums\components\twohanded.dm" #include "code\datums\components\udder.dm" #include "code\datums\components\unbreakable.dm" @@ -1884,6 +1887,7 @@ #include "code\game\objects\effects\temporary_visuals\projectiles\tracer.dm" #include "code\game\objects\items\airlock_painter.dm" #include "code\game\objects\items\apc_frame.dm" +#include "code\game\objects\items\bear_armor.dm" #include "code\game\objects\items\binoculars.dm" #include "code\game\objects\items\blueprints.dm" #include "code\game\objects\items\body_egg.dm" @@ -4099,6 +4103,9 @@ #include "code\modules\mob\living\basic\space_fauna\lightgeist.dm" #include "code\modules\mob\living\basic\space_fauna\mushroom.dm" #include "code\modules\mob\living\basic\space_fauna\spaceman.dm" +#include "code\modules\mob\living\basic\space_fauna\bear\_bear.dm" +#include "code\modules\mob\living\basic\space_fauna\bear\bear_ai_behavior.dm" +#include "code\modules\mob\living\basic\space_fauna\bear\bear_ai_subtree.dm" #include "code\modules\mob\living\basic\space_fauna\carp\carp.dm" #include "code\modules\mob\living\basic\space_fauna\carp\carp_abilities.dm" #include "code\modules\mob\living\basic\space_fauna\carp\carp_ai_actions.dm" @@ -4336,7 +4343,6 @@ #include "code\modules\mob\living\simple_animal\guardian\types\standard.dm" #include "code\modules\mob\living\simple_animal\guardian\types\support.dm" #include "code\modules\mob\living\simple_animal\hostile\alien.dm" -#include "code\modules\mob\living\simple_animal\hostile\bear.dm" #include "code\modules\mob\living\simple_animal\hostile\blob.dm" #include "code\modules\mob\living\simple_animal\hostile\blobbernaut.dm" #include "code\modules\mob\living\simple_animal\hostile\blobspore.dm" diff --git a/tools/UpdatePaths/Scripts/77141_bears.txt b/tools/UpdatePaths/Scripts/77141_bears.txt new file mode 100644 index 00000000000..122408a3c22 --- /dev/null +++ b/tools/UpdatePaths/Scripts/77141_bears.txt @@ -0,0 +1,6 @@ +/mob/living/simple_animal/hostile/bear : /mob/living/basic/bear{@OLD;wander=@SKIP;speak=@SKIP} +/mob/living/simple_animal/hostile/bear/butter : /mob/living/basic/bear/butter{@OLD;wander=@SKIP;speak=@SKIP} +/mob/living/simple_animal/hostile/bear/hudson : /mob/living/basic/bear/hudson{@OLD;wander=@SKIP;speak=@SKIP} +/mob/living/simple_animal/hostile/bear/fightpit : /mob/living/basic/bear/fightpit{@OLD;wander=@SKIP;speak=@SKIP} +/mob/living/simple_animal/hostile/bear/russian : /mob/living/basic/bear/russian{@OLD;wander=@SKIP;speak=@SKIP} +/mob/living/simple_animal/hostile/bear/snow : /mob/living/basic/bear/snow{@OLD;wander=@SKIP;speak=@SKIP} \ No newline at end of file