diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index eebcf24d8e3..7f408a6805e 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -147,6 +147,10 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list( #define iscow(A) (istype(A, /mob/living/basic/cow)) +#define isgorilla(A) (istype(A, /mob/living/basic/gorilla)) + +#define is_simian(A) (isgorilla(A) || ismonkey(A)) + /// returns whether or not the atom is either a basic mob OR simple animal #define isanimal_or_basicmob(A) (istype(A, /mob/living/simple_animal) || istype(A, /mob/living/basic)) diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index cd76af78f6c..a18a77f180d 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -87,6 +87,7 @@ #define ROLE_SERVANT_GOLEM "Servant Golem" #define ROLE_SLAUGHTER_DEMON "Slaughter Demon" #define ROLE_WIZARD_APPRENTICE "apprentice" +#define ROLE_SYNDICATE_MONKEY "Syndicate Monkey Agent" //Spawner roles #define ROLE_ANCIENT_CREW "Ancient Crew" diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index c9c2c6ea83b..920af616463 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -281,6 +281,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_NO_TRANSFORMATION_STING "no_transformation_sting" /// Carbons with this trait can't have their DNA copied by diseases nor changelings #define TRAIT_NO_DNA_COPY "no_dna_copy" +/// Carbons with this trait cant have their dna scrambled by genetics or a disease retrovirus. +#define TRAIT_NO_DNA_SCRAMBLE "no_dna_scramble" /// Carbons with this trait can eat blood to regenerate their own blood volume, instead of injecting it #define TRAIT_DRINKS_BLOOD "drinks_blood" /// Mob is immune to clone (cellular) damage diff --git a/code/_globalvars/lists/names.dm b/code/_globalvars/lists/names.dm index 01e6f3b59dc..b2662b5e804 100644 --- a/code/_globalvars/lists/names.dm +++ b/code/_globalvars/lists/names.dm @@ -24,6 +24,7 @@ GLOBAL_LIST_INIT(nightmare_names, world.file2list("strings/names/nightmare.txt") GLOBAL_LIST_INIT(megacarp_first_names, world.file2list("strings/names/megacarp1.txt")) GLOBAL_LIST_INIT(megacarp_last_names, world.file2list("strings/names/megacarp2.txt")) GLOBAL_LIST_INIT(cyberauth_names, world.file2list("strings/names/cyberauth.txt")) +GLOBAL_LIST_INIT(syndicate_monkey_names, world.file2list("strings/names/syndicate_monkey.txt")) GLOBAL_LIST_INIT(verbs, world.file2list("strings/names/verbs.txt")) GLOBAL_LIST_INIT(ing_verbs, world.file2list("strings/names/ing_verbs.txt")) diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 3d69a40dbdd..2d745cb6290 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -842,6 +842,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) /proc/scramble_dna(mob/living/carbon/M, ui=FALSE, se=FALSE, uf=FALSE, probability) if(!M.has_dna()) CRASH("[M] does not have DNA") + if(HAS_TRAIT(M, TRAIT_NO_DNA_SCRAMBLE)) + return if(se) for(var/i=1, i <= DNA_MUTATION_BLOCKS, i++) if(prob(probability)) diff --git a/code/game/objects/items/boxcutter.dm b/code/game/objects/items/boxcutter.dm index 62273c1080f..467bc666e60 100644 --- a/code/game/objects/items/boxcutter.dm +++ b/code/game/objects/items/boxcutter.dm @@ -17,6 +17,8 @@ var/snap_time_weak_handcuffs = 0 SECONDS /// Used on Initialize, how much time to cut real handcuffs. Null means it can't. var/snap_time_strong_handcuffs = null + /// Starts open if true + var/start_extended = FALSE /obj/item/boxcutter/get_all_tool_behaviours() return list(TOOL_KNIFE) @@ -31,6 +33,7 @@ AddComponent( \ /datum/component/transforming, \ + start_transformed = start_extended, \ force_on = 10, \ throwforce_on = 4, \ throw_speed_on = throw_speed, \ @@ -53,3 +56,6 @@ else RemoveElement(/datum/element/cuffsnapping, snap_time_weak_handcuffs, snap_time_strong_handcuffs) return COMPONENT_NO_DEFAULT_MESSAGE + +/obj/item/boxcutter/extended + start_extended = TRUE diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm index 624939b3928..450c1b4ce27 100644 --- a/code/game/objects/items/storage/toolbox.dm +++ b/code/game/objects/items/storage/toolbox.dm @@ -449,3 +449,65 @@ desc = "A gun case. Has the symbol of the Third Soviet Union stamped on the side." weapon_to_spawn = /obj/item/gun/ballistic/automatic/plastikov extra_to_spawn = /obj/item/food/rationpack //sorry comrade, cannot get you more ammo, here, have lunch + +/obj/item/storage/toolbox/guncase/monkeycase + name = "monkey gun case" + desc = "Everything a monkey needs to truly go ape-shit. There's a paw-shaped hand scanner lock on the front of the case." + +/obj/item/storage/toolbox/guncase/monkeycase/Initialize(mapload) + . = ..() + atom_storage.locked = STORAGE_SOFT_LOCKED + +/obj/item/storage/toolbox/guncase/monkeycase/attack_self(mob/user, modifiers) + if(!monkey_check(user)) + return + return ..() + +/obj/item/storage/toolbox/guncase/monkeycase/attack_self_secondary(mob/user, modifiers) + attack_self(user, modifiers) + return + +/obj/item/storage/toolbox/guncase/monkeycase/attack_hand(mob/user, list/modifiers) + if(!monkey_check(user)) + return + return ..() + +/obj/item/storage/toolbox/guncase/monkeycase/proc/monkey_check(mob/user) + if(atom_storage.locked == STORAGE_NOT_LOCKED) + return TRUE + + if(is_simian(user)) + atom_storage.locked = STORAGE_NOT_LOCKED + to_chat(user, span_notice("You place your paw on the paw scanner, and hear a soft click as [src] unlocks!")) + playsound(src, 'sound/items/click.ogg', 25, TRUE) + return TRUE + to_chat(user, span_warning("You put your hand on the hand scanner, and it rejects it with an angry chimpanzee screech!")) + playsound(src, "sound/creatures/monkey/monkey_screech_[rand(1,7)].ogg", 75, TRUE) + return FALSE + +/obj/item/storage/toolbox/guncase/monkeycase/PopulateContents() + switch(rand(1, 3)) + if(1) + // Uzi with a boxcutter. + new /obj/item/gun/ballistic/automatic/mini_uzi/chimpgun(src) + new /obj/item/ammo_box/magazine/uzim9mm(src) + new /obj/item/ammo_box/magazine/uzim9mm(src) + new /obj/item/boxcutter/extended(src) + if(2) + // Thompson with a boxcutter. + new /obj/item/gun/ballistic/automatic/tommygun/chimpgun(src) + new /obj/item/ammo_box/magazine/tommygunm45(src) + new /obj/item/ammo_box/magazine/tommygunm45(src) + new /obj/item/boxcutter/extended(src) + if(3) + // M1911 with a switchblade and an extra banana bomb. + new /obj/item/gun/ballistic/automatic/pistol/m1911/chimpgun(src) + new /obj/item/ammo_box/magazine/m45(src) + new /obj/item/ammo_box/magazine/m45(src) + new /obj/item/switchblade/extended(src) + new /obj/item/food/grown/banana/bunch/monkeybomb(src) + + // Banana bomb! Basically a tiny flashbang for monkeys. + new /obj/item/food/grown/banana/bunch/monkeybomb(src) + // Somewhere to store it all. + new /obj/item/storage/backpack/messenger(src) diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm index 47229ddd462..d036d424705 100644 --- a/code/modules/antagonists/_common/antag_spawner.dm +++ b/code/modules/antagonists/_common/antag_spawner.dm @@ -283,3 +283,138 @@ veil_msg = span_warning("You sense an adorable presence lurking just beyond the veil...") demon_type = /mob/living/basic/demon/slaughter/laughter + +/** + * A subtype meant for 'normal' antag spawner items so as to reduce the amount of required hardcoding. + */ + +/obj/item/antag_spawner/loadout + name = "generic beacon" + desc = "A single-use beacon designed to quickly launch bad code into the field." + icon = 'icons/obj/device.dmi' + icon_state = "locator" + /// The mob type to spawn. + var/mob/living/spawn_type = /mob/living/carbon/human + /// The species type to set a human spawn to. + var/species_type = /datum/species/human + /// The applied outfit. Won't work with nonhuman spawn types. + var/datum/outfit/outfit + /// The antag datum applied + var/datum/antagonist/antag_datum + /// Style used by the droppod + var/pod_style = STYLE_SYNDICATE + /// Do we use a random subtype of the outfit? + var/use_subtypes = TRUE + /// The antag role we check if the ghosts have enabled to get the poll. + var/poll_role_check = ROLE_TRAITOR + /// The mind's special role. + var/role_to_play = ROLE_SYNDICATE_MONKEY + /// What category to ignore the poll + var/poll_ignore_category = POLL_IGNORE_SYNDICATE + /// text given when device fails to secure candidates + var/fail_text = "Unable to connect to Syndicate command. Please wait and try again later or use the beacon on your uplink to get your points refunded." + +/obj/item/antag_spawner/loadout/proc/check_usability(mob/user) + if(used) + to_chat(user, span_warning("[src] is out of power!")) + return FALSE + return TRUE + +/// Creates the drop pod the spawned_mob will be dropped by +/obj/item/antag_spawner/loadout/proc/setup_pod() + var/obj/structure/closet/supplypod/pod = new(null, pod_style) + pod.explosionSize = list(0,0,0,0) + pod.bluespace = TRUE + return pod + +/obj/item/antag_spawner/loadout/attack_self(mob/user) + if(!(check_usability(user))) + return + + to_chat(user, span_notice("You activate [src] and wait for confirmation.")) + var/list/baddie_candidates = poll_ghost_candidates("Do you want to play as a [role_to_play]?", poll_role_check, poll_role_check, 10 SECONDS, poll_ignore_category) + if(!LAZYLEN(baddie_candidates)) + to_chat(user, span_warning(fail_text)) + return + if(QDELETED(src) || !check_usability(user)) + return + used = TRUE + var/mob/dead/observer/ghostie = pick(baddie_candidates) + spawn_antag(ghostie.client, get_turf(src), user) + do_sparks(4, TRUE, src) + qdel(src) + +// For subtypes to do special things to the summoned dude. +/obj/item/antag_spawner/loadout/proc/do_special_things(mob/living/carbon/human/spawned_mob, mob/user) + return + +/obj/item/antag_spawner/loadout/spawn_antag(client/our_client, turf/T, mob/user) + var/mob/living/spawned_mob = new spawn_type() + var/obj/structure/closet/supplypod/pod = setup_pod() + our_client.prefs.safe_transfer_prefs_to(spawned_mob, is_antag = TRUE) + spawned_mob.ckey = our_client.key + var/datum/mind/op_mind = spawned_mob.mind + if(length(GLOB.newplayer_start)) // needed as hud code doesn't render huds if the atom (in this case the spawned_mob) is in nullspace, so just move the spawned_mob somewhere safe + spawned_mob.forceMove(pick(GLOB.newplayer_start)) + else + spawned_mob.forceMove(locate(1,1,1)) + + antag_datum = new() + + if(ishuman(spawned_mob)) + var/mob/living/carbon/human/human_mob = spawned_mob + human_mob.set_species(species_type) + human_mob.equipOutfit(outfit) + + op_mind.special_role = role_to_play + + do_special_things(spawned_mob, user) + + spawned_mob.forceMove(pod) + new /obj/effect/pod_landingzone(get_turf(src), pod) + +/obj/item/antag_spawner/loadout/monkey_man + name = "monkey agent beacon" + desc = "A single-use beacon designed to launch a specially-trained simian agent to the field for emergency support." + icon = 'icons/obj/device.dmi' + icon_state = "locator" + species_type = /datum/species/monkey + outfit = /datum/outfit/syndicate_monkey + antag_datum = /datum/antagonist/syndicate_monkey + use_subtypes = FALSE + poll_role_check = ROLE_TRAITOR + role_to_play = ROLE_SYNDICATE_MONKEY + poll_ignore_category = POLL_IGNORE_SYNDICATE + fail_text = "Unable to connect to the Syndicate Banana Department. Please wait and try again later or use the beacon on your uplink to get your points refunded." + +/obj/item/antag_spawner/loadout/monkey_man/do_special_things(mob/living/carbon/human/monkey_man, mob/user) + + monkey_man.fully_replace_character_name(monkey_man.real_name, pick(GLOB.syndicate_monkey_names)) + + monkey_man.dna.add_mutation(/datum/mutation/human/clever) + // Can't make them human or nonclever. At least not with the easy and boring way out. + for(var/datum/mutation/human/mutation as anything in monkey_man.dna.mutations) + mutation.mutadone_proof = TRUE + mutation.instability = 0 + + // Extra backup! + ADD_TRAIT(monkey_man, TRAIT_NO_DNA_SCRAMBLE, SPECIES_TRAIT) + // Anything else requires enough effort that they deserve it. + + monkey_man.mind.enslave_mind_to_creator(user) + + var/obj/item/implant/explosive/imp = new(src) + imp.implant(monkey_man, user) + +/datum/outfit/syndicate_monkey + name = "Syndicate Monkey Agent Kit" + + head = /obj/item/clothing/head/fedora + mask = /obj/item/clothing/mask/cigarette/syndicate + uniform = /obj/item/clothing/under/syndicate + l_pocket = /obj/item/reagent_containers/cup/soda_cans/monkey_energy + r_pocket = /obj/item/storage/fancy/cigarettes/cigpack_syndicate + internals_slot = NONE + belt = /obj/item/lighter/skull + r_hand = /obj/item/food/grown/banana + diff --git a/code/modules/antagonists/syndicate_monkey/syndicate_monkey.dm b/code/modules/antagonists/syndicate_monkey/syndicate_monkey.dm new file mode 100644 index 00000000000..eae5d558a7c --- /dev/null +++ b/code/modules/antagonists/syndicate_monkey/syndicate_monkey.dm @@ -0,0 +1,37 @@ +/datum/antagonist/syndicate_monkey + name = "\improper Syndicate Monkey" + antagpanel_category = ANTAG_GROUP_SYNDICATE + show_in_roundend = TRUE + show_in_antagpanel = TRUE + show_name_in_check_antagonists = TRUE + count_against_dynamic_roll_chance = FALSE + show_to_ghosts = TRUE + /// The antagonist's master, used for objective + var/mob/living/monky_master + +/datum/antagonist/syndicate_monkey/on_gain() + monky_master = owner.enslaved_to?.resolve() + if(monky_master) + forge_objectives(monky_master) + return ..() + +/datum/antagonist/syndicate_monkey/Destroy() + monky_master = null + return ..() + +/datum/antagonist/syndicate_monkey/greet() + . = ..() + owner.announce_objectives() + +/datum/objective/syndicate_monkey + var/mob/living/monky_master + +/datum/objective/syndicate_monkey/check_completion() + return monky_master.stat != DEAD + +/datum/antagonist/syndicate_monkey/forge_objectives(mob/monky_master) + var/datum/objective/syndicate_monkey/objective = new + objective.monky_master = monky_master + objective.explanation_text = "You are a badass monkey syndicate agent. Protect and obey all of your master [monky_master]'s orders!" + objective.owner = owner + objectives += objective diff --git a/code/modules/clothing/under/syndicate.dm b/code/modules/clothing/under/syndicate.dm index 19d5d3b93b2..20a5cda0592 100644 --- a/code/modules/clothing/under/syndicate.dm +++ b/code/modules/clothing/under/syndicate.dm @@ -8,6 +8,7 @@ alt_covers_chest = TRUE icon = 'icons/obj/clothing/under/syndicate.dmi' worn_icon = 'icons/mob/clothing/under/syndicate.dmi' + supports_variations_flags = CLOTHING_MONKEY_VARIATION /datum/armor/clothing_under/syndicate melee = 10 @@ -32,6 +33,7 @@ armor_type = /datum/armor/clothing_under/syndicate_bloodred resistance_flags = FIRE_PROOF | ACID_PROOF can_adjust = FALSE + supports_variations_flags = NONE /datum/armor/clothing_under/syndicate_bloodred melee = 10 @@ -99,6 +101,7 @@ icon_state = "tactical_suit" inhand_icon_state = "bl_suit" can_adjust = FALSE + supports_variations_flags = NONE /obj/item/clothing/under/syndicate/camo name = "camouflage fatigues" @@ -106,12 +109,14 @@ icon_state = "camogreen" inhand_icon_state = "g_suit" can_adjust = FALSE + supports_variations_flags = NONE /obj/item/clothing/under/syndicate/soviet name = "Ratnik 5 tracksuit" desc = "Badly translated labels tell you to clean this in Vodka. Great for squatting in." icon_state = "trackpants" can_adjust = FALSE + supports_variations_flags = NONE armor_type = /datum/armor/clothing_under/syndicate_soviet resistance_flags = NONE @@ -123,12 +128,14 @@ desc = "With a suit lined with this many pockets, you are ready to operate." icon_state = "syndicate_combat" can_adjust = FALSE + supports_variations_flags = NONE /obj/item/clothing/under/syndicate/rus_army name = "advanced military tracksuit" desc = "Military grade tracksuits for frontline squatting." icon_state = "rus_under" can_adjust = FALSE + supports_variations_flags = NONE armor_type = /datum/armor/clothing_under/syndicate_rus_army resistance_flags = NONE @@ -142,6 +149,7 @@ worn_icon = 'icons/mob/clothing/under/medical.dmi' icon_state = "scrubswine" can_adjust = FALSE + supports_variations_flags = NONE armor_type = /datum/armor/clothing_under/syndicate_scrubs /datum/armor/clothing_under/syndicate_scrubs diff --git a/code/modules/hydroponics/grown/banana.dm b/code/modules/hydroponics/grown/banana.dm index 64979b048cb..3b7ddbbd83c 100644 --- a/code/modules/hydroponics/grown/banana.dm +++ b/code/modules/hydroponics/grown/banana.dm @@ -191,3 +191,18 @@ var/obj/effect/decal/cleanable/food/plant_smudge/banana_smudge = new(loc) banana_smudge.color = "#ffe02f" qdel(src) + +/obj/item/food/grown/banana/bunch/monkeybomb + desc = "Am exquisite bunch of bananas. Their otherwordly plumpness seems to be hiding something." + +/obj/item/food/grown/banana/bunch/monkeybomb/examine(mob/user) + . = ..() + if(!is_simian(user)) + . += span_notice("There's a banana label on one of the 'nanas you can't quite make out the details of.") + return + . += span_notice("The banana label on this bunch indicates that monkeys can use this as a sonic grenade with a 3 second timer!") + +/obj/item/food/grown/banana/bunch/monkeybomb/attack_self(mob/user, modifiers) + if(!is_simian(user)) + return to_chat(user, span_notice("You don't really know what to do with this.")) + else start_ripening() diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm index 9b34e2924fe..df289c514dc 100644 --- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm +++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm @@ -40,8 +40,6 @@ payday_modifier = 1.5 ai_controlled_species = TRUE - - /datum/species/monkey/random_name(gender,unique,lastname) var/randname = "monkey ([rand(1,999)])" diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm index 3e286f6c58b..70e2210a4e9 100644 --- a/code/modules/projectiles/guns/ballistic/automatic.dm +++ b/code/modules/projectiles/guns/ballistic/automatic.dm @@ -146,6 +146,17 @@ mag_display = TRUE rack_sound = 'sound/weapons/gun/pistol/slide_lock.ogg' +/** + * Weak uzi for syndicate chimps. It comes in a 4 TC kit. + * Roughly 9 damage per bullet every 0.2 seconds, equaling out to downing an opponent in a bit over a second, if they have no armor. + */ +/obj/item/gun/ballistic/automatic/mini_uzi/chimpgun + name = "\improper MONK-10" + desc = "Developed by Syndicate monkeys, for syndicate Monkeys. Despite the name, this weapon resembles an Uzi significantly more than a MAC-10. Uses 9mm rounds. There's a label on the other side of the gun that says \"Do what comes natural.\"" + projectile_damage_multiplier = 0.4 + projectile_wound_bonus = -25 + pin = /obj/item/firing_pin/monkey + /obj/item/gun/ballistic/automatic/m90 name = "\improper M-90gl Carbine" desc = "A three-round burst 5.56 toploading carbine, designated 'M-90gl'. Has an attached underbarrel grenade launcher." @@ -218,10 +229,25 @@ bolt_type = BOLT_TYPE_OPEN empty_indicator = TRUE show_bolt_icon = FALSE + /// Rate of fire, set on initialize only + var/rof = 0.1 SECONDS /obj/item/gun/ballistic/automatic/tommygun/Initialize(mapload) . = ..() - AddComponent(/datum/component/automatic_fire, 0.1 SECONDS) + AddComponent(/datum/component/automatic_fire, rof) + +/** + * Weak tommygun for syndicate chimps. It comes in a 4 TC kit. + * Roughly 9 damage per bullet every 0.2 seconds, equaling out to downing an opponent in a bit over a second, if they have no armor. + */ +/obj/item/gun/ballistic/automatic/tommygun/chimpgun + name = "\improper Typewriter" + desc = "It was the best of times, it was the BLURST of times!? You stupid monkeys!" + fire_delay = 2 + rof = 0.2 SECONDS + projectile_damage_multiplier = 0.4 + projectile_wound_bonus = -25 + pin = /obj/item/firing_pin/monkey /obj/item/gun/ballistic/automatic/ar name = "\improper NT-ARG 'Boarder'" diff --git a/code/modules/projectiles/guns/ballistic/pistol.dm b/code/modules/projectiles/guns/ballistic/pistol.dm index f69494e0a18..5d4ca7d8c2b 100644 --- a/code/modules/projectiles/guns/ballistic/pistol.dm +++ b/code/modules/projectiles/guns/ballistic/pistol.dm @@ -56,6 +56,18 @@ lock_back_sound = 'sound/weapons/gun/pistol/slide_lock.ogg' bolt_drop_sound = 'sound/weapons/gun/pistol/slide_drop.ogg' +/** + * Weak 1911 for syndicate chimps. It comes in a 4 TC kit. + * 15 damage every.. second? 7 shots to kill. Not fast. + */ +/obj/item/gun/ballistic/automatic/pistol/m1911/chimpgun + name = "\improper CH1M911" + desc = "For the monkey mafioso on-the-go. Uses .45 rounds and has the distinct smell of bananas." + projectile_damage_multiplier = 0.5 + projectile_wound_bonus = -12 + pin = /obj/item/firing_pin/monkey + + /obj/item/gun/ballistic/automatic/pistol/m1911/no_mag spawnwithmagazine = FALSE diff --git a/code/modules/projectiles/pins.dm b/code/modules/projectiles/pins.dm index 6c2914b495d..45763feff04 100644 --- a/code/modules/projectiles/pins.dm +++ b/code/modules/projectiles/pins.dm @@ -373,6 +373,17 @@ suit_requirement = /obj/item/clothing/suit/bluetag tagcolor = "blue" +/obj/item/firing_pin/monkey + name = "monkeylock firing pin" + desc = "This firing pin prevents non-monkeys from firing a gun." + fail_message = "not a monkey!" + +/obj/item/firing_pin/monkey/pin_auth(mob/living/user) + if(!is_simian(user)) + playsound(get_turf(src), "sound/creatures/monkey/monkey_screech_[rand(1,7)].ogg", 75, TRUE) + return FALSE + return TRUE + /obj/item/firing_pin/Destroy() if(gun) gun.pin = null diff --git a/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm index ab1894fe04c..506bea0c659 100644 --- a/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm @@ -1247,7 +1247,7 @@ /datum/reagent/consumable/ethanol/bananahonk/on_mob_life(mob/living/carbon/drinker, seconds_per_tick, times_fired) . = ..() var/obj/item/organ/internal/liver/liver = drinker.get_organ_slot(ORGAN_SLOT_LIVER) - if((liver && HAS_TRAIT(liver, TRAIT_COMEDY_METABOLISM)) || ismonkey(drinker)) + if((liver && HAS_TRAIT(liver, TRAIT_COMEDY_METABOLISM)) || is_simian(drinker)) if(drinker.heal_bodypart_damage(brute = 1 * REM * seconds_per_tick, burn = 1 * REM * seconds_per_tick, updating_health = FALSE)) return UPDATE_MOB_HEALTH diff --git a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm index 8270b42f502..28039f8b5b6 100644 --- a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm @@ -116,7 +116,7 @@ /datum/reagent/consumable/banana/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) . = ..() var/obj/item/organ/internal/liver/liver = affected_mob.get_organ_slot(ORGAN_SLOT_LIVER) - if((liver && HAS_TRAIT(liver, TRAIT_COMEDY_METABOLISM)) || ismonkey(affected_mob)) + if((liver && HAS_TRAIT(liver, TRAIT_COMEDY_METABOLISM)) || is_simian(affected_mob)) if(affected_mob.heal_bodypart_damage(brute = 1 * REM * seconds_per_tick, burn = 1 * REM * seconds_per_tick, updating_health = FALSE)) return UPDATE_MOB_HEALTH @@ -670,7 +670,7 @@ /datum/reagent/consumable/monkey_energy/on_mob_metabolize(mob/living/affected_mob) . = ..() - if(ismonkey(affected_mob)) + if(is_simian(affected_mob)) affected_mob.add_movespeed_modifier(/datum/movespeed_modifier/reagent/monkey_energy) /datum/reagent/consumable/monkey_energy/on_mob_end_metabolize(mob/living/affected_mob) diff --git a/code/modules/uplink/uplink_items/clownops.dm b/code/modules/uplink/uplink_items/clownops.dm index 1b5948ebd05..84cf0ea3c51 100644 --- a/code/modules/uplink/uplink_items/clownops.dm +++ b/code/modules/uplink/uplink_items/clownops.dm @@ -114,6 +114,26 @@ restricted = TRUE refundable = TRUE +/datum/uplink_item/reinforcement/monkey_agent + name = "Simian Agent Reinforcements" + desc = "Call in an extremely well trained monkey secret agent from our Syndicate Banana Department. \ + They've been trained to operate machinery and can read, but they can't speak Common." + item = /obj/item/antag_spawner/loadout/monkey_man + cost = 7 + purchasable_from = UPLINK_CLOWN_OPS + restricted = TRUE + refundable = TRUE + +/datum/uplink_item/reinforcement/monkey_supplies + name = "Simian Agent Supplies" + desc = "Sometimes you need a bit more firepower than a rabid monkey. Such as a rabid, armed monkey! \ + Monkeys can unpack this kit to recieve a bag with a bargain-bin gun, ammunition, and some miscellaneous supplies." + item = /obj/item/storage/toolbox/guncase/monkeycase + cost = 4 + purchasable_from = UPLINK_CLOWN_OPS + restricted = TRUE + refundable = TRUE + /datum/uplink_item/mech/honker name = "Dark H.O.N.K." desc = "A clown combat mech equipped with bombanana peel and tearstache grenade launchers, as well as the ubiquitous HoNkER BlAsT 5000." diff --git a/code/modules/uplink/uplink_items/job.dm b/code/modules/uplink/uplink_items/job.dm index 9fe0dbe0a92..96a1c13827f 100644 --- a/code/modules/uplink/uplink_items/job.dm +++ b/code/modules/uplink/uplink_items/job.dm @@ -343,3 +343,25 @@ item = /obj/item/bee_smoker cost = 4 restricted_roles = list(JOB_BOTANIST) + +/datum/uplink_item/role_restricted/monkey_agent + name = "Simian Agent Reinforcements" + desc = "Call in an extremely well trained monkey secret agent from our Syndicate Banana Department. \ + They've been trained to operate machinery and can read, but they can't speak Common. \ + Please note that these are free-range monkeys that don't react with Mutadone." + item = /obj/item/antag_spawner/loadout/monkey_man + cost = 6 + restricted_roles = list(JOB_RESEARCH_DIRECTOR, JOB_SCIENTIST, JOB_GENETICIST, JOB_ASSISTANT, JOB_MIME, JOB_CLOWN) + restricted = TRUE + refundable = TRUE + +/datum/uplink_item/role_restricted/monkey_supplies + name = "Simian Agent Supplies" + desc = "Sometimes you need a bit more firepower than a rabid monkey. Such as a rabid, armed monkey! \ + Monkeys can unpack this kit to recieve a bag with a bargain-bin gun, ammunition, and some miscellaneous supplies." + item = /obj/item/storage/toolbox/guncase/monkeycase + cost = 4 + limited_stock = 3 + restricted_roles = list(JOB_ASSISTANT, JOB_MIME, JOB_CLOWN) + restricted = TRUE + refundable = FALSE diff --git a/icons/mob/human/species/monkey/uniform.dmi b/icons/mob/human/species/monkey/uniform.dmi index 21d70e5694f..a835629528a 100644 Binary files a/icons/mob/human/species/monkey/uniform.dmi and b/icons/mob/human/species/monkey/uniform.dmi differ diff --git a/strings/names/syndicate_monkey.txt b/strings/names/syndicate_monkey.txt new file mode 100644 index 00000000000..9b2c059a7df --- /dev/null +++ b/strings/names/syndicate_monkey.txt @@ -0,0 +1,19 @@ +Agent 9 +Agent Banana +Agent Potassium +Agent Ape +Al Chimpone +Aldo +Banana Bond +Bonobo Assassin +Caesar +Evil Monkey +Solid Simian +Tony Bananas +Koba +Murderous George +Monkey Business +Hit-Monkey +Guenter +Goku +Kill Julien diff --git a/tgstation.dme b/tgstation.dme index d4b0ff7a836..d2f7b5828c9 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3136,6 +3136,7 @@ #include "code\modules\antagonists\space_ninja\space_ninja.dm" #include "code\modules\antagonists\spiders\spiders.dm" #include "code\modules\antagonists\survivalist\survivalist.dm" +#include "code\modules\antagonists\syndicate_monkey\syndicate_monkey.dm" #include "code\modules\antagonists\traitor\balance_helper.dm" #include "code\modules\antagonists\traitor\datum_traitor.dm" #include "code\modules\antagonists\traitor\objective_category.dm"