mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-31 00:58:26 +01:00
Regal Rat cleanup & minor changes (#91012)
## About The Pull Request Since #90505 added another entry to it the Regal Rat Riot ability, which turns maintenance creatures into versions loyal to the rat, has become sort of unmanageable (and to be honest it was a bit gross to start with). Instead of having a big if/else list (which was making the same range check multiple times...) that sets stats on a bunch of mobs, I delegated it to the mobs themselves and instead of changing some stats of the existing mobs we just turn them into a new mob which can be spawned or placed separately by mappers or admins if they want. Other stuff I changed: Riot (the ability which transforms mobs into minions) no longer spawns a mouse if it fails to find anything. Instead you have a chance to fish mice out of disposals bins while digging out trash and items. Domain is now a toggle which activates itself every 6 seconds rather than a button you manually click every 6 seconds. Riot makes a visual effect when used. Rare Pepe randomisation is done via a random spawner instead of the mob modifying a bunch of its own properties in Initialise. A bunch of mobs now automatically follow you after being tamed. I wrote this assuming I was going to add it to the rioted mobs but then didn't end up doing that because you might want them to immediately attack someone. My rule of thumb is that if I think you'd want the mob to attack someone the moment it is befriended I didn't add this and if you wouldn't I did. I changed some of the regal rat minion names, and some of them can now spawn from gold slime which couldn't before. ## Why It's Good For The Game This proc sucked and now it's nicer. As for the other changes; - A tamed mob immediately following you is nice feedback and saves you a click as it's likely to be your first action. Also removes some admin panel shitcode I added. - I changed Domain to a toggle because you generally want to use it on cooldown and someone suggested it on this PR and it sounded like a good idea. - I saw someone in Discord complaining that the previous flow of recruiting rats by hitting Riot with nothing around to summon one, waiting, hitting it again to convert one rat, and waiting again was tedious and annoying which I agree with. This method improves the quality of life by separating these two actions but _also_ as a side effect reduces a regal rat's ability to secretly stockpile 50 rats in a hidden maintenance room because most disposal bins are in slightly more visible areas, they'll actually need to go and make a mess somewhere someone can see them. ## Changelog 🆑 balance: Regal Rats can now grab mice out of disposal bins, and no longer spawn them with the Riot ability. balance: The Riot ability no longer needs to be used once for each slightly different kind of mob in your radius. balance: The Regal Rat Domain ability is now toggled on and off. balance: Several kinds of mob will immediately start following you once tamed. balance: Rats, hostile frogs, and evil snails can be created via gold slime reaction. /🆑
This commit is contained in:
@@ -17,3 +17,6 @@
|
||||
|
||||
///Called when a /mob/living/simple_animal/hostile fines a new target: (atom/source, new_target)
|
||||
#define COMSIG_HOSTILE_FOUND_TARGET "comsig_hostile_found_target"
|
||||
|
||||
///Called when a regal rat uses their riot ability on a mob
|
||||
#define COMSIG_REGAL_RAT_RIOTED "comsig_regal_rat_rioted"
|
||||
|
||||
@@ -1054,3 +1054,11 @@ GLOBAL_LIST_INIT(layers_to_offset, list(
|
||||
/// Distance which you can see someone's ID card
|
||||
/// Short enough that you can inspect over tables (bartender checking age)
|
||||
#define ID_EXAMINE_DISTANCE 3
|
||||
|
||||
GLOBAL_LIST_INIT(regal_rat_minion_commands, list(
|
||||
/datum/pet_command/idle,
|
||||
/datum/pet_command/free,
|
||||
/datum/pet_command/protect_owner,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/attack/mouse
|
||||
))
|
||||
|
||||
@@ -417,18 +417,15 @@
|
||||
/datum/pet_command/idle,
|
||||
/datum/pet_command/move,
|
||||
/datum/pet_command/attack,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/follow/start_active,
|
||||
/datum/pet_command/protect_owner,
|
||||
)
|
||||
var/datum/component/obeys_commands/command_component = target.AddComponent(/datum/component/obeys_commands, pet_commands)
|
||||
target.AddComponent(/datum/component/obeys_commands, pet_commands)
|
||||
|
||||
if (isnull(da_boss))
|
||||
return
|
||||
|
||||
target.befriend(da_boss)
|
||||
// Fuck it we're in admin territory we can do code crimes here
|
||||
var/datum/pet_command/follow/follow_command = command_component.available_commands["Follow"]
|
||||
follow_command?.set_command_active(target, da_boss)
|
||||
|
||||
/// Whatever it was doing before we fucked with it (mostly, can't do this with total confidence)
|
||||
/datum/admin_ai_template/reset
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
callout_type = /datum/callout_option/move
|
||||
///the behavior we use to follow
|
||||
var/follow_behavior = /datum/ai_behavior/pet_follow_friend
|
||||
///should we activate immediately if we're doing nothing else and gain a friend?
|
||||
var/activate_on_befriend = FALSE
|
||||
|
||||
/datum/pet_command/follow/set_command_active(mob/living/parent, mob/living/commander)
|
||||
. = ..()
|
||||
@@ -59,6 +61,18 @@
|
||||
controller.queue_behavior(follow_behavior, BB_CURRENT_PET_TARGET)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
|
||||
/datum/pet_command/follow/add_new_friend(mob/living/tamer)
|
||||
. = ..()
|
||||
var/mob/living/parent = weak_parent.resolve()
|
||||
if (!parent)
|
||||
return
|
||||
if (activate_on_befriend && !parent.ai_controller.blackboard_key_exists(BB_ACTIVE_PET_COMMAND))
|
||||
try_activate_command(tamer)
|
||||
|
||||
/// Like follow but start active
|
||||
/datum/pet_command/follow/start_active
|
||||
activate_on_befriend = TRUE
|
||||
|
||||
/**
|
||||
* # Pet Command: Play Dead
|
||||
* Pretend to be dead for a random period of time
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/// Mob which can become evil when exposed to a certain ability
|
||||
/datum/element/regal_rat_minion
|
||||
element_flags = ELEMENT_BESPOKE
|
||||
argument_hash_start_idx = 2
|
||||
/// Typepath of converted mob
|
||||
var/converted_path
|
||||
/// Balloon string to output on conversion
|
||||
var/success_balloon
|
||||
/// Commands to give this mob on conversion
|
||||
var/list/pet_commands
|
||||
|
||||
/datum/element/regal_rat_minion/Attach(datum/target, converted_path, success_balloon = "squeak", list/pet_commands)
|
||||
. = ..()
|
||||
if (!isliving(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
|
||||
src.converted_path = converted_path
|
||||
src.success_balloon = success_balloon
|
||||
src.pet_commands = pet_commands
|
||||
|
||||
RegisterSignal(target, COMSIG_REGAL_RAT_RIOTED, PROC_REF(on_rioted))
|
||||
|
||||
/datum/element/regal_rat_minion/Detach(datum/source)
|
||||
. = ..()
|
||||
UnregisterSignal(source, COMSIG_REGAL_RAT_RIOTED)
|
||||
|
||||
/// Makes a mob into a minion
|
||||
/datum/element/regal_rat_minion/proc/on_rioted(mob/living/minion, mob/living/master)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
INVOKE_ASYNC(src, PROC_REF(do_conversion), minion, master)
|
||||
|
||||
/// Actually turn the mob into a different mob
|
||||
/datum/element/regal_rat_minion/proc/do_conversion(mob/living/minion, mob/living/master)
|
||||
if (minion.stat == DEAD)
|
||||
return
|
||||
|
||||
var/mob/living/result = converted_path
|
||||
var/new_name = minion.name == initial(minion.name) ? result::name : minion.name
|
||||
var/mob/living/new_minion = minion.change_mob_type(converted_path, new_name = new_name, delete_old_mob = TRUE)
|
||||
if (length(pet_commands))
|
||||
new_minion.AddComponent(/datum/component/obeys_commands, pet_commands)
|
||||
|
||||
qdel(new_minion.GetComponent(/datum/component/tameable)) // Rats don't share
|
||||
|
||||
new_minion.befriend(master)
|
||||
new_minion.faction = master.faction.Copy()
|
||||
new_minion.balloon_alert_to_viewers(success_balloon)
|
||||
@@ -84,34 +84,3 @@
|
||||
/obj/effect/anomaly/bioscrambler/detonate()
|
||||
COOLDOWN_RESET(src, pulse_cooldown)
|
||||
anomalyEffect()
|
||||
|
||||
/// Visual effect spawned when the bioscrambler scrambles your bio
|
||||
/obj/effect/temp_visual/circle_wave
|
||||
icon = 'icons/effects/64x64.dmi'
|
||||
icon_state = "circle_wave"
|
||||
pixel_x = -16
|
||||
pixel_y = -16
|
||||
duration = 0.5 SECONDS
|
||||
color = COLOR_LIME
|
||||
var/max_alpha = 255
|
||||
///How far the effect would scale in size
|
||||
var/amount_to_scale = 2
|
||||
|
||||
/obj/effect/temp_visual/circle_wave/Initialize(mapload)
|
||||
transform = matrix().Scale(0.1)
|
||||
animate(src, transform = matrix().Scale(amount_to_scale), time = duration, flags = ANIMATION_PARALLEL)
|
||||
animate(src, alpha = max_alpha, time = duration * 0.6, flags = ANIMATION_PARALLEL)
|
||||
animate(alpha = 0, time = duration * 0.4)
|
||||
apply_wibbly_filters(src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/temp_visual/circle_wave/bioscrambler
|
||||
color = COLOR_LIME
|
||||
|
||||
/obj/effect/temp_visual/circle_wave/bioscrambler/light
|
||||
max_alpha = 128
|
||||
|
||||
/obj/effect/temp_visual/circle_wave/void_conduit
|
||||
color = COLOR_FULL_TONER_BLACK
|
||||
duration = 12 SECONDS
|
||||
amount_to_scale = 12
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
loot = list( // This spawner will scatter water related items around a moist site.
|
||||
/obj/item/clothing/head/cone = 7,
|
||||
/obj/item/clothing/suit/caution = 3,
|
||||
/mob/living/basic/frog = 2,
|
||||
/obj/effect/spawner/random/frog = 2,
|
||||
/obj/item/reagent_containers/cup/rag = 2,
|
||||
/obj/item/reagent_containers/cup/bucket = 2,
|
||||
/obj/effect/decal/cleanable/blood/old = 2,
|
||||
@@ -194,9 +194,19 @@
|
||||
if(mapload)
|
||||
var/turf/location = get_turf(loc)
|
||||
if(location.initial_gas_mix != OPENTURF_DEFAULT_ATMOS && location.initial_gas_mix != OPENTURF_DIRTY_ATMOS)
|
||||
loot -= list(/mob/living/basic/frog, /mob/living/basic/axolotl)
|
||||
loot -= list(/obj/effect/spawner/random/frog, /mob/living/basic/axolotl)
|
||||
return ..()
|
||||
|
||||
/obj/effect/spawner/random/frog
|
||||
name = "random frog"
|
||||
desc = "Spawns a frog, or sometimes a RARE frog."
|
||||
icon = 'icons/mob/simple/animal.dmi'
|
||||
icon_state = "frog"
|
||||
loot = list(
|
||||
/mob/living/basic/frog = 99,
|
||||
/mob/living/basic/frog/rare = 1,
|
||||
)
|
||||
|
||||
/obj/effect/spawner/random/trash/graffiti
|
||||
name = "random graffiti spawner"
|
||||
icon_state = "rune"
|
||||
|
||||
@@ -766,3 +766,34 @@
|
||||
duration = 5 MINUTES
|
||||
pixel_x = -16
|
||||
pixel_y = -8 //32
|
||||
|
||||
/// Visual effect spawned when the bioscrambler scrambles your bio
|
||||
/obj/effect/temp_visual/circle_wave
|
||||
icon = 'icons/effects/64x64.dmi'
|
||||
icon_state = "circle_wave"
|
||||
pixel_x = -16
|
||||
pixel_y = -16
|
||||
duration = 0.5 SECONDS
|
||||
color = COLOR_LIME
|
||||
var/max_alpha = 255
|
||||
///How far the effect would scale in size
|
||||
var/amount_to_scale = 2
|
||||
|
||||
/obj/effect/temp_visual/circle_wave/Initialize(mapload)
|
||||
transform = matrix().Scale(0.1)
|
||||
animate(src, transform = matrix().Scale(amount_to_scale), time = duration, flags = ANIMATION_PARALLEL)
|
||||
animate(src, alpha = max_alpha, time = duration * 0.6, flags = ANIMATION_PARALLEL)
|
||||
animate(alpha = 0, time = duration * 0.4)
|
||||
apply_wibbly_filters(src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/temp_visual/circle_wave/bioscrambler
|
||||
color = COLOR_LIME
|
||||
|
||||
/obj/effect/temp_visual/circle_wave/bioscrambler/light
|
||||
max_alpha = 128
|
||||
|
||||
/obj/effect/temp_visual/circle_wave/void_conduit
|
||||
color = COLOR_FULL_TONER_BLACK
|
||||
duration = 12 SECONDS
|
||||
amount_to_scale = 12
|
||||
|
||||
@@ -204,7 +204,7 @@
|
||||
cost = CARGO_CRATE_VALUE * 2
|
||||
contains = list(
|
||||
/mob/living/basic/axolotl,
|
||||
/mob/living/basic/frog,
|
||||
/obj/effect/spawner/random/frog,
|
||||
)
|
||||
crate_name = "amphibian crate"
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@
|
||||
/mob/living/basic/pet/dog/corgi/puppy = 5,
|
||||
/mob/living/basic/pet/cat/kitten = 5,
|
||||
/mob/living/basic/frog = 5,
|
||||
/mob/living/basic/frog/rare = 1,
|
||||
/mob/living/basic/axolotl = 1,
|
||||
/mob/living/basic/pet/dog/corgi/puppy/void = 1,
|
||||
/mob/living/basic/pet/dog/corgi/puppy/slime = 1,
|
||||
|
||||
@@ -201,7 +201,8 @@
|
||||
|
||||
/obj/item/fish/tadpole/Initialize(mapload, apply_qualities = TRUE)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/fish_growth, /mob/living/basic/frog, rand(2 MINUTES, 3 MINUTES))
|
||||
var/output_path = prob(99) ? /mob/living/basic/frog : /mob/living/basic/frog/rare
|
||||
AddComponent(/datum/component/fish_growth, output_path, rand(2 MINUTES, 3 MINUTES))
|
||||
RegisterSignal(src, COMSIG_FISH_BEFORE_GROWING, PROC_REF(growth_checks))
|
||||
RegisterSignal(src, COMSIG_FISH_FINISH_GROWING, PROC_REF(on_growth))
|
||||
|
||||
@@ -252,7 +253,7 @@
|
||||
/obj/item/fish/tadpole/proc/gestation(mob/living/user)
|
||||
if(QDELETED(user) || QDELETED(src))
|
||||
return
|
||||
new /mob/living/basic/frog(user)
|
||||
new /obj/effect/spawner/random/frog(user.drop_location())
|
||||
user.gib()
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons())
|
||||
var/list/return_list = zebra_typecacheof(list(
|
||||
/datum/data/vending_product = FISH_ICON_COIN,
|
||||
/mob/living/basic/axolotl = FISH_ICON_CRITTER,
|
||||
/mob/living/basic/frog = FISH_ICON_CRITTER,
|
||||
/obj/effect/spawner/random/frog = FISH_ICON_CRITTER,
|
||||
/mob/living/basic/carp = FISH_ICON_DEF,
|
||||
/mob/living/basic/mining = FISH_ICON_HOSTILE,
|
||||
/mob/living/basic/skeleton = FISH_ICON_BONE,
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
FISHING_RANDOM_SEED = 16,
|
||||
/obj/item/seeds/grass = 6,
|
||||
/obj/item/seeds/random = 1,
|
||||
/mob/living/basic/frog = 1,
|
||||
/obj/effect/spawner/random/frog = 1,
|
||||
/mob/living/basic/axolotl = 1,
|
||||
/mob/living/basic/turtle = 2,
|
||||
)
|
||||
@@ -98,7 +98,7 @@
|
||||
/obj/item/seeds/grass = 4,
|
||||
FISHING_RANDOM_SEED = 4,
|
||||
/obj/item/seeds/random = 1,
|
||||
/mob/living/basic/frog = 1,
|
||||
/obj/effect/spawner/random/frog = 1,
|
||||
/mob/living/basic/axolotl = 1,
|
||||
)
|
||||
fishing_difficulty = FISHING_EASY_DIFFICULTY + 5
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
FISHING_DUD = 20,
|
||||
/obj/item/fish/bumpy = 10,
|
||||
/obj/item/fish/sacabambaspis = 10,
|
||||
/mob/living/basic/frog = 2,
|
||||
/obj/effect/spawner/random/frog = 2,
|
||||
/obj/item/fishing_rod/telescopic/master = 1,
|
||||
)
|
||||
fish_counts = list(
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
/datum/pet_command/idle,
|
||||
/datum/pet_command/move,
|
||||
/datum/pet_command/free,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/follow/start_active,
|
||||
/datum/pet_command/untargeted_ability/blood_rain,
|
||||
/datum/pet_command/untargeted_ability/summon_toad,
|
||||
/datum/pet_command/attack,
|
||||
|
||||
@@ -239,7 +239,7 @@
|
||||
overlay_icon_state = "bg_revenant_border"
|
||||
spell_requirements = NONE
|
||||
cooldown_time = 30 SECONDS
|
||||
summon_type = list(/mob/living/basic/frog/frog_suicide)
|
||||
summon_type = list(/mob/living/basic/frog/suicide)
|
||||
summon_radius = 2
|
||||
summon_amount = 2
|
||||
max_summons = 2
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
var/list/seedling_commands = list(
|
||||
/datum/pet_command/idle,
|
||||
/datum/pet_command/free,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/follow/start_active,
|
||||
)
|
||||
|
||||
/mob/living/basic/seedling/Initialize(mapload)
|
||||
@@ -213,7 +213,7 @@
|
||||
seedling_commands = list(
|
||||
/datum/pet_command/idle,
|
||||
/datum/pet_command/free,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/follow/start_active,
|
||||
/datum/pet_command/attack,
|
||||
/datum/pet_command/use_ability/solarbeam,
|
||||
/datum/pet_command/use_ability/rapidseeds,
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
/datum/pet_command/idle,
|
||||
/datum/pet_command/free,
|
||||
/datum/pet_command/grub_spit,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/follow/start_active,
|
||||
/datum/pet_command/fetch,
|
||||
)
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
/datum/pet_command/free,
|
||||
/datum/pet_command/attack,
|
||||
/datum/pet_command/breed/gutlunch,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/follow/start_active,
|
||||
/datum/pet_command/fetch,
|
||||
/datum/pet_command/mine_walls,
|
||||
)
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
/datum/pet_command/move,
|
||||
/datum/pet_command/attack,
|
||||
charge_command,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/follow/start_active,
|
||||
/datum/pet_command/fish,
|
||||
)
|
||||
AddComponent(/datum/component/happiness)
|
||||
|
||||
@@ -52,7 +52,7 @@ GLOBAL_LIST_EMPTY(raptor_population)
|
||||
/datum/pet_command/move,
|
||||
/datum/pet_command/free,
|
||||
/datum/pet_command/attack,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/follow/start_active,
|
||||
/datum/pet_command/fetch,
|
||||
)
|
||||
///things we inherited from our parent
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
/datum/pet_command/minebot_ability/dump,
|
||||
/datum/pet_command/automate_mining,
|
||||
/datum/pet_command/free/minebot,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/follow/start_active,
|
||||
/datum/pet_command/attack/minebot,
|
||||
)
|
||||
///possible colors the bot can have
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
var/static/list/pet_commands = list(
|
||||
/datum/pet_command/idle,
|
||||
/datum/pet_command/free,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/follow/start_active,
|
||||
/datum/pet_command/perform_trick_sequence,
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Add 'walkies' as valid input
|
||||
/datum/pet_command/follow/dog
|
||||
activate_on_befriend = TRUE
|
||||
speech_commands = list("heel", "follow", "walkies")
|
||||
|
||||
// Add 'good dog' as valid input
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
/datum/pet_command/idle,
|
||||
/datum/pet_command/move,
|
||||
/datum/pet_command/free,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/follow/start_active,
|
||||
/datum/pet_command/attack,
|
||||
/datum/pet_command/perform_trick_sequence,
|
||||
)
|
||||
|
||||
@@ -19,8 +19,11 @@
|
||||
verb_exclaim = "gurgles loudly"
|
||||
verb_yell = "gurgles loudly"
|
||||
worn_slot_flags = ITEM_SLOT_HEAD
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
faction = list(FACTION_NEUTRAL, FACTION_MAINT_CREATURES)
|
||||
ai_controller = /datum/ai_controller/basic_controller/snail
|
||||
/// What do we turn into if effected by a regal rat?
|
||||
var/minion_path = /mob/living/basic/snail/angry
|
||||
|
||||
/mob/living/basic/snail/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -42,6 +45,9 @@
|
||||
create_reagents(100, REAGENT_HOLDER_ALIVE)
|
||||
RegisterSignal(reagents, COMSIG_REAGENTS_HOLDER_UPDATED, PROC_REF(on_reagents_update))
|
||||
|
||||
if (minion_path)
|
||||
AddElement(/datum/element/regal_rat_minion, converted_path = minion_path, success_balloon = "gurgle", pet_commands = GLOB.regal_rat_minion_commands)
|
||||
|
||||
/mob/living/basic/snail/proc/on_entered(datum/source, obj/effect/decal/cleanable/food/salt/potential_salt)
|
||||
SIGNAL_HANDLER
|
||||
if(istype(potential_salt))
|
||||
@@ -68,19 +74,36 @@
|
||||
)
|
||||
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" : ""]"
|
||||
icon_state = HAS_TRAIT(src, TRAIT_SHELL_RETREATED) ? "snail_shell" : "[base_icon_state]"
|
||||
return ..()
|
||||
|
||||
|
||||
/// This snail is going to try and beat you up
|
||||
/mob/living/basic/snail/angry
|
||||
name = "sewer snail"
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
icon_state = "snail_maints"
|
||||
icon_living = "snail_maints"
|
||||
icon_dead = "snail_maints_dead"
|
||||
base_icon_state = "snail_maints"
|
||||
health = 40
|
||||
maxHealth = 40
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 8
|
||||
obj_damage = 8
|
||||
can_be_held = FALSE
|
||||
minion_path = null
|
||||
ai_controller = /datum/ai_controller/basic_controller/snail/trash
|
||||
|
||||
|
||||
///snail's custom holder object
|
||||
/obj/item/clothing/head/mob_holder/snail
|
||||
|
||||
|
||||
@@ -4,15 +4,21 @@
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/domain
|
||||
name = "Rat King's Domain"
|
||||
desc = "Corrupts this area to be more suitable for your rat army."
|
||||
desc = "While enabled, continuously corrupt the surrounding area to be more suitable for your rat army."
|
||||
check_flags = AB_CHECK_CONSCIOUS|AB_CHECK_INCAPACITATED
|
||||
click_to_activate = FALSE
|
||||
cooldown_time = 6 SECONDS
|
||||
cooldown_time = 1 SECONDS
|
||||
button_icon = 'icons/mob/actions/actions_animal.dmi'
|
||||
background_icon_state = "bg_clock"
|
||||
overlay_icon_state = "bg_clock_border"
|
||||
button_icon_state = "coffer"
|
||||
button_icon_state = "coffer_off"
|
||||
shared_cooldown = NONE
|
||||
/// Are we currently ticking?
|
||||
var/is_active = FALSE
|
||||
/// How often do we make a mess?
|
||||
var/mess_interval = 6 SECONDS
|
||||
/// Don't do anything if we're on this cooldown
|
||||
COOLDOWN_DECLARE(mess_cooldown)
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/domain/IsAvailable(feedback = FALSE)
|
||||
. = ..()
|
||||
@@ -23,25 +29,65 @@
|
||||
owner.balloon_alert(owner, "can't use while ventcrawling!")
|
||||
return FALSE
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/domain/proc/domain()
|
||||
var/turf/location = get_turf(owner)
|
||||
location.atmos_spawn_air("[GAS_MIASMA]=4;[TURF_TEMPERATURE(T20C)]")
|
||||
switch (rand(1,10))
|
||||
if (8)
|
||||
new /obj/effect/decal/cleanable/vomit(location)
|
||||
if (9)
|
||||
new /obj/effect/decal/cleanable/vomit/old(location)
|
||||
if (10)
|
||||
new /obj/effect/decal/cleanable/oil/slippery(location)
|
||||
else
|
||||
new /obj/effect/decal/cleanable/dirt(location)
|
||||
StartCooldown()
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/domain/Activate(atom/target)
|
||||
StartCooldown(10 SECONDS)
|
||||
domain()
|
||||
set_domain_active(!is_active)
|
||||
StartCooldown()
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/domain/Remove(mob/removed_from)
|
||||
set_domain_active(FALSE)
|
||||
return ..()
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/domain/update_status_on_signal(datum/source, new_stat, old_stat)
|
||||
. = ..()
|
||||
if (!IsAvailable())
|
||||
set_domain_active(FALSE)
|
||||
|
||||
/// Enable or disable the ability
|
||||
/datum/action/cooldown/mob_cooldown/domain/proc/set_domain_active(should_active)
|
||||
if (is_active == should_active || isnull(owner))
|
||||
return
|
||||
is_active = should_active
|
||||
|
||||
if (is_active)
|
||||
RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_MOVE_VENTCRAWLING), PROC_REF(cancel_on_signal))
|
||||
button_icon_state = "coffer"
|
||||
spread_domain()
|
||||
else
|
||||
UnregisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_MOVE_VENTCRAWLING))
|
||||
button_icon_state = "coffer_off"
|
||||
|
||||
build_all_button_icons(update_flags = UPDATE_BUTTON_ICON)
|
||||
|
||||
/// Stop spreading shit when one of these events happens
|
||||
/datum/action/cooldown/mob_cooldown/domain/proc/cancel_on_signal()
|
||||
SIGNAL_HANDLER
|
||||
set_domain_active(FALSE)
|
||||
|
||||
/// Create gas and spawn mess
|
||||
/datum/action/cooldown/mob_cooldown/domain/proc/spread_domain()
|
||||
if (!is_active || !COOLDOWN_FINISHED(src, mess_cooldown) || !owner)
|
||||
return
|
||||
|
||||
var/turf/our_location = get_turf(owner)
|
||||
our_location.atmos_spawn_air("[GAS_MIASMA]=4;[TURF_TEMPERATURE(T20C)]")
|
||||
|
||||
var/list/available_spots = list(our_location) + get_adjacent_open_turfs(owner)
|
||||
var/turf/mess_location = pick(available_spots)
|
||||
|
||||
switch (rand(1,10))
|
||||
if (8)
|
||||
new /obj/effect/decal/cleanable/vomit(mess_location)
|
||||
if (9)
|
||||
new /obj/effect/decal/cleanable/vomit/old(mess_location)
|
||||
if (10)
|
||||
new /obj/effect/decal/cleanable/oil/slippery(mess_location)
|
||||
else
|
||||
new /obj/effect/decal/cleanable/dirt(mess_location)
|
||||
|
||||
COOLDOWN_START(src, mess_cooldown, mess_interval) // We use a cooldown AND timer because of the toggle
|
||||
addtimer(CALLBACK(src, PROC_REF(spread_domain)), mess_interval, TIMER_DELETE_ME)
|
||||
|
||||
/**
|
||||
* This action checks some nearby maintenance animals and makes them your minions.
|
||||
* If none are nearby, creates a new mouse.
|
||||
@@ -59,22 +105,6 @@
|
||||
shared_cooldown = NONE
|
||||
/// How close does something need to be for us to recruit it?
|
||||
var/range = 5
|
||||
/// Commands you can give to your mouse army
|
||||
var/static/list/mouse_commands = list(
|
||||
/datum/pet_command/idle,
|
||||
/datum/pet_command/free,
|
||||
/datum/pet_command/protect_owner,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/attack/mouse
|
||||
)
|
||||
/// Commands you can give to glockroaches
|
||||
var/static/list/glockroach_commands = list(
|
||||
/datum/pet_command/idle,
|
||||
/datum/pet_command/free,
|
||||
/datum/pet_command/protect_owner/glockroach,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/attack/glockroach
|
||||
)
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/riot/IsAvailable(feedback = FALSE)
|
||||
. = ..()
|
||||
@@ -98,145 +128,15 @@
|
||||
* * Spawn a single mouse if below the mouse cap.
|
||||
*/
|
||||
/datum/action/cooldown/mob_cooldown/riot/proc/riot()
|
||||
var/uplifted_mice = FALSE
|
||||
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!"))
|
||||
return
|
||||
playsound(owner, 'sound/mobs/non-humanoids/mouse/mousesqueek.ogg', vol = 150, frequency = 10000)
|
||||
|
||||
var/static/list/converted_check_list = list(FACTION_RAT)
|
||||
var/uplifted_roach = FALSE
|
||||
for (var/mob/living/basic/cockroach/nearby_roach in oview(owner, range))
|
||||
uplifted_roach = convert_roach(nearby_roach, converted_check_list) || uplifted_roach
|
||||
if (uplifted_roach)
|
||||
owner.visible_message(span_warning("[owner] commands their army to action, mutating them into sewer roaches!"))
|
||||
return
|
||||
new /obj/effect/temp_visual/circle_wave/brown(get_turf(owner))
|
||||
for (var/mob/living/possible_minion in oview(owner, range))
|
||||
SEND_SIGNAL(possible_minion, COMSIG_REGAL_RAT_RIOTED, owner)
|
||||
|
||||
var/uplifted_frog = FALSE
|
||||
for (var/mob/living/basic/frog/nearby_frog in oview(owner, range))
|
||||
uplifted_frog = convert_frog(nearby_frog, converted_check_list) || uplifted_frog
|
||||
if (uplifted_frog)
|
||||
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!"))
|
||||
return
|
||||
new /mob/living/basic/mouse(owner.loc)
|
||||
owner.visible_message(span_warning("[owner] commands a mouse to their side!"))
|
||||
|
||||
/// Makes a passed mob into our minion
|
||||
/datum/action/cooldown/mob_cooldown/riot/proc/make_minion(mob/living/new_minion, minion_desc, list/command_list = mouse_commands)
|
||||
if (isbasicmob(new_minion))
|
||||
new_minion.AddComponent(/datum/component/obeys_commands, command_list)
|
||||
qdel(new_minion.GetComponent(/datum/component/tameable)) // Rats don't share
|
||||
new_minion.befriend(owner)
|
||||
new_minion.faction = owner.faction.Copy()
|
||||
// Give a hint in description too
|
||||
new_minion.desc += minion_desc
|
||||
new_minion.balloon_alert_to_viewers("squeak")
|
||||
|
||||
/// Turns a mouse into an angry mouse
|
||||
/datum/action/cooldown/mob_cooldown/riot/proc/convert_mouse(mob/living/basic/mouse/nearby_mouse)
|
||||
// This mouse is already rat controlled, let's not bother with it.
|
||||
if (istype(nearby_mouse.ai_controller, /datum/ai_controller/basic_controller/mouse/rat))
|
||||
return FALSE
|
||||
|
||||
var/mob/living/basic/mouse/rat/rat_path = /mob/living/basic/mouse/rat
|
||||
// Change name
|
||||
if (nearby_mouse.name == "mouse")
|
||||
nearby_mouse.name = initial(rat_path.name)
|
||||
// Buffs our combat stats to that of a rat
|
||||
nearby_mouse.melee_damage_lower = initial(rat_path.melee_damage_lower)
|
||||
nearby_mouse.melee_damage_upper = initial(rat_path.melee_damage_upper)
|
||||
nearby_mouse.obj_damage = initial(rat_path.obj_damage)
|
||||
nearby_mouse.maxHealth = initial(rat_path.maxHealth)
|
||||
nearby_mouse.health = initial(rat_path.health)
|
||||
// Replace our AI with a rat one
|
||||
nearby_mouse.ai_controller = new /datum/ai_controller/basic_controller/mouse/rat(nearby_mouse)
|
||||
make_minion(nearby_mouse, " ...Except this one looks corrupted and aggressive.")
|
||||
return TRUE
|
||||
|
||||
/// Turns a roach into an angry roach
|
||||
/datum/action/cooldown/mob_cooldown/riot/proc/convert_roach(mob/living/basic/cockroach/nearby_roach, list/converted_check_list)
|
||||
// No need to convert when not on the same team.
|
||||
if (faction_check(nearby_roach.faction, converted_check_list))
|
||||
return FALSE
|
||||
|
||||
var/list/minion_commands = mouse_commands
|
||||
if (!findtext(nearby_roach.name, "sewer"))
|
||||
nearby_roach.name = "sewer [nearby_roach.name]"
|
||||
|
||||
if (istype(nearby_roach, /mob/living/basic/cockroach/glockroach) || istype(nearby_roach, /mob/living/basic/cockroach/hauberoach))
|
||||
if (istype(nearby_roach, /mob/living/basic/cockroach/glockroach))
|
||||
minion_commands = glockroach_commands
|
||||
nearby_roach.melee_damage_lower += 0.5
|
||||
nearby_roach.melee_damage_upper += 2
|
||||
else
|
||||
nearby_roach.melee_damage_lower += 2
|
||||
nearby_roach.melee_damage_upper += 4
|
||||
nearby_roach.obj_damage += 5
|
||||
nearby_roach.ai_controller = new /datum/ai_controller/basic_controller/cockroach/sewer(nearby_roach)
|
||||
nearby_roach.melee_attack_cooldown = 0.8 SECONDS
|
||||
|
||||
nearby_roach.icon_state += "_sewer"
|
||||
nearby_roach.maxHealth += 1
|
||||
nearby_roach.health += 1
|
||||
make_minion(nearby_roach, " <br>This one looks extra robust.", minion_commands)
|
||||
return TRUE
|
||||
|
||||
/// Turns a frog into a crazy frog. This doesn't do anything interesting and should when it becomes a basic mob.
|
||||
/datum/action/cooldown/mob_cooldown/riot/proc/convert_frog(mob/living/basic/frog/nearby_frog, list/converted_check_list)
|
||||
// No need to convert when not on the same team.
|
||||
if(faction_check(nearby_frog.faction, converted_check_list) || nearby_frog.stat == DEAD)
|
||||
return FALSE
|
||||
|
||||
var/list/minion_commands = mouse_commands
|
||||
if (!findtext(nearby_frog.name, "trash"))
|
||||
nearby_frog.name = replacetext(nearby_frog.name, "frog", "trash frog")
|
||||
|
||||
nearby_frog.icon_state += "_trash"
|
||||
nearby_frog.icon_living += "_trash"
|
||||
nearby_frog.icon_dead = nearby_frog.icon_state + "_dead"
|
||||
nearby_frog.maxHealth += 10
|
||||
nearby_frog.health += 10
|
||||
nearby_frog.melee_damage_lower += 1
|
||||
nearby_frog.melee_damage_upper += 5
|
||||
nearby_frog.obj_damage += 10
|
||||
nearby_frog.ai_controller = new /datum/ai_controller/basic_controller/frog/trash(nearby_frog)
|
||||
var/crazy_frog_desc = " ...[findtext(nearby_frog.name, "rare") ? "even though" : "perhaps because"] they live in a trash bag."
|
||||
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
|
||||
/obj/effect/temp_visual/circle_wave/brown
|
||||
color = COLOR_BROWN
|
||||
amount_to_scale = 4
|
||||
|
||||
// Command you can give to a mouse to make it kill someone
|
||||
/datum/pet_command/attack/mouse
|
||||
|
||||
@@ -25,3 +25,9 @@
|
||||
|
||||
/datum/ai_planning_subtree/use_mob_ability/domain
|
||||
ability_key = BB_DOMAIN_ABILITY
|
||||
|
||||
/datum/ai_planning_subtree/use_mob_ability/domain/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/datum/action/cooldown/mob_cooldown/domain/domain = controller.blackboard[ability_key]
|
||||
if (!istype(domain) || domain.is_active)
|
||||
return
|
||||
return ..()
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
var/static/list/pet_commands = list(
|
||||
/datum/pet_command/idle,
|
||||
/datum/pet_command/free,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/follow/start_active,
|
||||
/datum/pet_command/perform_trick_sequence,
|
||||
)
|
||||
|
||||
|
||||
+107
-99
@@ -34,6 +34,10 @@
|
||||
ai_controller = /datum/ai_controller/basic_controller/cockroach
|
||||
|
||||
var/cockroach_cell_line = CELL_LINE_TABLE_COCKROACH
|
||||
/// What do we turn into if recruited by a regal rat?
|
||||
var/minion_path = /mob/living/basic/cockroach/sewer
|
||||
/// Command list given to minionised cockroaches
|
||||
var/list/minion_commands
|
||||
|
||||
/mob/living/basic/cockroach/Initialize(mapload)
|
||||
var/turf/our_turf = get_turf(src)
|
||||
@@ -57,6 +61,14 @@
|
||||
ADD_TRAIT(src, TRAIT_NUKEIMMUNE, INNATE_TRAIT)
|
||||
ADD_TRAIT(src, TRAIT_RADIMMUNE, INNATE_TRAIT)
|
||||
|
||||
if (minion_path)
|
||||
set_pet_commands()
|
||||
AddElement(/datum/element/regal_rat_minion, converted_path = minion_path, success_balloon = "hiss", pet_commands = minion_commands)
|
||||
|
||||
/// Decide what this should be able to be told to do
|
||||
/mob/living/basic/cockroach/proc/set_pet_commands()
|
||||
minion_commands = GLOB.regal_rat_minion_commands
|
||||
|
||||
/mob/living/basic/cockroach/ex_act() //Explosions are a terrible way to handle a cockroach.
|
||||
return FALSE
|
||||
|
||||
@@ -64,76 +76,22 @@
|
||||
/mob/living/basic/cockroach/spawn_gibs()
|
||||
return
|
||||
|
||||
/datum/ai_controller/basic_controller/cockroach
|
||||
blackboard = list(
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
||||
BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends,
|
||||
BB_OWNER_SELF_HARM_RESPONSES = list(
|
||||
"*me waves its antennae in disapproval.",
|
||||
"*me chitters sadly."
|
||||
)
|
||||
)
|
||||
|
||||
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/random_speech/insect,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/roach,
|
||||
)
|
||||
|
||||
/obj/projectile/glockroachbullet
|
||||
damage = 10 //same damage as a hivebot
|
||||
damage_type = BRUTE
|
||||
|
||||
/obj/item/ammo_casing/glockroach
|
||||
name = "0.9mm bullet casing"
|
||||
desc = "A... 0.9mm bullet casing? What?"
|
||||
projectile_type = /obj/projectile/glockroachbullet
|
||||
|
||||
|
||||
/mob/living/basic/cockroach/glockroach
|
||||
name = "glockroach"
|
||||
desc = "HOLY SHIT, THAT COCKROACH HAS A GUN!"
|
||||
icon_state = "glockroach"
|
||||
melee_damage_lower = 2.5
|
||||
melee_damage_upper = 10
|
||||
obj_damage = 10
|
||||
/// Roach which tries to ineffectually attack you
|
||||
/mob/living/basic/cockroach/sewer
|
||||
name = "sewer roach"
|
||||
icon_state = "cockroach_sewer"
|
||||
desc = "This bug has a really bad attitude."
|
||||
health = 2
|
||||
maxHealth = 2 // Wow!
|
||||
melee_damage_lower = 2
|
||||
melee_damage_upper = 4
|
||||
obj_damage = 5
|
||||
melee_attack_cooldown = 0.8 SECONDS
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
faction = list(FACTION_HOSTILE, FACTION_MAINT_CREATURES)
|
||||
ai_controller = /datum/ai_controller/basic_controller/cockroach/glockroach
|
||||
cockroach_cell_line = CELL_LINE_TABLE_GLOCKROACH
|
||||
///number of burst shots
|
||||
var/burst_shots
|
||||
///cooldown between attacks
|
||||
var/ranged_cooldown = 1 SECONDS
|
||||
|
||||
/mob/living/basic/cockroach/glockroach/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(\
|
||||
/datum/component/ranged_attacks,\
|
||||
casing_type = /obj/item/ammo_casing/glockroach,\
|
||||
burst_shots = burst_shots,\
|
||||
cooldown_time = ranged_cooldown,\
|
||||
)
|
||||
if (ranged_cooldown <= 1 SECONDS)
|
||||
AddComponent(/datum/component/ranged_mob_full_auto)
|
||||
|
||||
/datum/ai_controller/basic_controller/cockroach/glockroach
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/pet_planning,
|
||||
/datum/ai_planning_subtree/random_speech/insect,
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/basic_ranged_attack_subtree/glockroach, //If we are attacking someone, this will prevent us from hunting
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/roach,
|
||||
)
|
||||
|
||||
/datum/ai_planning_subtree/basic_ranged_attack_subtree/glockroach
|
||||
ranged_attack_behavior = /datum/ai_behavior/basic_ranged_attack/glockroach
|
||||
|
||||
/datum/ai_behavior/basic_ranged_attack/glockroach //Slightly slower, as this is being made in feature freeze ;)
|
||||
action_cooldown = 1 SECONDS
|
||||
minion_path = null
|
||||
ai_controller = /datum/ai_controller/basic_controller/cockroach/aggro
|
||||
|
||||
/// Roach with a spiky hat, like a caltrop
|
||||
/mob/living/basic/cockroach/hauberoach
|
||||
name = "hauberoach"
|
||||
desc = "Is that cockroach wearing a tiny yet immaculate replica 19th century Prussian spiked helmet? ...Is that a bad thing?"
|
||||
@@ -149,8 +107,9 @@
|
||||
attack_vis_effect = ATTACK_EFFECT_SLASH
|
||||
faction = list(FACTION_HOSTILE, FACTION_MAINT_CREATURES)
|
||||
sharpness = SHARP_POINTY
|
||||
ai_controller = /datum/ai_controller/basic_controller/cockroach/hauberoach
|
||||
ai_controller = /datum/ai_controller/basic_controller/cockroach/aggro
|
||||
cockroach_cell_line = CELL_LINE_TABLE_HAUBEROACH
|
||||
minion_path = /mob/living/basic/cockroach/hauberoach/imperial
|
||||
|
||||
/mob/living/basic/cockroach/hauberoach/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -173,43 +132,92 @@
|
||||
living_target.visible_message(span_notice("[living_target] squashes [cockroach], not even noticing its spike."), span_notice("You squashed [cockroach], not even noticing its spike."))
|
||||
return FALSE
|
||||
|
||||
/datum/ai_controller/basic_controller/cockroach/hauberoach
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/pet_planning,
|
||||
/datum/ai_planning_subtree/random_speech/insect,
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree, //If we are attacking someone, this will prevent us from hunting
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/roach,
|
||||
)
|
||||
/// Regal rat royal escort
|
||||
/mob/living/basic/cockroach/hauberoach/imperial
|
||||
name = "imperial hauberoach"
|
||||
desc = "This cockroach seems to have found employment as a professional royal guard."
|
||||
health = 2
|
||||
maxHealth = 2
|
||||
melee_damage_lower = 3
|
||||
melee_damage_upper = 12
|
||||
icon_state = "hauberoach_sewer"
|
||||
minion_path = null
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
|
||||
/datum/ai_controller/basic_controller/cockroach/sewer
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/pet_planning,
|
||||
/datum/ai_planning_subtree/random_speech/insect,
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/roach,
|
||||
)
|
||||
/// Roach with a gun
|
||||
/mob/living/basic/cockroach/glockroach
|
||||
name = "glockroach"
|
||||
desc = "HOLY SHIT, THAT COCKROACH HAS A GUN!"
|
||||
icon_state = "glockroach"
|
||||
melee_damage_lower = 2.5
|
||||
melee_damage_upper = 10
|
||||
obj_damage = 10
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
faction = list(FACTION_HOSTILE, FACTION_MAINT_CREATURES)
|
||||
ai_controller = /datum/ai_controller/basic_controller/cockroach/glockroach
|
||||
cockroach_cell_line = CELL_LINE_TABLE_GLOCKROACH
|
||||
minion_path = /mob/living/basic/cockroach/glockroach/gang
|
||||
///number of burst shots
|
||||
var/burst_shots
|
||||
///cooldown between attacks
|
||||
var/ranged_cooldown = 1 SECONDS
|
||||
|
||||
/mob/living/basic/cockroach/glockroach/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(\
|
||||
/datum/component/ranged_attacks,\
|
||||
casing_type = /obj/item/ammo_casing/glockroach,\
|
||||
burst_shots = burst_shots,\
|
||||
cooldown_time = ranged_cooldown,\
|
||||
)
|
||||
if (ranged_cooldown <= 1 SECONDS)
|
||||
AddComponent(/datum/component/ranged_mob_full_auto)
|
||||
|
||||
/mob/living/basic/cockroach/glockroach/set_pet_commands()
|
||||
var/static/list/glockroach_commands = list(
|
||||
/datum/pet_command/idle,
|
||||
/datum/pet_command/free,
|
||||
/datum/pet_command/protect_owner/glockroach,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/attack/glockroach
|
||||
)
|
||||
minion_commands = glockroach_commands
|
||||
|
||||
/mob/living/basic/cockroach/glockroach/gang
|
||||
name = "gangroach"
|
||||
desc = "This roach grew up on the wrong side of the streets and has fallen in with the wrong crowd."
|
||||
icon_state = "glockroach_sewer"
|
||||
health = 2
|
||||
maxHealth = 2
|
||||
minion_path = null
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
|
||||
/obj/projectile/glockroachbullet
|
||||
damage = 10 //same damage as a hivebot
|
||||
damage_type = BRUTE
|
||||
|
||||
/obj/item/ammo_casing/glockroach
|
||||
name = "0.9mm bullet casing"
|
||||
desc = "A... 0.9mm bullet casing? What?"
|
||||
projectile_type = /obj/projectile/glockroachbullet
|
||||
|
||||
/// Roach with an SMG
|
||||
/mob/living/basic/cockroach/glockroach/mobroach
|
||||
name = "mobroach"
|
||||
desc = "WE'RE FUCKED, THAT GLOCKROACH HAS A TOMMYGUN!"
|
||||
desc = "WE'RE FUCKED, THAT COCKROACH HAS A TOMMYGUN!"
|
||||
icon_state = "mobroach"
|
||||
ai_controller = /datum/ai_controller/basic_controller/cockroach/mobroach
|
||||
burst_shots = 4
|
||||
ranged_cooldown = 2 SECONDS
|
||||
minion_path = /mob/living/basic/cockroach/glockroach/mobroach/goon
|
||||
|
||||
/datum/ai_controller/basic_controller/cockroach/mobroach
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/pet_planning,
|
||||
/datum/ai_planning_subtree/random_speech/insect,
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/basic_ranged_attack_subtree/mobroach, //If we are attacking someone, this will prevent us from hunting
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/roach,
|
||||
)
|
||||
ai_controller = /datum/ai_controller/basic_controller/cockroach/glockroach
|
||||
|
||||
/datum/ai_planning_subtree/basic_ranged_attack_subtree/mobroach
|
||||
ranged_attack_behavior = /datum/ai_behavior/basic_ranged_attack/mobroach
|
||||
/mob/living/basic/cockroach/glockroach/mobroach/goon
|
||||
name = "goonroach"
|
||||
desc = "You got it, boss."
|
||||
icon_state = "mobroach_sewer"
|
||||
health = 2
|
||||
maxHealth = 2
|
||||
minion_path = null
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
|
||||
/datum/ai_behavior/basic_ranged_attack/mobroach
|
||||
action_cooldown = 2 SECONDS
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
/// AI controller for normal roach
|
||||
/datum/ai_controller/basic_controller/cockroach
|
||||
blackboard = list(
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
||||
BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends,
|
||||
BB_OWNER_SELF_HARM_RESPONSES = list(
|
||||
"*me waves its antennae in disapproval.",
|
||||
"*me chitters sadly."
|
||||
)
|
||||
)
|
||||
|
||||
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/random_speech/insect,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/roach,
|
||||
)
|
||||
|
||||
/// AI controller for aggressive roach
|
||||
/datum/ai_controller/basic_controller/cockroach/aggro
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/pet_planning,
|
||||
/datum/ai_planning_subtree/random_speech/insect,
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/roach,
|
||||
)
|
||||
|
||||
/// AI controller for roach who can shoot at you
|
||||
/datum/ai_controller/basic_controller/cockroach/glockroach
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/pet_planning,
|
||||
/datum/ai_planning_subtree/random_speech/insect,
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/basic_ranged_attack_subtree/glockroach, //If we are attacking someone, this will prevent us from hunting
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/roach,
|
||||
)
|
||||
|
||||
/datum/ai_planning_subtree/basic_ranged_attack_subtree/glockroach
|
||||
ranged_attack_behavior = /datum/ai_behavior/basic_ranged_attack/glockroach
|
||||
|
||||
/datum/ai_behavior/basic_ranged_attack/glockroach //Slightly slower, as this is being made in feature freeze ;)
|
||||
action_cooldown = 1 SECONDS
|
||||
|
||||
/// roach who shoots at you slightly slower
|
||||
/datum/ai_controller/basic_controller/cockroach/mobroach
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/pet_planning,
|
||||
/datum/ai_planning_subtree/random_speech/insect,
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/basic_ranged_attack_subtree/mobroach,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/roach,
|
||||
)
|
||||
|
||||
/datum/ai_planning_subtree/basic_ranged_attack_subtree/mobroach
|
||||
ranged_attack_behavior = /datum/ai_behavior/basic_ranged_attack/mobroach
|
||||
|
||||
/datum/ai_behavior/basic_ranged_attack/mobroach
|
||||
action_cooldown = 2 SECONDS
|
||||
@@ -45,15 +45,14 @@
|
||||
var/poison_per_bite = 3
|
||||
///What reagent the mob injects targets with
|
||||
var/poison_type = /datum/reagent/drug/space_drugs
|
||||
///What type do we become if influenced by a regal rat?
|
||||
var/minion_type = /mob/living/basic/frog/crazy
|
||||
|
||||
/mob/living/basic/frog/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
add_traits(list(TRAIT_NODROWN, TRAIT_SWIMMER, TRAIT_VENTCRAWLER_ALWAYS), INNATE_TRAIT)
|
||||
|
||||
if(prob(1))
|
||||
make_rare()
|
||||
|
||||
var/static/list/loc_connections = list(
|
||||
COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
|
||||
)
|
||||
@@ -61,23 +60,56 @@
|
||||
AddElement(/datum/element/venomous, poison_type, poison_per_bite)
|
||||
AddElement(/datum/element/ai_retaliate)
|
||||
AddElement(/datum/element/swabable, CELL_LINE_TABLE_FROG, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
|
||||
if (minion_type)
|
||||
AddElement(/datum/element/regal_rat_minion, converted_path = minion_type, success_balloon = "ribbit", pet_commands = GLOB.regal_rat_minion_commands)
|
||||
|
||||
/mob/living/basic/frog/proc/make_rare()
|
||||
/mob/living/basic/frog/proc/on_entered(datum/source, entered as mob|obj)
|
||||
SIGNAL_HANDLER
|
||||
if(stat || !isliving(entered))
|
||||
return
|
||||
var/mob/living/entered_mob = entered
|
||||
if(entered_mob.mob_size > MOB_SIZE_TINY)
|
||||
playsound(src, stepped_sound, vol = 50, vary = TRUE)
|
||||
|
||||
/mob/living/basic/frog/rare
|
||||
name = "rare frog"
|
||||
desc = "They seem a little smug."
|
||||
icon_state = "rare_[icon_state]"
|
||||
icon_living = "rare_[icon_living]"
|
||||
icon_dead = "rare_[icon_dead]"
|
||||
icon_state = "rare_frog"
|
||||
icon_living = "rare_frog"
|
||||
icon_dead = "rare_frog_dead"
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
butcher_results = list(/obj/item/food/nugget = 5)
|
||||
poison_type = /datum/reagent/drug/mushroomhallucinogen
|
||||
minion_type = /mob/living/basic/frog/crazy/rare
|
||||
|
||||
/// These frogs would REALLY rather like to get at your blood basically by any means possible
|
||||
/mob/living/basic/frog/crazy
|
||||
name = "trash frog"
|
||||
desc = "They seem a little mad."
|
||||
icon_state = "frog_trash"
|
||||
icon_living = "frog_trash"
|
||||
icon_dead = "frog_trash_dead"
|
||||
health = 25
|
||||
maxHealth = 25
|
||||
melee_damage_lower = 6
|
||||
melee_damage_upper = 15
|
||||
obj_damage = 20
|
||||
minion_type = null
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
ai_controller = /datum/ai_controller/basic_controller/frog/trash
|
||||
|
||||
/mob/living/basic/frog/crazy/rare
|
||||
name = "crazy frog"
|
||||
desc = "They look hopping mad."
|
||||
icon_state = "rare_frog_trash"
|
||||
icon_living = "rare_frog_trash"
|
||||
icon_dead = "rare_frog_trash_dead"
|
||||
minion_type = null
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
butcher_results = list(/obj/item/food/nugget = 5)
|
||||
poison_type = /datum/reagent/drug/mushroomhallucinogen
|
||||
|
||||
/mob/living/basic/frog/proc/on_entered(datum/source, AM as mob|obj)
|
||||
SIGNAL_HANDLER
|
||||
if(!stat && isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
if(L.mob_size > MOB_SIZE_TINY)
|
||||
playsound(src, stepped_sound, 50, TRUE)
|
||||
|
||||
/// The cold doesn't bother him
|
||||
/mob/living/basic/frog/icemoon_facility
|
||||
name = "Peter Jr."
|
||||
desc = "They seem a little cold."
|
||||
@@ -86,11 +118,17 @@
|
||||
habitable_atmos = null
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
|
||||
/mob/living/basic/frog/icemoon_facility/make_rare()
|
||||
. = ..()
|
||||
name = "Peter Sr." //make him senior.
|
||||
/mob/living/basic/frog/icemoon_facility/crazy
|
||||
name = "Crazy Pete"
|
||||
desc = "The cold is really getting to him."
|
||||
icon_state = "frog_trash"
|
||||
icon_living = "frog_trash"
|
||||
icon_dead = "frog_trash_dead"
|
||||
ai_controller = /datum/ai_controller/basic_controller/frog/trash
|
||||
|
||||
/mob/living/basic/frog/frog_suicide
|
||||
|
||||
/// Frog spawned by leapers which explodes on attack
|
||||
/mob/living/basic/frog/suicide
|
||||
name = "suicide frog"
|
||||
desc = "Driven by sheer will."
|
||||
icon_state = "frog_trash"
|
||||
@@ -99,10 +137,11 @@
|
||||
maxHealth = 5
|
||||
health = 5
|
||||
ai_controller = /datum/ai_controller/basic_controller/frog/suicide_frog
|
||||
minion_type = null
|
||||
///how long do we exist for
|
||||
var/existence_period = 15 SECONDS
|
||||
|
||||
/mob/living/basic/frog/frog_suicide/Initialize(mapload)
|
||||
/mob/living/basic/frog/suicide/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/explode_on_attack, mob_type_dont_bomb = typecacheof(list(/mob/living/basic/frog, /mob/living/basic/leaper)))
|
||||
addtimer(CALLBACK(src, PROC_REF(death)), existence_period)
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
var/static/list/pet_commands = list(
|
||||
/datum/pet_command/idle,
|
||||
/datum/pet_command/free,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/follow/start_active,
|
||||
/datum/pet_command/perform_trick_sequence,
|
||||
)
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
var/static/list/pet_commands = list(
|
||||
/datum/pet_command/idle,
|
||||
/datum/pet_command/free,
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/follow/start_active,
|
||||
/datum/pet_command/perform_trick_sequence,
|
||||
)
|
||||
|
||||
@@ -86,6 +86,8 @@
|
||||
var/static/list/food_types = list(/obj/item/food/cheese)
|
||||
AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 100)
|
||||
|
||||
AddElement(/datum/element/regal_rat_minion, converted_path = /mob/living/basic/mouse/rat, pet_commands = GLOB.regal_rat_minion_commands)
|
||||
|
||||
/mob/living/basic/mouse/Destroy()
|
||||
SSmobs.cheeserats -= src
|
||||
return ..()
|
||||
@@ -300,7 +302,7 @@
|
||||
name = "rat"
|
||||
desc = "They're a nasty, ugly, evil, disease-ridden rodent with anger issues."
|
||||
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
melee_damage_lower = 3
|
||||
melee_damage_upper = 5
|
||||
obj_damage = 5
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
if(istext(new_type))
|
||||
new_type = text2path(new_type)
|
||||
|
||||
if( !ispath(new_type) )
|
||||
if(!ispath(new_type) )
|
||||
to_chat(usr, "Invalid type path (new_type = [new_type]) in change_mob_type(). Contact a coder.")
|
||||
return
|
||||
|
||||
|
||||
@@ -143,21 +143,32 @@
|
||||
king.visible_message(span_warning("[king] starts rummaging through [src]."),span_notice("You rummage through [src]..."))
|
||||
if (!do_after(king, 2 SECONDS, src, interaction_key = "regalrat"))
|
||||
return
|
||||
|
||||
var/cheese = FALSE
|
||||
var/loot = rand(1,100)
|
||||
switch(loot)
|
||||
if(1 to 5)
|
||||
to_chat(king, span_notice("You find some leftover coins. More for the royal treasury!"))
|
||||
var/pickedcoin = pick(GLOB.ratking_coins)
|
||||
for(var/i = 1 to rand(1,3))
|
||||
new pickedcoin(get_turf(king))
|
||||
new pickedcoin(king.drop_location())
|
||||
if(6 to 33)
|
||||
cheese = TRUE
|
||||
king.say(pick("Treasure!","Our precious!","Cheese!"), ignore_spam = TRUE, forced = "regal rat rummaging")
|
||||
to_chat(king, span_notice("Score! You find some cheese!"))
|
||||
new /obj/item/food/cheese/wedge(get_turf(king))
|
||||
new /obj/item/food/cheese/wedge(king.drop_location())
|
||||
else
|
||||
var/pickedtrash = pick(GLOB.ratking_trash)
|
||||
to_chat(king, span_notice("You just find more garbage and dirt. Lovely, but beneath you now."))
|
||||
new pickedtrash(get_turf(king))
|
||||
new pickedtrash(king.drop_location())
|
||||
|
||||
if (cheese)
|
||||
return // We don't want them to eat your reward
|
||||
var/rat_cap = CONFIG_GET(number/ratcap)
|
||||
if (LAZYLEN(SSmobs.cheeserats) < rat_cap && prob(33))
|
||||
var/mob/living/basic/mouse/new_subject = new(king.drop_location())
|
||||
playsound(new_subject, 'sound/mobs/non-humanoids/mouse/mousesqueek.ogg', 100)
|
||||
visible_message(span_warning("[new_subject] climbs out of [src]!"))
|
||||
|
||||
/// Moves an item into the diposal bin
|
||||
/obj/machinery/disposal/proc/place_item_in_disposal(obj/item/I, mob/user)
|
||||
|
||||
@@ -578,7 +578,7 @@
|
||||
/datum/reagent/toxin = -1)
|
||||
|
||||
virus_suspectibility = 0.5
|
||||
resulting_atom = /mob/living/basic/frog
|
||||
resulting_atom = /obj/effect/spawner/random/frog
|
||||
|
||||
/datum/micro_organism/cell_line/axolotl
|
||||
desc = "caudata amphibian cells"
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 20 KiB |
+3
-1
@@ -1734,6 +1734,7 @@
|
||||
#include "code\datums\elements\radiation_protected_clothing.dm"
|
||||
#include "code\datums\elements\radioactive.dm"
|
||||
#include "code\datums\elements\ranged_armour.dm"
|
||||
#include "code\datums\elements\regal_rat_minion.dm"
|
||||
#include "code\datums\elements\relay_attackers.dm"
|
||||
#include "code\datums\elements\ridable.dm"
|
||||
#include "code\datums\elements\rust.dm"
|
||||
@@ -5434,12 +5435,13 @@
|
||||
#include "code\modules\mob\living\basic\turtle\turtle_ai.dm"
|
||||
#include "code\modules\mob\living\basic\vermin\axolotl.dm"
|
||||
#include "code\modules\mob\living\basic\vermin\butterfly.dm"
|
||||
#include "code\modules\mob\living\basic\vermin\cockroach.dm"
|
||||
#include "code\modules\mob\living\basic\vermin\crab.dm"
|
||||
#include "code\modules\mob\living\basic\vermin\frog.dm"
|
||||
#include "code\modules\mob\living\basic\vermin\lizard.dm"
|
||||
#include "code\modules\mob\living\basic\vermin\mouse.dm"
|
||||
#include "code\modules\mob\living\basic\vermin\space_bat.dm"
|
||||
#include "code\modules\mob\living\basic\vermin\cockroach\cockroach.dm"
|
||||
#include "code\modules\mob\living\basic\vermin\cockroach\cockroach_ai.dm"
|
||||
#include "code\modules\mob\living\basic\vermin\mothroach\mothroach.dm"
|
||||
#include "code\modules\mob\living\basic\vermin\mothroach\mothroach_ai.dm"
|
||||
#include "code\modules\mob\living\brain\brain.dm"
|
||||
|
||||
Reference in New Issue
Block a user