From b2ccdeab8b98ad5ce54702ba8739b600fbb2aa90 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Thu, 12 Oct 2023 03:27:23 +0200 Subject: [PATCH] [MIRROR] Basic Mob Gorillas [MDB IGNORE] (#24284) * Basic Mob Gorillas (#78918) ## About The Pull Request Now we can make basic mobs with hands easily so I did, they don't actually use their hands for anything with AI. In the future we can come back and share the monkey AI where they pick up items to hit people with, but frankly few weapons are more deadly than a gorilla's fists. IIRC I didn't really change their behaviour much, this is mostly just a straight conversion. Main difference is that they will prioritise eating nearby bananas and fruit salads over punching people. When I make these conversions nowadays I need to decide between "does this attack at the speed that it did as an NPC mob or the speed it did as a player?" I am arbitrarily deciding that gorillas are usually not players and electing for the former, but tell me if you disagree. I also made "show basic inhand sprites" into a component shared by Gorillas, Drones, and Dextrous Guardians (all also now available to become basic, once I get around to it), And I added an AI behaviour to run a basic emote. This is similar but different to "random speech", which kind of sucks and needs rewriting anyway. Gorillas don't speak, only ooga. ## Why It's Good For The Game https://www.youtube.com/watch?v=npuuTBlEb1U ## Changelog :cl: refactor: Gorillas now use the basic mob framework. Please report any unusual side effects. /:cl: * Basic Mob Gorillas * Modular paths --------- Co-authored-by: Jacquerel Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> --- .../RandomRuins/SpaceRuins/skyrat/gorilla.dmm | 2 +- code/__DEFINES/ai/ai_blackboard.dm | 7 +- .../signals/signals_mob/signals_mob_main.dm | 3 + code/__DEFINES/drone.dm | 5 +- code/__DEFINES/guardian_defines.dm | 5 +- .../ai/basic_mobs/basic_subtrees/run_emote.dm | 33 ++++ .../basic_subtrees/speech_subtree.dm | 2 +- code/datums/components/basic_inhands.dm | 50 +++++ code/datums/elements/amputating_limbs.dm | 2 +- code/datums/memory/_memory.dm | 2 +- code/datums/station_traits/neutral_traits.dm | 4 +- code/game/objects/items/food/monkeycube.dm | 2 +- .../traitor/objectives/kill_pet.dm | 2 +- code/modules/mob/inventory.dm | 4 + code/modules/mob/living/basic/basic.dm | 1 + code/modules/mob/living/basic/clown/clown.dm | 16 +- .../basic/farm_animals/gorilla/gorilla.dm | 181 ++++++++++++++++++ .../gorilla/gorilla_accessories.dm | 5 + .../basic/farm_animals/gorilla/gorilla_ai.dm | 35 ++++ .../farm_animals/gorilla/gorilla_emotes.dm} | 3 +- .../mob/living/basic/heretic/flesh_worm.dm | 2 +- .../basic/lavaland/lobstrosity/lobstrosity.dm | 2 +- .../carbon/alien/adult/adult_update_icons.dm | 2 +- .../mob/living/carbon/carbon_update_icons.dm | 10 +- .../living/carbon/human/human_update_icons.dm | 10 +- code/modules/mob/living/living.dm | 2 +- .../simple_animal/friendly/drone/_drone.dm | 1 + .../friendly/drone/visuals_icons.dm | 39 ---- .../living/simple_animal/guardian/guardian.dm | 27 +-- .../simple_animal/hostile/gorilla/gorilla.dm | 174 ----------------- .../hostile/gorilla/visuals_icons.dm | 56 ------ .../mob/living/simple_animal/simple_animal.dm | 1 + code/modules/mob/mob_update_icons.dm | 3 +- code/modules/mob/transform_procs.dm | 2 +- .../spells/spell_types/conjure/simian.dm | 8 +- .../unit_tests/simple_animal_freeze.dm | 3 - .../traitor/objectives/kill_pet.dm | 2 +- .../modules/emotes/code/scream_emote.dm | 2 +- strings/sillytips.txt | 1 + tgstation.dme | 9 +- .../Scripts/78918_simple_to_basic_gorilla.txt | 2 + 41 files changed, 375 insertions(+), 347 deletions(-) create mode 100644 code/datums/ai/basic_mobs/basic_subtrees/run_emote.dm create mode 100644 code/datums/components/basic_inhands.dm create mode 100644 code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm create mode 100644 code/modules/mob/living/basic/farm_animals/gorilla/gorilla_accessories.dm create mode 100644 code/modules/mob/living/basic/farm_animals/gorilla/gorilla_ai.dm rename code/modules/mob/living/{simple_animal/hostile/gorilla/emotes.dm => basic/farm_animals/gorilla/gorilla_emotes.dm} (78%) delete mode 100644 code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm delete mode 100644 code/modules/mob/living/simple_animal/hostile/gorilla/visuals_icons.dm create mode 100644 tools/UpdatePaths/Scripts/78918_simple_to_basic_gorilla.txt diff --git a/_maps/RandomRuins/SpaceRuins/skyrat/gorilla.dmm b/_maps/RandomRuins/SpaceRuins/skyrat/gorilla.dmm index b36c9c867e4..aecf79a010e 100644 --- a/_maps/RandomRuins/SpaceRuins/skyrat/gorilla.dmm +++ b/_maps/RandomRuins/SpaceRuins/skyrat/gorilla.dmm @@ -6,7 +6,7 @@ /obj/structure/chair/sofa/right/brown{ dir = 4 }, -/mob/living/simple_animal/hostile/gorilla{ +/mob/living/basic/gorilla{ anchored = 1; dir = 4; faction = list("neutral") diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm index 3877bc689d5..7ed8518e66f 100644 --- a/code/__DEFINES/ai/ai_blackboard.dm +++ b/code/__DEFINES/ai/ai_blackboard.dm @@ -11,6 +11,11 @@ ///How close a mob must be for us to select it as a target, if that is less than how far we can maintain it as a target #define BB_AGGRO_RANGE "BB_aggro_range" +/// Store a single or list of emotes at this key +#define BB_EMOTE_KEY "BB_emotes" +/// Chance to perform an emote per second +#define BB_EMOTE_CHANCE "BB_EMOTE_CHANCE" + ///Turf we want a mob to move to #define BB_TRAVEL_DESTINATION "BB_travel_destination" @@ -105,4 +110,4 @@ #define BB_EMOTE_HEAR "emote_hear" #define BB_EMOTE_SEE "emote_see" #define BB_EMOTE_SOUND "emote_sound" -#define BB_EMOTE_CHANCE "emote_chance" +#define BB_SPEAK_CHANCE "emote_chance" diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm index 7dffe24331a..51211f5ad6d 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm @@ -31,6 +31,9 @@ /// From base of /mob/living/simple_animal/bot/proc/bot_step() #define COMSIG_MOB_BOT_STEP "mob_bot_step" +/// From base of /mob/proc/update_held_items +#define COMSIG_MOB_UPDATE_HELD_ITEMS "mob_update_held_items" + /// From base of /client/Move(): (list/move_args) #define COMSIG_MOB_CLIENT_PRE_LIVING_MOVE "mob_client_pre_living_move" /// Should we stop the current living movement attempt diff --git a/code/__DEFINES/drone.dm b/code/__DEFINES/drone.dm index 8907d172194..0d31e3caf41 100644 --- a/code/__DEFINES/drone.dm +++ b/code/__DEFINES/drone.dm @@ -2,9 +2,8 @@ /// If drones are blacklisted from certain sensitive machines GLOBAL_VAR_INIT(drone_machine_blacklist_enabled, FALSE) -#define DRONE_HANDS_LAYER 1 -#define DRONE_HEAD_LAYER 2 -#define DRONE_TOTAL_LAYERS 2 +#define DRONE_HEAD_LAYER 1 +#define DRONE_TOTAL_LAYERS 1 /// Message displayed when new drone spawns in drone network #define DRONE_NET_CONNECT span_notice("DRONE NETWORK: [name] connected.") diff --git a/code/__DEFINES/guardian_defines.dm b/code/__DEFINES/guardian_defines.dm index d7aae6965a7..e7961368fee 100644 --- a/code/__DEFINES/guardian_defines.dm +++ b/code/__DEFINES/guardian_defines.dm @@ -3,6 +3,5 @@ #define GUARDIAN_THEME_CARP "carp" #define GUARDIAN_THEME_MINER "miner" -#define GUARDIAN_COLOR_LAYER 2 -#define GUARDIAN_HANDS_LAYER 1 -#define GUARDIAN_TOTAL_LAYERS 2 +#define GUARDIAN_COLOR_LAYER 1 +#define GUARDIAN_TOTAL_LAYERS 1 diff --git a/code/datums/ai/basic_mobs/basic_subtrees/run_emote.dm b/code/datums/ai/basic_mobs/basic_subtrees/run_emote.dm new file mode 100644 index 00000000000..6f2f5cdc203 --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_subtrees/run_emote.dm @@ -0,0 +1,33 @@ +/// Intermittently run an emote +/datum/ai_planning_subtree/run_emote + var/emote_key = BB_EMOTE_KEY + var/emote_chance_key = BB_EMOTE_CHANCE + +/datum/ai_planning_subtree/run_emote/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/emote_chance = controller.blackboard[emote_chance_key] || 0 + if (!SPT_PROB(emote_chance, seconds_per_tick)) + return + controller.queue_behavior(/datum/ai_behavior/run_emote, emote_key) + +/// Emote from a blackboard key +/datum/ai_behavior/run_emote + +/datum/ai_behavior/run_emote/perform(seconds_per_tick, datum/ai_controller/controller, emote_key) + var/mob/living/living_pawn = controller.pawn + if (!isliving(living_pawn)) + finish_action(controller, FALSE) + return + + var/list/emote_list = controller.blackboard[emote_key] + var/emote + if (islist(emote_list)) + emote = length(emote_list) ? pick(emote_list) : null + else + emote = emote_list + + if(isnull(emote)) + finish_action(controller, FALSE) + return + + living_pawn.emote(emote) + finish_action(controller, TRUE) 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 52f4a3459bf..7a3d5470b1a 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/speech_subtree.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/speech_subtree.dm @@ -228,6 +228,6 @@ emote_see = speech_lines[BB_EMOTE_SEE] || list() emote_hear = speech_lines[BB_EMOTE_HEAR] || list() sound = speech_lines[BB_EMOTE_SOUND] || list() - speech_chance = speech_lines[BB_EMOTE_CHANCE] ? speech_lines[BB_EMOTE_CHANCE] : initial(speech_chance) + speech_chance = speech_lines[BB_SPEAK_CHANCE] ? speech_lines[BB_SPEAK_CHANCE] : initial(speech_chance) return ..() diff --git a/code/datums/components/basic_inhands.dm b/code/datums/components/basic_inhands.dm new file mode 100644 index 00000000000..ac50f618861 --- /dev/null +++ b/code/datums/components/basic_inhands.dm @@ -0,0 +1,50 @@ +/** + * Basic handling for showing held items in a mob's hands + */ +/datum/component/basic_inhands + /// Layer index we show our inhands upon + var/display_layer + /// Y offset to apply to inhands + var/y_offset + /// X offset to apply to inhands, is inverted for the left hand + var/x_offset + /// What overlays are we currently showing? + var/list/cached_overlays + +/datum/component/basic_inhands/Initialize(display_layer = 1, y_offset = 0, x_offset = 0) + . = ..() + if (!isliving(parent)) + return COMPONENT_INCOMPATIBLE + src.display_layer = display_layer + src.y_offset = y_offset + src.x_offset = x_offset + cached_overlays = list() + +/datum/component/basic_inhands/RegisterWithParent() + . = ..() + RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_updated_overlays)) + RegisterSignal(parent, COMSIG_MOB_UPDATE_HELD_ITEMS, PROC_REF(on_updated_held_items)) + +/datum/component/basic_inhands/UnregisterFromParent() + . = ..() + UnregisterSignal(parent, list(COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_MOB_UPDATE_HELD_ITEMS)) + +/// When your overlays update, add your held overlays +/datum/component/basic_inhands/proc/on_updated_overlays(atom/parent_atom, list/overlays) + SIGNAL_HANDLER + overlays += cached_overlays + +/// When your number of held items changes, regenerate held icons +/datum/component/basic_inhands/proc/on_updated_held_items(mob/living/holding_mob) + SIGNAL_HANDLER + var/list/held_overlays = list() + for(var/obj/item/held in holding_mob.held_items) + var/is_right = holding_mob.get_held_index_of_item(held) % 2 == 0 + var/icon_file = is_right ? held.righthand_file : held.lefthand_file + var/mutable_appearance/held_overlay = held.build_worn_icon(default_layer = HANDS_LAYER, default_icon_file = icon_file, isinhands = TRUE) + held_overlay.pixel_y += y_offset + held_overlay.pixel_x += x_offset * (is_right ? 1 : -1) + held_overlays += held_overlay + + cached_overlays = held_overlays + holding_mob.update_appearance(UPDATE_OVERLAYS) diff --git a/code/datums/elements/amputating_limbs.dm b/code/datums/elements/amputating_limbs.dm index 7271b20a6c3..16a99e96f6c 100644 --- a/code/datums/elements/amputating_limbs.dm +++ b/code/datums/elements/amputating_limbs.dm @@ -68,7 +68,7 @@ /// Chop one off /datum/element/amputating_limbs/proc/amputate(mob/living/surgeon, mob/living/carbon/victim, obj/item/bodypart/to_remove) - surgeon.visible_message(span_warning("[surgeon] begins [surgery_verb] [to_remove] off of [victim]!")) + surgeon.visible_message(span_warning("[surgeon] [surgery_verb] [to_remove] off of [victim]!")) if (surgery_time > 0 && !do_after(surgeon, delay = surgery_time, target = victim)) return to_remove.dismember() diff --git a/code/datums/memory/_memory.dm b/code/datums/memory/_memory.dm index e3f161d5f0e..2b3e250a3fb 100644 --- a/code/datums/memory/_memory.dm +++ b/code/datums/memory/_memory.dm @@ -257,6 +257,7 @@ /mob/living/basic/cow/wisdom, /mob/living/basic/crab, /mob/living/basic/goat, + /mob/living/basic/gorilla, /mob/living/basic/headslug, /mob/living/basic/killer_tomato, /mob/living/basic/lizard, @@ -274,7 +275,6 @@ /mob/living/basic/statue, /mob/living/basic/stickman, /mob/living/basic/stickman/dog, - /mob/living/simple_animal/hostile/gorilla, /mob/living/simple_animal/hostile/megafauna/dragon/lesser, /mob/living/simple_animal/parrot, /mob/living/simple_animal/pet/cat, diff --git a/code/datums/station_traits/neutral_traits.dm b/code/datums/station_traits/neutral_traits.dm index 26bbc689afa..8402c70236b 100644 --- a/code/datums/station_traits/neutral_traits.dm +++ b/code/datums/station_traits/neutral_traits.dm @@ -148,7 +148,7 @@ show_in_report = FALSE // Selective attention test. Did you spot the gorilla? /// The gorilla we created, we only hold this ref until the round starts. - var/mob/living/simple_animal/hostile/gorilla/cargo_domestic/cargorilla + var/mob/living/basic/gorilla/cargorilla/cargorilla /datum/station_trait/cargorilla/New() . = ..() @@ -189,7 +189,7 @@ cargorilla = null /// Get us a ghost for the gorilla. -/datum/station_trait/cargorilla/proc/get_ghost_for_gorilla(mob/living/simple_animal/hostile/gorilla/cargo_domestic/gorilla) +/datum/station_trait/cargorilla/proc/get_ghost_for_gorilla(mob/living/basic/gorilla/cargorilla/gorilla) if(QDELETED(gorilla)) return diff --git a/code/game/objects/items/food/monkeycube.dm b/code/game/objects/items/food/monkeycube.dm index 0013fbcdadd..ffc9b63c62f 100644 --- a/code/game/objects/items/food/monkeycube.dm +++ b/code/game/objects/items/food/monkeycube.dm @@ -62,7 +62,7 @@ /datum/reagent/medicine/strange_reagent = 5, ) tastes = list("the jungle" = 1, "bananas" = 1, "jimmies" = 1) - spawned_mob = /mob/living/simple_animal/hostile/gorilla + spawned_mob = /mob/living/basic/gorilla /obj/item/food/monkeycube/chicken name = "chicken cube" diff --git a/code/modules/antagonists/traitor/objectives/kill_pet.dm b/code/modules/antagonists/traitor/objectives/kill_pet.dm index f90599e6c35..ae28f5dbf4c 100644 --- a/code/modules/antagonists/traitor/objectives/kill_pet.dm +++ b/code/modules/antagonists/traitor/objectives/kill_pet.dm @@ -26,9 +26,9 @@ JOB_CHIEF_MEDICAL_OFFICER = /mob/living/simple_animal/pet/cat/runtime, JOB_CHIEF_ENGINEER = /mob/living/simple_animal/parrot/poly, JOB_QUARTERMASTER = list( + /mob/living/basic/gorilla/cargorilla, /mob/living/basic/sloth/citrus, /mob/living/basic/sloth/paperwork, - /mob/living/simple_animal/hostile/gorilla/cargo_domestic, ) ) /// The head that we are targetting diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 7e288ebcee5..4660a1b0546 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -286,6 +286,10 @@ I.dropped(src) return FALSE +/// Returns true if a mob is holding something +/mob/proc/is_holding_items() + return !!locate(/obj/item) in held_items + /mob/proc/drop_all_held_items() . = FALSE for(var/obj/item/I in held_items) diff --git a/code/modules/mob/living/basic/basic.dm b/code/modules/mob/living/basic/basic.dm index a8b9d724752..4802ef347a0 100644 --- a/code/modules/mob/living/basic/basic.dm +++ b/code/modules/mob/living/basic/basic.dm @@ -291,6 +291,7 @@ update_held_items() /mob/living/basic/update_held_items() + . = ..() if(isnull(client) || isnull(hud_used) || hud_used.hud_version == HUD_STYLE_NOHUD) return var/turf/our_turf = get_turf(src) diff --git a/code/modules/mob/living/basic/clown/clown.dm b/code/modules/mob/living/basic/clown/clown.dm index 78715361356..5682edf9339 100644 --- a/code/modules/mob/living/basic/clown/clown.dm +++ b/code/modules/mob/living/basic/clown/clown.dm @@ -37,7 +37,7 @@ BB_EMOTE_SAY = list("HONK", "Honk!", "Welcome to clown planet!"), BB_EMOTE_HEAR = list("honks", "squeaks"), BB_EMOTE_SOUND = list('sound/items/bikehorn.ogg'), //WE LOVE TO PARTY - BB_EMOTE_CHANCE = 5, + BB_SPEAK_CHANCE = 5, ) ///do we waddle (honk) var/waddles = TRUE @@ -150,9 +150,9 @@ ), BB_EMOTE_HEAR = list("honks", "contemplates its existence"), BB_EMOTE_SEE = list("sweats", "jiggles"), - BB_EMOTE_CHANCE = 5, + BB_SPEAK_CHANCE = 5, ) - + /mob/living/basic/clown/fleshclown/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) @@ -185,7 +185,7 @@ emotes = list( BB_EMOTE_SAY = list("YA-HONK!!!"), BB_EMOTE_HEAR = list("honks", "squeaks"), - BB_EMOTE_CHANCE = 60, + BB_SPEAK_CHANCE = 60, ) /mob/living/basic/clown/clownhulk @@ -221,7 +221,7 @@ BB_EMOTE_SAY = list("HONK", "Honk!", "HAUAUANK!!!", "GUUURRRRAAAHHH!!!"), BB_EMOTE_HEAR = list("honks", "grunts"), BB_EMOTE_SEE = list("sweats"), - BB_EMOTE_CHANCE = 5, + BB_SPEAK_CHANCE = 5, ) /mob/living/basic/clown/clownhulk/chlown @@ -252,7 +252,7 @@ emotes = list( BB_EMOTE_SAY = list("HONK", "Honk!", "Bruh", "cheeaaaahhh?"), BB_EMOTE_SEE = list("asserts his dominance", "emasculates everyone implicitly"), - BB_EMOTE_CHANCE = 5, + BB_SPEAK_CHANCE = 5, ) /mob/living/basic/clown/clownhulk/honkmunculus @@ -318,7 +318,7 @@ BB_EMOTE_SAY = list("HONK!!!", "The Honkmother is merciful, so I must act out her wrath.", "parce mihi ad beatus honkmother placet mihi ut peccata committere,", "DIE!!!"), BB_EMOTE_HEAR = list("honks", "grunts"), BB_EMOTE_SEE = list("sweats"), - BB_EMOTE_CHANCE = 5, + BB_SPEAK_CHANCE = 5, ) /mob/living/basic/clown/mutant @@ -354,7 +354,7 @@ emotes = list( BB_EMOTE_SAY = list("aaaaaahhhhuuhhhuhhhaaaaa", "AAAaaauuuaaAAAaauuhhh", "huuuuuh... hhhhuuuooooonnnnkk", "HuaUAAAnKKKK"), BB_EMOTE_SEE = list("squirms", "writhes", "pulsates", "froths", "oozes"), - BB_EMOTE_CHANCE = 10, + BB_SPEAK_CHANCE = 10, ) /mob/living/basic/clown/mutant/slow diff --git a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm new file mode 100644 index 00000000000..b0926b41811 --- /dev/null +++ b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm @@ -0,0 +1,181 @@ +/// Where do we draw gorilla held overlays? +#define GORILLA_HANDS_LAYER 1 + +/** + * Like a bigger monkey + * They make a lot of noise and punch limbs off unconscious folks + */ +/mob/living/basic/gorilla + name = "Gorilla" + desc = "A ground-dwelling, predominantly herbivorous ape which usually inhabits the forests of central Africa but today is quite far away from there." + icon = 'icons/mob/simple/gorilla.dmi' + icon_state = "crawling" + icon_living = "crawling" + icon_dead = "dead" + health_doll_icon = "crawling" + mob_biotypes = MOB_ORGANIC|MOB_HUMANOID + maxHealth = 220 + health = 220 + response_help_continuous = "prods" + response_help_simple = "prod" + response_disarm_continuous = "challenges" + response_disarm_simple = "challenge" + response_harm_continuous = "thumps" + response_harm_simple = "thump" + speed = 0.5 + melee_damage_lower = 15 + melee_damage_upper = 18 + damage_coeff = list(BRUTE = 1, BURN = 1.5, TOX = 1.5, CLONE = 0, STAMINA = 0, OXY = 1.5) + obj_damage = 20 + attack_verb_continuous = "pummels" + attack_verb_simple = "pummel" + attack_sound = 'sound/weapons/punch1.ogg' + unique_name = TRUE + ai_controller = /datum/ai_controller/basic_controller/gorilla + faction = list(FACTION_MONKEY, FACTION_JUNGLE) + butcher_results = list(/obj/item/food/meat/slab/gorilla = 4, /obj/effect/gibspawner/generic/animal = 1) + /// How likely our meaty fist is to stun someone + var/paralyze_chance = 20 + /// A counter for when we can scream again + var/oogas = 0 + /// Types of things we want to find and eat + var/static/list/gorilla_food = list( + /obj/item/food/bread/banana, + /obj/item/food/breadslice/banana, + /obj/item/food/cnds/banana_honk, + /obj/item/food/grown/banana, + /obj/item/food/popsicle/topsicle/banana, + /obj/item/food/salad/fruit, + /obj/item/food/salad/jungle, + /obj/item/food/sundae, + ) + +/mob/living/basic/gorilla/Initialize(mapload) + . = ..() + add_traits(list(TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP), ROUNDSTART_TRAIT) + AddElement(/datum/element/wall_smasher) + AddElement(/datum/element/dextrous) + AddElement(/datum/element/footstep, FOOTSTEP_MOB_BAREFOOT) + AddElement(/datum/element/basic_eating, heal_amt = 10, food_types = gorilla_food) + AddElement( + /datum/element/amputating_limbs, \ + surgery_time = 0 SECONDS, \ + surgery_verb = "punches",\ + ) + AddComponent(/datum/component/personal_crafting) + AddComponent(/datum/component/basic_inhands, y_offset = -1) + ai_controller?.set_blackboard_key(BB_BASIC_FOODS, gorilla_food) + +/mob/living/basic/gorilla/update_overlays() + . = ..() + if (is_holding_items()) + . += "standing_overlay" + +/mob/living/basic/gorilla/update_icon_state() + . = ..() + if (stat == DEAD) + return + icon_state = is_holding_items() ? "standing" : "crawling" + +/mob/living/basic/gorilla/update_held_items() + . = ..() + update_appearance(UPDATE_ICON) + if (is_holding_items()) + add_movespeed_modifier(/datum/movespeed_modifier/gorilla_standing) + else + remove_movespeed_modifier(/datum/movespeed_modifier/gorilla_standing) + +/mob/living/basic/gorilla/melee_attack(mob/living/target, list/modifiers, ignore_cooldown) + . = ..() + if (!. || !isliving(target)) + return + ooga_ooga() + if (prob(paralyze_chance)) + target.Paralyze(2 SECONDS) + visible_message(span_danger("[src] knocks [target] down!")) + else + target.throw_at(get_edge_target_turf(target, dir), range = rand(1, 2), speed = 7, thrower = src) + +/mob/living/basic/gorilla/gib(drop_bitflags = DROP_BRAIN) + if(!(drop_bitflags & DROP_BRAIN)) + return ..() + var/mob/living/brain/gorilla_brain = new(drop_location()) + gorilla_brain.name = real_name + gorilla_brain.real_name = real_name + mind?.transfer_to(gorilla_brain) + return ..() + +/mob/living/basic/gorilla/can_use_guns(obj/item/gun) + to_chat(src, span_warning("Your meaty finger is much too large for the trigger guard!")) + return FALSE + +/// Assert your dominance with audio cues +/mob/living/basic/gorilla/proc/ooga_ooga() + if (isnull(client)) + return // Sorry NPCs + oogas -= 1 + if(oogas > 0) + return + oogas = rand(2,6) + emote("ooga") + +/// Gorillas are slower when carrying something +/datum/movespeed_modifier/gorilla_standing + blacklisted_movetypes = (FLYING|FLOATING) + multiplicative_slowdown = 0.5 + +/// A smaller gorilla summoned via magic +/mob/living/basic/gorilla/lesser + name = "lesser Gorilla" + desc = "An adolescent Gorilla. It may not be fully grown but, much like a banana, that just means it's sturdier and harder to chew!" + maxHealth = 120 + health = 120 + speed = 0.35 + melee_damage_lower = 10 + melee_damage_upper = 15 + obj_damage = 15 + ai_controller = /datum/ai_controller/basic_controller/gorilla/lesser + butcher_results = list(/obj/item/food/meat/slab/gorilla = 2) + +/mob/living/basic/gorilla/lesser/Initialize(mapload) + . = ..() + transform *= 0.75 + +/// Cargo's wonderful mascot, the tranquil box-carrying ape +/mob/living/basic/gorilla/cargorilla + name = "Cargorilla" // Overriden, normally + icon = 'icons/mob/simple/cargorillia.dmi' + desc = "Cargo's pet gorilla. They seem to have an 'I love Mom' tattoo." + maxHealth = 200 + health = 200 + faction = list(FACTION_NEUTRAL, FACTION_MONKEY, FACTION_JUNGLE) + unique_name = FALSE + ai_controller = null + +/mob/living/basic/gorilla/cargorilla/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_PACIFISM, INNATE_TRAIT) + AddComponent(/datum/component/crate_carrier) + +/** + * Poll ghosts for control of the gorilla. Not added in init because we only want to poll when the round starts. + * Preferably in future we can replace this with a popup on the lobby to queue to become a gorilla. + */ +/mob/living/basic/gorilla/cargorilla/proc/poll_for_gorilla() + AddComponent(\ + /datum/component/ghost_direct_control,\ + poll_candidates = TRUE,\ + poll_length = 30 SECONDS,\ + role_name = "Cargorilla",\ + assumed_control_message = "You are Cargorilla, a pacifist friend of the station and carrier of freight.",\ + poll_ignore_key = POLL_IGNORE_CARGORILLA,\ + after_assumed_control = CALLBACK(src, PROC_REF(became_player_controlled)),\ + ) + +/// Called once a ghost assumes control +/mob/living/basic/gorilla/cargorilla/proc/became_player_controlled() + mind.set_assigned_role(SSjob.GetJobType(/datum/job/cargo_technician)) + mind.special_role = "Cargorilla" + to_chat(src, span_notice("You can pick up crates by clicking on them, and drop them by clicking on the ground.")) + +#undef GORILLA_HANDS_LAYER diff --git a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla_accessories.dm b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla_accessories.dm new file mode 100644 index 00000000000..814e56487bf --- /dev/null +++ b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla_accessories.dm @@ -0,0 +1,5 @@ +/// Cargorilla's ID card +/obj/item/card/id/advanced/cargo_gorilla + name = "cargorilla ID" + desc = "A card used to provide ID and determine access across the station. A gorilla-sized ID for a gorilla-sized cargo technician." + trim = /datum/id_trim/job/cargo_technician diff --git a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla_ai.dm b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla_ai.dm new file mode 100644 index 00000000000..c6230754277 --- /dev/null +++ b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla_ai.dm @@ -0,0 +1,35 @@ +/// Pretty basic, just click people to death. Also hunt and eat bananas. +/datum/ai_controller/basic_controller/gorilla + blackboard = list( + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items/gorilla, + BB_EMOTE_KEY = "ooga", + BB_EMOTE_CHANCE = 40, + ) + + ai_traits = STOP_MOVING_WHEN_PULLED + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + + planning_subtrees = list( + /datum/ai_planning_subtree/run_emote, + /datum/ai_planning_subtree/find_food, + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/attack_obstacle_in_path/gorilla, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + ) + +/datum/targetting_datum/basic/allow_items/gorilla + stat_attack = UNCONSCIOUS + +/datum/ai_planning_subtree/attack_obstacle_in_path/gorilla + attack_behaviour = /datum/ai_behavior/attack_obstructions/gorilla + +/datum/ai_behavior/attack_obstructions/gorilla + can_attack_turfs = TRUE + +/datum/ai_controller/basic_controller/gorilla/lesser + blackboard = list( + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items, + BB_EMOTE_KEY = "ooga", + BB_EMOTE_CHANCE = 60, + ) diff --git a/code/modules/mob/living/simple_animal/hostile/gorilla/emotes.dm b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla_emotes.dm similarity index 78% rename from code/modules/mob/living/simple_animal/hostile/gorilla/emotes.dm rename to code/modules/mob/living/basic/farm_animals/gorilla/gorilla_emotes.dm index 20166d81391..94133336c4d 100644 --- a/code/modules/mob/living/simple_animal/hostile/gorilla/emotes.dm +++ b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla_emotes.dm @@ -1,5 +1,5 @@ /datum/emote/gorilla - mob_type_allowed_typecache = /mob/living/simple_animal/hostile/gorilla + mob_type_allowed_typecache = /mob/living/basic/gorilla mob_type_blacklist_typecache = list() /datum/emote/gorilla/ooga @@ -9,4 +9,3 @@ message_param = "oogas at %t." emote_type = EMOTE_AUDIBLE | EMOTE_VISIBLE sound = 'sound/creatures/gorilla.ogg' - diff --git a/code/modules/mob/living/basic/heretic/flesh_worm.dm b/code/modules/mob/living/basic/heretic/flesh_worm.dm index 05ef707faf4..3c60a9b653c 100644 --- a/code/modules/mob/living/basic/heretic/flesh_worm.dm +++ b/code/modules/mob/living/basic/heretic/flesh_worm.dm @@ -38,7 +38,7 @@ AddElement(\ /datum/element/amputating_limbs,\ surgery_time = 0 SECONDS,\ - surgery_verb = "tearing",\ + surgery_verb = "tears",\ minimum_stat = CONSCIOUS,\ snip_chance = 10,\ target_zones = GLOB.arm_zones,\ diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm index f7feaa88265..a048fe77ab1 100644 --- a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm +++ b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm @@ -39,7 +39,7 @@ AddElement(/datum/element/basic_eating, food_types = target_foods) AddElement(\ /datum/element/amputating_limbs,\ - surgery_verb = "snipping",\ + surgery_verb = "begins snipping",\ target_zones = GLOB.arm_zones,\ ) charge = new(src) diff --git a/code/modules/mob/living/carbon/alien/adult/adult_update_icons.dm b/code/modules/mob/living/carbon/alien/adult/adult_update_icons.dm index 8c211151123..bbfd68f8186 100644 --- a/code/modules/mob/living/carbon/alien/adult/adult_update_icons.dm +++ b/code/modules/mob/living/carbon/alien/adult/adult_update_icons.dm @@ -76,7 +76,7 @@ //Royals have bigger sprites, so inhand things must be handled differently. /mob/living/carbon/alien/adult/royal/update_held_items() - ..() + . = ..() remove_overlay(HANDS_LAYER) var/list/hands = list() diff --git a/code/modules/mob/living/carbon/carbon_update_icons.dm b/code/modules/mob/living/carbon/carbon_update_icons.dm index 2aab0a5e2bb..d4fa006957e 100644 --- a/code/modules/mob/living/carbon/carbon_update_icons.dm +++ b/code/modules/mob/living/carbon/carbon_update_icons.dm @@ -282,11 +282,17 @@ update_body() /mob/living/carbon/update_held_items() + . = ..() remove_overlay(HANDS_LAYER) if (handcuffed) drop_all_held_items() return + overlays_standing[HANDS_LAYER] = get_held_overlays() + apply_overlay(HANDS_LAYER) + +/// Generate held item overlays +/mob/living/carbon/proc/get_held_overlays() var/list/hands = list() for(var/obj/item/I in held_items) if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) @@ -307,9 +313,7 @@ icon_file = I.righthand_file hands += I.build_worn_icon(default_layer = HANDS_LAYER, default_icon_file = icon_file, isinhands = TRUE) - - overlays_standing[HANDS_LAYER] = hands - apply_overlay(HANDS_LAYER) + return hands /mob/living/carbon/update_fire_overlay(stacks, on_fire, last_icon_state, suffix = "") var/fire_icon = "[dna?.species.fire_overlay || "human"]_[stacks > MOB_BIG_FIRE_STACK_THRESHOLD ? "big_fire" : "small_fire"][suffix]" diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm index d1ecdfaa7aa..42eb727a83d 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -656,12 +656,7 @@ There are several things that need to be remembered: apply_overlay(LEGCUFF_LAYER) throw_alert("legcuffed", /atom/movable/screen/alert/restrained/legcuffed, new_master = src.legcuffed) -/mob/living/carbon/human/update_held_items() - remove_overlay(HANDS_LAYER) - if (handcuffed) - drop_all_held_items() - return - +/mob/living/carbon/human/get_held_overlays() var/list/hands = list() for(var/obj/item/worn_item in held_items) var/held_index = get_held_index_of_item(worn_item) @@ -690,8 +685,7 @@ There are several things that need to be remembered: held_in_hand?.held_hand_offset?.apply_offset(hand_overlay) hands += hand_overlay - overlays_standing[HANDS_LAYER] = hands - apply_overlay(HANDS_LAYER) + return hands /proc/wear_female_version(t_color, icon, layer, type, greyscale_colors, mutant_styles) // SKYRAT EDIT CHANGE - Digi female gender shaping - ORIGINAL: /proc/wear_female_version(t_color, icon, layer, type, greyscale_colors) var/index = "[t_color]-[greyscale_colors][(mutant_styles & STYLE_DIGI) ? "-d" : ""]" // SKYRAT EDIT CHANGE - Digi female gender shaping - Original: var/index = "[t_color]-[greyscale_colors]]" diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index ef57b9b1467..c409b84c4e2 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1489,6 +1489,7 @@ /mob/living/basic/cow, /mob/living/basic/crab, /mob/living/basic/goat, + /mob/living/basic/gorilla, /mob/living/basic/headslug, /mob/living/basic/killer_tomato, /mob/living/basic/lizard, @@ -1506,7 +1507,6 @@ /mob/living/basic/statue, /mob/living/basic/stickman, /mob/living/basic/stickman/dog, - /mob/living/simple_animal/hostile/gorilla, /mob/living/simple_animal/hostile/megafauna/dragon/lesser, /mob/living/simple_animal/parrot, /mob/living/simple_animal/pet/cat, diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm index a0f078acd92..75471c3cc30 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -173,6 +173,7 @@ . = ..() GLOB.drones_list += src access_card = new /obj/item/card/id/advanced/simple_bot(src) + AddComponent(/datum/component/basic_inhands, y_offset = getItemPixelShiftY()) // Doing this hurts my soul, but simple_animal access reworks are for another day. var/datum/id_trim/job/cap_trim = SSid_access.trim_singletons_by_path[/datum/id_trim/job/captain] diff --git a/code/modules/mob/living/simple_animal/friendly/drone/visuals_icons.dm b/code/modules/mob/living/simple_animal/friendly/drone/visuals_icons.dm index 69c2ac3e8cf..90391dff585 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/visuals_icons.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/visuals_icons.dm @@ -27,45 +27,6 @@ if(slot_flags & (ITEM_SLOT_HANDS|ITEM_SLOT_BACKPACK|ITEM_SLOT_DEX_STORAGE)) update_inv_internal_storage() -/mob/living/simple_animal/drone/update_held_items() - remove_overlay(DRONE_HANDS_LAYER) - var/list/hands_overlays = list() - - var/obj/item/l_hand = get_item_for_held_index(1) - var/obj/item/r_hand = get_item_for_held_index(2) - - var/y_shift = getItemPixelShiftY() - - if(r_hand) - var/mutable_appearance/r_hand_overlay = r_hand.build_worn_icon(default_layer = DRONE_HANDS_LAYER, default_icon_file = r_hand.righthand_file, isinhands = TRUE) - if(y_shift) - r_hand_overlay.pixel_y += y_shift - - hands_overlays += r_hand_overlay - - if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) - SET_PLANE_EXPLICIT(r_hand, ABOVE_HUD_PLANE, src) - r_hand.screen_loc = ui_hand_position(get_held_index_of_item(r_hand)) - client.screen |= r_hand - - if(l_hand) - var/mutable_appearance/l_hand_overlay = l_hand.build_worn_icon(default_layer = DRONE_HANDS_LAYER, default_icon_file = l_hand.lefthand_file, isinhands = TRUE) - if(y_shift) - l_hand_overlay.pixel_y += y_shift - - hands_overlays += l_hand_overlay - - if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) - SET_PLANE_EXPLICIT(l_hand, ABOVE_HUD_PLANE, src) - l_hand.screen_loc = ui_hand_position(get_held_index_of_item(l_hand)) - client.screen |= l_hand - - - if(hands_overlays.len) - drone_overlays[DRONE_HANDS_LAYER] = hands_overlays - apply_overlay(DRONE_HANDS_LAYER) - - /mob/living/simple_animal/drone/proc/update_inv_internal_storage() if(internal_storage && client && hud_used?.hud_shown) internal_storage.screen_loc = ui_drone_storage diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm index 919d54ac736..4ca35a67357 100644 --- a/code/modules/mob/living/simple_animal/guardian/guardian.dm +++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm @@ -90,6 +90,7 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians GLOB.parasites += src update_theme(theme) AddElement(/datum/element/simple_flying) + AddComponent(/datum/component/basic_inhands) manifest_effects() /mob/living/simple_animal/hostile/guardian/Destroy() //if deleted by admins or something random, cut from the summoner @@ -462,32 +463,6 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians cut_overlay(overlay) guardian_overlays[cache_index] = null -/mob/living/simple_animal/hostile/guardian/update_held_items() - remove_overlay(GUARDIAN_HANDS_LAYER) - var/list/hands_overlays = list() - var/obj/item/l_hand = get_item_for_held_index(1) - var/obj/item/r_hand = get_item_for_held_index(2) - - if(r_hand) - hands_overlays += r_hand.build_worn_icon(default_layer = GUARDIAN_HANDS_LAYER, default_icon_file = r_hand.righthand_file, isinhands = TRUE) - - if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) - SET_PLANE_EXPLICIT(r_hand, ABOVE_HUD_PLANE, src) - r_hand.screen_loc = ui_hand_position(get_held_index_of_item(r_hand)) - client.screen |= r_hand - - if(l_hand) - hands_overlays += l_hand.build_worn_icon(default_layer = GUARDIAN_HANDS_LAYER, default_icon_file = l_hand.lefthand_file, isinhands = TRUE) - - if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) - SET_PLANE_EXPLICIT(l_hand, ABOVE_HUD_PLANE, src) - l_hand.screen_loc = ui_hand_position(get_held_index_of_item(l_hand)) - client.screen |= l_hand - - if(length(hands_overlays)) - guardian_overlays[GUARDIAN_HANDS_LAYER] = hands_overlays - apply_overlay(GUARDIAN_HANDS_LAYER) - /mob/living/simple_animal/hostile/guardian/regenerate_icons() update_held_items() diff --git a/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm b/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm deleted file mode 100644 index 6f5952382c6..00000000000 --- a/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm +++ /dev/null @@ -1,174 +0,0 @@ -#define GORILLA_TOTAL_LAYERS 1 - -/mob/living/simple_animal/hostile/gorilla - name = "Gorilla" - desc = "A ground-dwelling, predominantly herbivorous ape that inhabits the forests of central Africa." - icon = 'icons/mob/simple/gorilla.dmi' - icon_state = "crawling" - icon_living = "crawling" - icon_dead = "dead" - health_doll_icon = "crawling" - mob_biotypes = MOB_ORGANIC|MOB_HUMANOID - speak_chance = 80 - maxHealth = 220 - health = 220 - loot = list(/obj/effect/gibspawner/generic/animal) - butcher_results = list(/obj/item/food/meat/slab/gorilla = 4) - response_help_continuous = "prods" - response_help_simple = "prod" - response_disarm_continuous = "challenges" - response_disarm_simple = "challenge" - response_harm_continuous = "thumps" - response_harm_simple = "thump" - speed = 0.5 - melee_damage_lower = 15 - melee_damage_upper = 18 - damage_coeff = list(BRUTE = 1, BURN = 1.5, TOX = 1.5, CLONE = 0, STAMINA = 0, OXY = 1.5) - obj_damage = 20 - environment_smash = ENVIRONMENT_SMASH_WALLS - attack_verb_continuous = "pummels" - attack_verb_simple = "pummel" - attack_sound = 'sound/weapons/punch1.ogg' - dextrous = TRUE - hud_type = /datum/hud/dextrous - held_items = list(null, null) - faction = list(FACTION_MONKEY, FACTION_JUNGLE) - robust_searching = TRUE - stat_attack = HARD_CRIT - minbodytemp = 270 - maxbodytemp = 350 - unique_name = TRUE - footstep_type = FOOTSTEP_MOB_BAREFOOT - - var/list/gorilla_overlays[GORILLA_TOTAL_LAYERS] - var/oogas = 0 - -// Gorillas like to dismember limbs from unconscious mobs. -// Returns null when the target is not an unconscious carbon mob; a list of limbs (possibly empty) otherwise. -/mob/living/simple_animal/hostile/gorilla/proc/get_target_bodyparts(atom/hit_target) - if(!iscarbon(hit_target)) - return - - var/mob/living/carbon/carbon_target = hit_target - if(carbon_target.stat < UNCONSCIOUS) - return - - var/list/parts = list() - for(var/obj/item/bodypart/part as anything in carbon_target.bodyparts) - if(part.body_part == HEAD || part.body_part == CHEST) - continue - if(part.bodypart_flags & BODYPART_UNREMOVABLE) - continue - parts += part - return parts - -/mob/living/simple_animal/hostile/gorilla/AttackingTarget(atom/attacked_target) - . = ..() - if(!.) - return - - if(client) - oogaooga() - - var/list/parts = get_target_bodyparts(target) - if(length(parts)) - var/obj/item/bodypart/to_dismember = pick(parts) - to_dismember.dismember() - return - - if(isliving(target)) - var/mob/living/living_target = target - if(prob(80)) - living_target.throw_at(get_edge_target_turf(living_target, dir), rand(1, 2), 7, src) - - else - living_target.Paralyze(2 SECONDS) - visible_message(span_danger("[src] knocks [living_target] down!")) - -/mob/living/simple_animal/hostile/gorilla/CanAttack(atom/the_target) - var/list/parts = get_target_bodyparts(target) - return ..() && !ismonkey(the_target) && (!parts || length(parts) > 3) - -/mob/living/simple_animal/hostile/gorilla/CanSmashTurfs(turf/T) - return iswallturf(T) - -/mob/living/simple_animal/hostile/gorilla/gib(drop_bitflags=DROP_BRAIN) - if(drop_bitflags & DROP_BRAIN) - var/mob/living/brain/gorilla_brain = new(drop_location()) - gorilla_brain.name = real_name - gorilla_brain.real_name = real_name - mind?.transfer_to(gorilla_brain) - return ..() - -/mob/living/simple_animal/hostile/gorilla/handle_automated_speech(override) - if(speak_chance && (override || prob(speak_chance))) - playsound(src, 'sound/creatures/gorilla.ogg', 50) - return ..() - -/mob/living/simple_animal/hostile/gorilla/can_use_guns(obj/item/G) - to_chat(src, span_warning("Your meaty finger is much too large for the trigger guard!")) - return FALSE - -/mob/living/simple_animal/hostile/gorilla/proc/oogaooga() - oogas -= 1 - if(oogas <= 0) - oogas = rand(2,6) - playsound(src, 'sound/creatures/gorilla.ogg', 50) - -/mob/living/simple_animal/hostile/gorilla/lesser - name = "lesser Gorilla" - desc = "An adolescent Gorilla. It may not be fully grown but, much like a banana, that just means it's sturdier and harder to chew!" - speak_chance = 100 // compensating for something - maxHealth = 120 - health = 120 - butcher_results = list(/obj/item/food/meat/slab/gorilla = 2) - speed = 0.35 - melee_damage_lower = 10 - melee_damage_upper = 15 - obj_damage = 15 - stat_attack = SOFT_CRIT - unique_name = TRUE - -/mob/living/simple_animal/hostile/gorilla/lesser/Initialize(mapload) - . = ..() - transform *= 0.75 // smolrilla - -/mob/living/simple_animal/hostile/gorilla/cargo_domestic - name = "Cargorilla" // Overriden, normally - icon = 'icons/mob/simple/cargorillia.dmi' - desc = "Cargo's pet gorilla. They seem to have an 'I love Mom' tattoo." - maxHealth = 200 - health = 200 - faction = list(FACTION_NEUTRAL, FACTION_MONKEY, FACTION_JUNGLE) - gold_core_spawnable = NO_SPAWN - unique_name = FALSE - -/mob/living/simple_animal/hostile/gorilla/cargo_domestic/Initialize(mapload) - . = ..() - ADD_TRAIT(src, TRAIT_PACIFISM, INNATE_TRAIT) - AddComponent(/datum/component/crate_carrier) - -/// Poll ghosts for control of the gorilla. -/mob/living/simple_animal/hostile/gorilla/cargo_domestic/proc/poll_for_gorilla() - AddComponent(\ - /datum/component/ghost_direct_control,\ - poll_candidates = TRUE,\ - poll_length = 30 SECONDS,\ - role_name = "Cargorilla",\ - assumed_control_message = "You are Cargorilla, a pacifistic friend of the station and carrier of freight.",\ - poll_ignore_key = POLL_IGNORE_CARGORILLA,\ - after_assumed_control = CALLBACK(src, PROC_REF(became_player_controlled)),\ - ) - -/// Called once a ghost assumes control -/mob/living/simple_animal/hostile/gorilla/cargo_domestic/proc/became_player_controlled() - mind.set_assigned_role(SSjob.GetJobType(/datum/job/cargo_technician)) - mind.special_role = "Cargorilla" - to_chat(src, span_notice("You can pick up crates by clicking on them, and drop them by clicking on the ground.")) - -/obj/item/card/id/advanced/cargo_gorilla - name = "cargorilla ID" - desc = "A card used to provide ID and determine access across the station. A gorilla-sized ID for a gorilla-sized cargo technician." - trim = /datum/id_trim/job/cargo_technician - -#undef GORILLA_TOTAL_LAYERS diff --git a/code/modules/mob/living/simple_animal/hostile/gorilla/visuals_icons.dm b/code/modules/mob/living/simple_animal/hostile/gorilla/visuals_icons.dm deleted file mode 100644 index 39dfe8f7d89..00000000000 --- a/code/modules/mob/living/simple_animal/hostile/gorilla/visuals_icons.dm +++ /dev/null @@ -1,56 +0,0 @@ -#define GORILLA_HANDS_LAYER 1 - -/mob/living/simple_animal/hostile/gorilla/proc/apply_overlay(cache_index) - . = gorilla_overlays[cache_index] - if(.) - add_overlay(.) - -/mob/living/simple_animal/hostile/gorilla/proc/remove_overlay(cache_index) - var/I = gorilla_overlays[cache_index] - if(I) - cut_overlay(I) - gorilla_overlays[cache_index] = null - -/mob/living/simple_animal/hostile/gorilla/update_held_items() - cut_overlays("standing_overlay") - remove_overlay(GORILLA_HANDS_LAYER) - - var/standing = FALSE - for(var/I in held_items) - if(I) - standing = TRUE - break - if(!standing) - if(stat != DEAD) - icon_state = "crawling" - set_varspeed(0.5) - return ..() - if(stat != DEAD) - icon_state = "standing" - set_varspeed(1) // Gorillas are slow when standing up. - - var/list/hands_overlays = list() - - var/obj/item/l_hand = get_item_for_held_index(1) - var/obj/item/r_hand = get_item_for_held_index(2) - - if(r_hand) - var/mutable_appearance/r_hand_overlay = r_hand.build_worn_icon(default_layer = GORILLA_HANDS_LAYER, default_icon_file = r_hand.righthand_file, isinhands = TRUE) - r_hand_overlay.pixel_y -= 1 - hands_overlays += r_hand_overlay - - if(l_hand) - var/mutable_appearance/l_hand_overlay = l_hand.build_worn_icon(default_layer = GORILLA_HANDS_LAYER, default_icon_file = l_hand.lefthand_file, isinhands = TRUE) - l_hand_overlay.pixel_y -= 1 - hands_overlays += l_hand_overlay - - if(hands_overlays.len) - gorilla_overlays[GORILLA_HANDS_LAYER] = hands_overlays - apply_overlay(GORILLA_HANDS_LAYER) - add_overlay("standing_overlay") - return ..() - -/mob/living/simple_animal/hostile/gorilla/regenerate_icons() - update_held_items() - -#undef GORILLA_HANDS_LAYER diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 4962e25afe0..85c146b29c8 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -563,6 +563,7 @@ update_held_items() /mob/living/simple_animal/update_held_items() + . = ..() if(!client || !hud_used || hud_used.hud_version == HUD_STYLE_NOHUD) return var/turf/our_turf = get_turf(src) diff --git a/code/modules/mob/mob_update_icons.dm b/code/modules/mob/mob_update_icons.dm index 8a6464ee182..b8b84f8782a 100644 --- a/code/modules/mob/mob_update_icons.dm +++ b/code/modules/mob/mob_update_icons.dm @@ -26,7 +26,8 @@ ///Updates the held items overlay(s) & HUD element. /mob/proc/update_held_items() - return + SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(src, COMSIG_MOB_UPDATE_HELD_ITEMS) ///Updates the mask overlay & HUD element. /mob/proc/update_worn_mask() diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index a492557d4e4..290177f5baf 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -298,7 +298,7 @@ regenerate_icons() icon = null invisibility = INVISIBILITY_MAXIMUM - var/mob/living/simple_animal/hostile/gorilla/new_gorilla = new (get_turf(src)) + var/mob/living/basic/gorilla/new_gorilla = new (get_turf(src)) new_gorilla.set_combat_mode(TRUE) if(mind) mind.transfer_to(new_gorilla) diff --git a/code/modules/spells/spell_types/conjure/simian.dm b/code/modules/spells/spell_types/conjure/simian.dm index 556a78e5012..aa9aabc6810 100644 --- a/code/modules/spells/spell_types/conjure/simian.dm +++ b/code/modules/spells/spell_types/conjure/simian.dm @@ -14,14 +14,18 @@ invocation_type = INVOCATION_SHOUT summon_radius = 2 - summon_type = list(/mob/living/carbon/human/species/monkey/angry, /mob/living/carbon/human/species/monkey/angry, /mob/living/simple_animal/hostile/gorilla/lesser) + summon_type = list( + /mob/living/basic/gorilla/lesser, + /mob/living/carbon/human/species/monkey/angry, + /mob/living/carbon/human/species/monkey/angry, // Listed twice so it's twice as likely, this class doesn't use pick weight + ) summon_amount = 4 /datum/action/cooldown/spell/conjure/simian/level_spell(bypass_cap) . = ..() summon_amount++ // MORE, MOOOOORE if(spell_level == spell_max_level) // We reward the faithful. - summon_type = list(/mob/living/carbon/human/species/monkey/angry, /mob/living/simple_animal/hostile/gorilla) + summon_type = list(/mob/living/carbon/human/species/monkey/angry, /mob/living/basic/gorilla) spell_requirements = SPELL_REQUIRES_NO_ANTIMAGIC // Max level lets you cast it naked, for monkey larp. to_chat(owner, span_notice("Your simian power has reached maximum capacity! You can now cast this spell naked, and you will create adult Gorillas with each cast.")) diff --git a/code/modules/unit_tests/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm index 8a96f56ef43..fc258596d4a 100644 --- a/code/modules/unit_tests/simple_animal_freeze.dm +++ b/code/modules/unit_tests/simple_animal_freeze.dm @@ -86,9 +86,6 @@ /mob/living/simple_animal/hostile/construct/wraith/mystic, /mob/living/simple_animal/hostile/construct/wraith/noncult, /mob/living/simple_animal/hostile/dark_wizard, - /mob/living/simple_animal/hostile/gorilla, - /mob/living/simple_animal/hostile/gorilla/lesser, - /mob/living/simple_animal/hostile/gorilla/cargo_domestic, /mob/living/simple_animal/hostile/guardian, /mob/living/simple_animal/hostile/guardian/assassin, /mob/living/simple_animal/hostile/guardian/charger, diff --git a/modular_skyrat/master_files/code/modules/antagonists/traitor/objectives/kill_pet.dm b/modular_skyrat/master_files/code/modules/antagonists/traitor/objectives/kill_pet.dm index 422a2d16c01..b3486f40ba7 100644 --- a/modular_skyrat/master_files/code/modules/antagonists/traitor/objectives/kill_pet.dm +++ b/modular_skyrat/master_files/code/modules/antagonists/traitor/objectives/kill_pet.dm @@ -11,7 +11,7 @@ JOB_QUARTERMASTER = list( /mob/living/basic/sloth/citrus, /mob/living/basic/sloth/paperwork, - /mob/living/simple_animal/hostile/gorilla/cargo_domestic, + /mob/living/basic/gorilla/cargorilla, ), // Non-heads like the warden, these are automatically medium-risk at minimum // They are also the only two modular additions so far diff --git a/modular_skyrat/modules/emotes/code/scream_emote.dm b/modular_skyrat/modules/emotes/code/scream_emote.dm index dd07e81cec8..50619d1bd85 100644 --- a/modular_skyrat/modules/emotes/code/scream_emote.dm +++ b/modular_skyrat/modules/emotes/code/scream_emote.dm @@ -24,7 +24,7 @@ return 'modular_skyrat/modules/emotes/sound/voice/scream_silicon.ogg' if(ismonkey(user)) return 'modular_skyrat/modules/emotes/sound/voice/scream_monkey.ogg' - if(istype(user, /mob/living/simple_animal/hostile/gorilla)) + if(istype(user, /mob/living/basic/gorilla)) return 'sound/creatures/gorilla.ogg' if(isalien(user)) return 'sound/voice/hiss6.ogg' diff --git a/strings/sillytips.txt b/strings/sillytips.txt index 752a09b25cb..5aa7af7ba00 100644 --- a/strings/sillytips.txt +++ b/strings/sillytips.txt @@ -37,3 +37,4 @@ To defeat the slaughter demon, shoot at it until it dies. When a round ends nearly everything about it is lost forever, leave your salt behind with it. You can win a pulse rifle from the arcade machine. Honest. Your sprite represents your hitbox, so that afro makes you easier to kill. The sacrifices we make for style. +Gorillas can be killed by land mines placed along forest paths. diff --git a/tgstation.dme b/tgstation.dme index dab4005135a..4fb116126b0 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -915,6 +915,7 @@ #include "code\datums\ai\basic_mobs\basic_subtrees\move_to_cardinal.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\opportunistic_ventcrawler.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\ranged_skirmish.dm" +#include "code\datums\ai\basic_mobs\basic_subtrees\run_emote.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\shapechange_ambush.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\simple_attack_target.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\simple_find_nearest_target_to_flee.dm" @@ -1023,6 +1024,7 @@ #include "code\datums\components\attached_sticker.dm" #include "code\datums\components\aura_healing.dm" #include "code\datums\components\bakeable.dm" +#include "code\datums\components\basic_inhands.dm" #include "code\datums\components\basic_mob_attack_telegraph.dm" #include "code\datums\components\basic_ranged_ready_overlay.dm" #include "code\datums\components\beetlejuice.dm" @@ -4471,6 +4473,10 @@ #include "code\modules\mob\living\basic\farm_animals\goat\_goat.dm" #include "code\modules\mob\living\basic\farm_animals\goat\goat_ai.dm" #include "code\modules\mob\living\basic\farm_animals\goat\goat_subtypes.dm" +#include "code\modules\mob\living\basic\farm_animals\gorilla\gorilla.dm" +#include "code\modules\mob\living\basic\farm_animals\gorilla\gorilla_accessories.dm" +#include "code\modules\mob\living\basic\farm_animals\gorilla\gorilla_ai.dm" +#include "code\modules\mob\living\basic\farm_animals\gorilla\gorilla_emotes.dm" #include "code\modules\mob\living\basic\heretic\ash_spirit.dm" #include "code\modules\mob\living\basic\heretic\fire_shark.dm" #include "code\modules\mob\living\basic\heretic\flesh_stalker.dm" @@ -4837,9 +4843,6 @@ #include "code\modules\mob\living\simple_animal\hostile\constructs\constructs.dm" #include "code\modules\mob\living\simple_animal\hostile\constructs\juggernaut.dm" #include "code\modules\mob\living\simple_animal\hostile\constructs\wraith.dm" -#include "code\modules\mob\living\simple_animal\hostile\gorilla\emotes.dm" -#include "code\modules\mob\living\simple_animal\hostile\gorilla\gorilla.dm" -#include "code\modules\mob\living\simple_animal\hostile\gorilla\visuals_icons.dm" #include "code\modules\mob\living\simple_animal\hostile\jungle\_jungle_mobs.dm" #include "code\modules\mob\living\simple_animal\hostile\jungle\leaper.dm" #include "code\modules\mob\living\simple_animal\hostile\megafauna\_megafauna.dm" diff --git a/tools/UpdatePaths/Scripts/78918_simple_to_basic_gorilla.txt b/tools/UpdatePaths/Scripts/78918_simple_to_basic_gorilla.txt new file mode 100644 index 00000000000..a22b7848d35 --- /dev/null +++ b/tools/UpdatePaths/Scripts/78918_simple_to_basic_gorilla.txt @@ -0,0 +1,2 @@ +/mob/living/simple_animal/hostile/gorilla/cargo_domestic : /mob/living/basic/gorilla/cargorilla{@OLD} +/mob/living/simple_animal/hostile/gorilla : /mob/living/basic/gorilla/@SUBTYPES{@OLD}