From 2d4d23dbf1e2cc23ed2046534011561e443060f7 Mon Sep 17 00:00:00 2001 From: Timberpoes Date: Mon, 21 Aug 2023 13:00:19 +0100 Subject: [PATCH] Replaces the poster and graffiti objectives with assault and early steal & destroy ones. (#77029) ## About The Pull Request With the blessings of @Watermelon914 I am removing the two objectives for placing posters and spraying graffiti. These old objectives are not dead. Their items have moved to the Badassery section of the uplink. A box of 3 demotivational posters can be bought for 1TC with 0 rep. The spraycan can be bought for 1TC with 0 rep. In their place comes one new objective and one extended objective. The new objective is Assault a Crewmember. This objective requires you to attack the specified target 2-5 times (random on objective generation). It tallies from any attack that filters through the `/datum/element/relay_attackers` element and has an "attacker" associated with it. Although it asks you not to kill the other player, it doesn't fail if you kill them. I have expanded the low-risk theft objectives with items like a mime mask, lawyer badge and a fake moustache (commonly on cooks). Finally, I've added a very low level set of steal-and-destroy objectives aimed at some items that will require a bit of basic breaking and entering, and the destruction of which may hurt crew morale. ``` /datum/objective_item/steal/traitor/donut_box /datum/objective_item/steal/traitor/rpd /datum/objective_item/steal/traitor/space_law /datum/objective_item/steal/traitor/granted_stamp /datum/objective_item/steal/traitor/denied_stamp /datum/objective_item/steal/traitor/lizard_plush /datum/objective_item/steal/traitor/moth_plush /datum/objective_item/steal/traitor/insuls ``` This PR also fixes clown shoes missing a proc override to allow them to actually register as a theft objective. ![image](https://github.com/tgstation/tgstation/assets/24975989/775d46cf-f40a-43e5-9bf1-3aa4a31d436e) ![image](https://github.com/tgstation/tgstation/assets/24975989/66c77815-1f2b-4dfb-99c6-b8f2e0061654) ![image](https://github.com/tgstation/tgstation/assets/24975989/85d3878a-c598-4ec0-9bb1-920380a004c6) ## Why It's Good For The Game Basically my discussion with Watermelon focused on the idea that the graffiti and poster objectives weren't really crimes. They baited antagonists into very passive play early-game. These new replacements encourage a more antagonistic playstyle. Starting fights plus B&E are two bread-and-butter play paradigms for antaggery. Giving a few early game theft + destroy options with a mix of impactful items (like insuls and RPDs) versus more symbolic or emotive items (plushies, donut boxes, Cargonia stamps) gets antagonists out and about in the station, warming themselves up. And having an objective to assault players (even if you don't kill them) allows cheeky antags with a penchant for shittery to start fights with players and start genuinely impacting the shift, involving sec and drawing players into their antaggery. Both of these natually ease players into the more substantive theft and murder objectives. The existing spray and posters are actually thematically super cool. Traitors now have even more access to them since they can be bought for 1TC per spraycan/3-pack of posters. This lets antags with TC to spare run gimmicks around them and adds extra fun to the Badassery section. ## Changelog :cl: del: Traitor objectives to place posters and graffiti the station have been removed. add: The items associated with the poster and graffiti objectives can now be purchased from the Badassery section of the uplink. The posters come in a box of 3 for 1TC, and the spraycans are 1TC each. add: Adds a new Assault traitor objective, requiring you to the attack the target a few times without needing to kill them. Earn TC and reputation by starting barroom fights and bait players into escalation battles for fun and profit. add: Expands low-risk steal objectives to include the Chef's fake moustache, Lawyer's badge, and Mime's mask. add: Adds brand new shift start Steal & Destroy objectives for early breaking and entering. Smash your way into a sec checkpoint to grab a Space Law book, engineering to grab some insulated gloves or the psych office to kidnap their moth plush. fix: Fixes an issue where the steal clown shoes objective would never be valid. /:cl: --- .../signals_atom/signals_atom_attack.dm | 2 + code/datums/elements/relay_attackers.dm | 25 ++-- code/game/gamemodes/objective_items.dm | 120 ++++++++++++++++ .../objects/effects/poster_demotivational.dm} | 83 ----------- .../game/objects/items/storage/uplink_kits.dm | 11 ++ .../objects/items/syndie_spraycan.dm} | 89 ------------ .../crates_lockers/closets/job_closets.dm | 3 + .../closets/secure/engineering.dm | 17 ++- .../traitor/objectives/demoralise_assault.dm | 133 ++++++++++++++++++ .../traitor/objectives/demoralise_crew.dm | 53 ------- .../traitor/objectives/destroy_item.dm | 21 +++ .../antagonists/traitor/objectives/steal.dm | 3 + code/modules/mining/mine_items.dm | 6 +- code/modules/uplink/uplink_items/badass.dm | 13 ++ tgstation.dme | 6 +- 15 files changed, 344 insertions(+), 241 deletions(-) rename code/{modules/antagonists/traitor/objectives/demoralise_poster.dm => game/objects/effects/poster_demotivational.dm} (53%) rename code/{modules/antagonists/traitor/objectives/demoralise_graffiti.dm => game/objects/items/syndie_spraycan.dm} (68%) create mode 100644 code/modules/antagonists/traitor/objectives/demoralise_assault.dm delete mode 100644 code/modules/antagonists/traitor/objectives/demoralise_crew.dm diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm index d0a7004b561..d47833f84c0 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm @@ -62,3 +62,5 @@ #define ATTACKER_STAMINA_ATTACK (1<<0) ///the attacker is shoving the source #define ATTACKER_SHOVING (1<<1) + /// The attack is a damaging-type attack + #define ATTACKER_DAMAGING_ATTACK (1<<2) diff --git a/code/datums/elements/relay_attackers.dm b/code/datums/elements/relay_attackers.dm index 307732c46ed..9bae3beb7e5 100644 --- a/code/datums/elements/relay_attackers.dm +++ b/code/datums/elements/relay_attackers.dm @@ -34,18 +34,25 @@ /datum/element/relay_attackers/proc/after_attackby(atom/target, obj/item/weapon, mob/attacker) SIGNAL_HANDLER if(weapon.force) - relay_attacker(target, attacker, weapon.damtype == STAMINA ? ATTACKER_STAMINA_ATTACK : NONE) + relay_attacker(target, attacker, weapon.damtype == STAMINA ? ATTACKER_STAMINA_ATTACK : ATTACKER_DAMAGING_ATTACK) /datum/element/relay_attackers/proc/on_attack_generic(atom/target, mob/living/attacker, list/modifiers) SIGNAL_HANDLER - var/shoving = LAZYACCESS(modifiers, RIGHT_CLICK) ? ATTACKER_SHOVING : NONE - if(attacker.combat_mode || shoving) - relay_attacker(target, attacker, shoving) + + // Check for a shove. + if(LAZYACCESS(modifiers, RIGHT_CLICK)) + relay_attacker(target, attacker, ATTACKER_SHOVING) + return + + // Else check for combat mode. + if(attacker.combat_mode) + relay_attacker(target, attacker, ATTACKER_DAMAGING_ATTACK) + return /datum/element/relay_attackers/proc/on_attack_npc(atom/target, mob/living/attacker) SIGNAL_HANDLER if(attacker.melee_damage_upper > 0) - relay_attacker(target, attacker) + relay_attacker(target, attacker, ATTACKER_DAMAGING_ATTACK) /// Even if another component blocked this hit, someone still shot at us /datum/element/relay_attackers/proc/on_bullet_act(atom/target, list/bullet_args, obj/projectile/hit_projectile) @@ -54,7 +61,7 @@ return if(!ismob(hit_projectile.firer)) return - relay_attacker(target, hit_projectile.firer, hit_projectile.damage_type == STAMINA ? ATTACKER_STAMINA_ATTACK : NONE) + relay_attacker(target, hit_projectile.firer, hit_projectile.damage_type == STAMINA ? ATTACKER_STAMINA_ATTACK : ATTACKER_DAMAGING_ATTACK) /// Even if another component blocked this hit, someone still threw something /datum/element/relay_attackers/proc/on_hitby(atom/target, atom/movable/hit_atom, datum/thrownthing/throwingdatum) @@ -67,15 +74,15 @@ var/mob/thrown_by = hit_item.thrownby?.resolve() if(!ismob(thrown_by)) return - relay_attacker(target, thrown_by, hit_item.damtype == STAMINA ? ATTACKER_STAMINA_ATTACK : NONE) + relay_attacker(target, thrown_by, hit_item.damtype == STAMINA ? ATTACKER_STAMINA_ATTACK : ATTACKER_DAMAGING_ATTACK) /datum/element/relay_attackers/proc/on_attack_hulk(atom/target, mob/attacker) SIGNAL_HANDLER - relay_attacker(target, attacker) + relay_attacker(target, attacker, ATTACKER_DAMAGING_ATTACK) /datum/element/relay_attackers/proc/on_attack_mech(atom/target, obj/vehicle/sealed/mecha/mecha_attacker, mob/living/pilot) SIGNAL_HANDLER - relay_attacker(target, mecha_attacker) + relay_attacker(target, mecha_attacker, ATTACKER_DAMAGING_ATTACK) /// Send out a signal identifying whoever just attacked us (usually a mob but sometimes a mech or turret) /datum/element/relay_attackers/proc/relay_attacker(atom/victim, atom/attacker, attack_flags) diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm index f4c4c800c9a..caa0da143f5 100644 --- a/code/game/gamemodes/objective_items.dm +++ b/code/game/gamemodes/objective_items.dm @@ -124,6 +124,40 @@ targetitem = /obj/item/clothing/shoes/clown_shoes excludefromjob = list(JOB_CLOWN, JOB_CARGO_TECHNICIAN, JOB_QUARTERMASTER) item_owner = list(JOB_CLOWN) + exists_on_map = TRUE + +/obj/item/clothing/shoes/clown_shoes/add_stealing_item_objective() + return add_item_to_steal(src, /obj/item/clothing/shoes/clown_shoes) + +/datum/objective_item/steal/traitor/mime_mask + name = "the mime's mask" + targetitem = /obj/item/clothing/mask/gas/mime + excludefromjob = list(JOB_MIME, JOB_CARGO_TECHNICIAN, JOB_QUARTERMASTER) + item_owner = list(JOB_MIME) + exists_on_map = TRUE + +/obj/item/clothing/mask/gas/mime/add_stealing_item_objective() + return add_item_to_steal(src, /obj/item/clothing/mask/gas/mime) + +/datum/objective_item/steal/traitor/pka + name = "a protokinetic accelerator" + targetitem = /obj/item/gun/energy/recharge/kinetic_accelerator + excludefromjob = list(JOB_SHAFT_MINER, JOB_CARGO_TECHNICIAN, JOB_QUARTERMASTER) + item_owner = list(JOB_SHAFT_MINER) + exists_on_map = TRUE + +/obj/item/gun/energy/recharge/kinetic_accelerator/add_stealing_item_objective() + return add_item_to_steal(src, /obj/item/gun/energy/recharge/kinetic_accelerator) + +/datum/objective_item/steal/traitor/chef_moustache + name = "a fancy fake moustache" + targetitem = /obj/item/clothing/mask/fakemoustache/italian + excludefromjob = list(JOB_COOK, JOB_HEAD_OF_PERSONNEL, JOB_CARGO_TECHNICIAN, JOB_QUARTERMASTER) + item_owner = list(JOB_COOK) + exists_on_map = TRUE + +/obj/item/clothing/mask/fakemoustache/italian/add_stealing_item_objective() + return add_item_to_steal(src, /obj/item/clothing/mask/fakemoustache/italian) /datum/objective_item/steal/traitor/det_revolver name = "detective's revolver" @@ -134,6 +168,16 @@ /obj/item/gun/ballistic/revolver/c38/detective/add_stealing_item_objective() return add_item_to_steal(src, /obj/item/gun/ballistic/revolver/c38/detective) +/datum/objective_item/steal/traitor/lawyers_badge + name = "the lawyer's badge" + targetitem = /obj/item/clothing/accessory/lawyers_badge + excludefromjob = list(JOB_LAWYER) + item_owner = list(JOB_LAWYER) + exists_on_map = TRUE + +/obj/item/clothing/accessory/lawyers_badge/add_stealing_item_objective() + return add_item_to_steal(src, /obj/item/clothing/accessory/lawyers_badge) + /datum/objective_item/steal/traitor/chief_engineer_belt name = "the chief engineer's belt" targetitem = /obj/item/storage/belt/utility/chief @@ -401,3 +445,79 @@ /obj/item/blackbox/add_stealing_item_objective() return add_item_to_steal(src, /obj/item/blackbox) + + +// A number of special early-game steal objectives intended to be used with the steal-and-destroy objective. +// They're basically items of utility or emotional value that may be found on many players or lying around the station. +/datum/objective_item/steal/traitor/insuls + name = "insulated gloves" + targetitem = /obj/item/clothing/gloves/color/yellow + excludefromjob = list(JOB_CARGO_TECHNICIAN, JOB_QUARTERMASTER, JOB_ATMOSPHERIC_TECHNICIAN, JOB_STATION_ENGINEER, JOB_CHIEF_ENGINEER) + item_owner = list(JOB_STATION_ENGINEER, JOB_CHIEF_ENGINEER) + exists_on_map = TRUE + +/obj/item/clothing/gloves/color/yellow/add_stealing_item_objective() + return add_item_to_steal(src, /obj/item/clothing/gloves/color/yellow) + +/datum/objective_item/steal/traitor/moth_plush + name = "cute moth plush toy" + targetitem = /obj/item/toy/plush/moth + excludefromjob = list(JOB_PSYCHOLOGIST, JOB_PARAMEDIC, JOB_CHEMIST, JOB_MEDICAL_DOCTOR, JOB_VIROLOGIST, JOB_CHIEF_MEDICAL_OFFICER, JOB_CORONER) + exists_on_map = TRUE + +/obj/item/toy/plush/moth/add_stealing_item_objective() + return add_item_to_steal(src, /obj/item/toy/plush/moth) + +/datum/objective_item/steal/traitor/lizard_plush + name = "cute lizard plush toy" + targetitem = /obj/item/toy/plush/lizard_plushie + exists_on_map = TRUE + +/obj/item/toy/plush/lizard_plushie/add_stealing_item_objective() + return add_item_to_steal(src, /obj/item/toy/plush/lizard_plushie) + +/datum/objective_item/steal/traitor/denied_stamp + name = "cargo's denied stamp" + targetitem = /obj/item/stamp/denied + excludefromjob = list(JOB_CARGO_TECHNICIAN, JOB_QUARTERMASTER, JOB_SHAFT_MINER) + exists_on_map = TRUE + +/obj/item/stamp/denied/add_stealing_item_objective() + return add_item_to_steal(src, /obj/item/stamp/denied) + +/datum/objective_item/steal/traitor/granted_stamp + name = "cargo's granted stamp" + targetitem = /obj/item/stamp/granted + excludefromjob = list(JOB_CARGO_TECHNICIAN, JOB_QUARTERMASTER, JOB_SHAFT_MINER) + exists_on_map = TRUE + +/obj/item/stamp/granted/add_stealing_item_objective() + return add_item_to_steal(src, /obj/item/stamp/granted) + +/datum/objective_item/steal/traitor/space_law + name = "a book on space law" + targetitem = /obj/item/book/manual/wiki/security_space_law + excludefromjob = list(JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_HEAD_OF_SECURITY, JOB_LAWYER, JOB_DETECTIVE) + exists_on_map = TRUE + +/obj/item/book/manual/wiki/security_space_law/add_stealing_item_objective() + return add_item_to_steal(src, /obj/item/book/manual/wiki/security_space_law) + +/datum/objective_item/steal/traitor/rpd + name = "rapid pipe dispenser" + targetitem = /obj/item/pipe_dispenser + excludefromjob = list(JOB_ATMOSPHERIC_TECHNICIAN, JOB_STATION_ENGINEER, JOB_CHIEF_ENGINEER, JOB_SCIENTIST, JOB_RESEARCH_DIRECTOR, JOB_GENETICIST, JOB_ROBOTICIST) + item_owner = list(JOB_CHIEF_ENGINEER) + exists_on_map = TRUE + +/obj/item/pipe_dispenser/add_stealing_item_objective() + return add_item_to_steal(src, /obj/item/pipe_dispenser) + +/datum/objective_item/steal/traitor/donut_box + name = "a box of prized donuts" + targetitem = /obj/item/storage/fancy/donut_box + excludefromjob = list(JOB_CAPTAIN, JOB_CHIEF_ENGINEER, JOB_HEAD_OF_PERSONNEL, JOB_HEAD_OF_SECURITY, JOB_QUARTERMASTER, JOB_CHIEF_MEDICAL_OFFICER, JOB_RESEARCH_DIRECTOR, JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_LAWYER, JOB_DETECTIVE) + exists_on_map = TRUE + +/obj/item/storage/fancy/donut_box/add_stealing_item_objective() + return add_item_to_steal(src, /obj/item/storage/fancy/donut_box) diff --git a/code/modules/antagonists/traitor/objectives/demoralise_poster.dm b/code/game/objects/effects/poster_demotivational.dm similarity index 53% rename from code/modules/antagonists/traitor/objectives/demoralise_poster.dm rename to code/game/objects/effects/poster_demotivational.dm index 868c8a14266..08e46b6af63 100644 --- a/code/modules/antagonists/traitor/objectives/demoralise_poster.dm +++ b/code/game/objects/effects/poster_demotivational.dm @@ -1,86 +1,3 @@ -/datum/traitor_objective/demoralise/poster - name = "Sow doubt among the crew %VIEWS% times using Syndicate propaganda." - description = "Use the button below to materialize a pack of posters, \ - which will demoralise nearby crew members (especially those in positions of authority). \ - If your posters are destroyed before they are sufficiently upset, this objective will fail. \ - Try hiding some broken glass behind your poster before you hang it to give \ - do-gooders who try to take it down a hard time!" - - progression_minimum = 0 MINUTES - progression_maximum = 30 MINUTES - progression_reward = list(4 MINUTES, 8 MINUTES) - telecrystal_reward = list(0, 1) - - duplicate_type = /datum/traitor_objective/demoralise/poster - /// Have we handed out a box of stuff yet? - var/granted_posters = FALSE - /// All of the posters the traitor gets, if this list is empty they've failed - var/list/obj/structure/sign/poster/traitor/posters = list() - -/datum/traitor_objective/demoralise/poster/generate_ui_buttons(mob/user) - var/list/buttons = list() - if (!granted_posters) - buttons += add_ui_button("", "Pressing this will materialize a box of posters in your hand.", "wifi", "summon_gear") - else - buttons += add_ui_button("[length(posters)] posters remaining", "This many propaganda posters remain active somewhere on the station.", "box", "none") - buttons += add_ui_button("[demoralised_crew_events] / [demoralised_crew_required] propagandised", "This many crew have been exposed to propaganda, out of a required [demoralised_crew_required].", "wifi", "none") - return buttons - -#define POSTERS_PROVIDED 3 - -/datum/traitor_objective/demoralise/poster/ui_perform_action(mob/living/user, action) - . = ..() - switch(action) - if ("summon_gear") - if (granted_posters) - return - - granted_posters = TRUE - var/obj/item/storage/box/syndie_kit/posterbox = new(user.drop_location()) - for(var/i in 1 to POSTERS_PROVIDED) - var/obj/item/poster/traitor/added_poster = new /obj/item/poster/traitor(posterbox) - var/obj/structure/sign/poster/traitor/poster_when_placed = added_poster.poster_structure - posters += poster_when_placed - RegisterSignal(poster_when_placed, COMSIG_DEMORALISING_EVENT, PROC_REF(on_mood_event)) - RegisterSignal(poster_when_placed, COMSIG_POSTER_TRAP_SUCCEED, PROC_REF(on_triggered_trap)) - RegisterSignal(poster_when_placed, COMSIG_QDELETING, PROC_REF(on_poster_destroy)) - - user.put_in_hands(posterbox) - posterbox.balloon_alert(user, "the box materializes in your hand") - -#undef POSTERS_PROVIDED - -/datum/traitor_objective/demoralise/poster/ungenerate_objective() - for (var/poster in posters) - UnregisterSignal(poster, COMSIG_DEMORALISING_EVENT) - UnregisterSignal(poster, COMSIG_QDELETING) - posters.Cut() - return ..() - -/** - * Called if someone gets glass stuck in their hand from one of your posters. - * - * Arguments - * * victim - A mob who just got something stuck in their hand. - */ -/datum/traitor_objective/demoralise/poster/proc/on_triggered_trap(datum/source, mob/victim) - SIGNAL_HANDLER - on_mood_event(victim.mind) - -/** - * Handles a poster being destroyed, increasing your progress towards failure. - * - * Arguments - * * poster - A poster which someone just ripped up. - */ -/datum/traitor_objective/demoralise/poster/proc/on_poster_destroy(obj/structure/sign/poster/traitor/poster) - SIGNAL_HANDLER - posters.Remove(poster) - UnregisterSignal(poster, COMSIG_DEMORALISING_EVENT) - if (length(posters) <= 0) - to_chat(handler.owner, span_warning("The trackers on your propaganda posters have stopped responding.")) - fail_objective(penalty_cost = telecrystal_penalty) - /obj/item/poster/traitor name = "random traitor poster" poster_type = /obj/structure/sign/poster/traitor/random diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm index 471df69fdd1..8f95ab55dfb 100644 --- a/code/game/objects/items/storage/uplink_kits.dm +++ b/code/game/objects/items/storage/uplink_kits.dm @@ -778,6 +778,17 @@ to_chat(target, span_userdanger("You're no longer identified as a nuclear operative! You are free to follow any valid goals you wish, even continuing to secure the disk. Just make sure neither any turrets nor operatives kill you on sight.")) return TRUE +/obj/item/storage/box/syndie_kit/poster_box + name = "syndicate poster pack" + desc = "Contains a variety of demotivational posters to ensure minimum productivity for the crew of any Nanotrasen station." + + /// Number of posters this box contains when spawning. + var/poster_count = 3 + +/obj/item/storage/box/syndie_kit/poster_box/PopulateContents() + for(var/i in 1 to poster_count) + new /obj/item/poster/traitor(src) + #undef KIT_RECON #undef KIT_BLOODY_SPAI #undef KIT_STEALTHY diff --git a/code/modules/antagonists/traitor/objectives/demoralise_graffiti.dm b/code/game/objects/items/syndie_spraycan.dm similarity index 68% rename from code/modules/antagonists/traitor/objectives/demoralise_graffiti.dm rename to code/game/objects/items/syndie_spraycan.dm index 5be1d609126..78ffb6a4772 100644 --- a/code/modules/antagonists/traitor/objectives/demoralise_graffiti.dm +++ b/code/game/objects/items/syndie_spraycan.dm @@ -1,92 +1,3 @@ -/datum/traitor_objective/demoralise/graffiti - name = "Sow doubt among the crew %VIEWS% times using Syndicate graffiti." - description = "Use the button below to materialize a seditious spray can, \ - and use it to draw a 3x3 tag in a place where people will come across it. \ - Special syndicate sealing agent ensures that it can't be removed for \ - five minutes following application, and it's slippery too! \ - People seeing or slipping on your graffiti grants progress towards success." - - progression_minimum = 0 MINUTES - progression_maximum = 30 MINUTES - progression_reward = list(4 MINUTES, 8 MINUTES) - telecrystal_reward = list(0, 1) - - duplicate_type = /datum/traitor_objective/demoralise/graffiti - /// Have we given out a spray can yet? - var/obtained_spray = FALSE - /// Graffiti 'rune' which we will be drawing - var/obj/effect/decal/cleanable/traitor_rune/rune - -/datum/traitor_objective/demoralise/graffiti/generate_ui_buttons(mob/user) - var/list/buttons = list() - if (!obtained_spray) - buttons += add_ui_button("", "Pressing this will materialize a syndicate spraycan in your hand.", "wifi", "summon_gear") - else - buttons += add_ui_button("[demoralised_crew_events] / [demoralised_crew_required] propagandised", "This many crew have been exposed to propaganda, out of a required [demoralised_crew_required].", "wifi", "none") - return buttons - -/datum/traitor_objective/demoralise/graffiti/ui_perform_action(mob/living/user, action) - . = ..() - switch(action) - if ("summon_gear") - if (obtained_spray) - return - - obtained_spray = TRUE - var/obj/item/traitor_spraycan/spray = new(user.drop_location()) - user.put_in_hands(spray) - spray.balloon_alert(user, "the spraycan materializes in your hand") - - RegisterSignal(spray, COMSIG_QDELETING, PROC_REF(on_spray_destroyed)) - RegisterSignal(spray, COMSIG_TRAITOR_GRAFFITI_DRAWN, PROC_REF(on_rune_complete)) - -/** - * Called when the spray can is deleted. - * If it's already been expended we don't care, if it hasn't you just made your objective impossible.area - * - * Arguments - * * spray - the spraycan which was just deleted - */ -/datum/traitor_objective/demoralise/graffiti/proc/on_spray_destroyed() - SIGNAL_HANDLER - // You fucked up pretty bad if you let this happen - if (!rune) - fail_objective(penalty_cost = telecrystal_penalty) - -/** - * Called when you managed to draw a traitor rune. - * Sets up tracking for objective progress, and unregisters signals for the spraycan because we don't care about it any more. - * - * Arguments - * * drawn_rune - graffiti 'rune' which was just drawn. - */ -/datum/traitor_objective/demoralise/graffiti/proc/on_rune_complete(atom/spray, obj/effect/decal/cleanable/traitor_rune/drawn_rune) - SIGNAL_HANDLER - rune = drawn_rune - UnregisterSignal(spray, COMSIG_QDELETING) - UnregisterSignal(spray, COMSIG_TRAITOR_GRAFFITI_DRAWN) - RegisterSignal(drawn_rune, COMSIG_QDELETING, PROC_REF(on_rune_destroyed)) - RegisterSignal(drawn_rune, COMSIG_DEMORALISING_EVENT, PROC_REF(on_mood_event)) - RegisterSignal(drawn_rune, COMSIG_TRAITOR_GRAFFITI_SLIPPED, PROC_REF(on_mood_event)) - -/** - * Called when your traitor rune is destroyed. If you haven't suceeded by now, you fail.area - * - * Arguments - * * rune - the rune which just got destroyed. - */ -/datum/traitor_objective/demoralise/graffiti/proc/on_rune_destroyed(obj/effect/decal/cleanable/traitor_rune/rune) - SIGNAL_HANDLER - fail_objective(penalty_cost = telecrystal_penalty) - -/datum/traitor_objective/demoralise/graffiti/ungenerate_objective() - if (rune) - UnregisterSignal(rune, COMSIG_QDELETING) - UnregisterSignal(rune, COMSIG_DEMORALISING_EVENT) - UnregisterSignal(rune, COMSIG_TRAITOR_GRAFFITI_SLIPPED) - rune = null - return ..() - // Extending the existing spraycan item was more trouble than it was worth, I don't want or need this to be able to draw arbitrary shapes. /obj/item/traitor_spraycan name = "seditious spraycan" diff --git a/code/game/objects/structures/crates_lockers/closets/job_closets.dm b/code/game/objects/structures/crates_lockers/closets/job_closets.dm index 7e70f27d6e7..14d201e07de 100644 --- a/code/game/objects/structures/crates_lockers/closets/job_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/job_closets.dm @@ -89,6 +89,9 @@ new /obj/item/clothing/suit/toggle/lawyer/black(src) new /obj/item/clothing/shoes/laceup(src) new /obj/item/clothing/shoes/laceup(src) + +/obj/structure/closet/lawcloset/populate_contents_immediate() + . = ..() new /obj/item/clothing/accessory/lawyers_badge(src) new /obj/item/clothing/accessory/lawyers_badge(src) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm index be49ebd08c3..b4dcb9ccb5e 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm @@ -13,7 +13,7 @@ new /obj/item/holosign_creator/atmos(src) new /obj/item/assembly/flash/handheld(src) new /obj/item/door_remote/chief_engineer(src) - new /obj/item/pipe_dispenser(src) + new /obj/item/circuitboard/machine/techfab/department/engineering(src) new /obj/item/extinguisher/advanced(src) new /obj/item/storage/photo_album/ce(src) @@ -24,6 +24,7 @@ // Traitor steal objective new /obj/item/areaeditor/blueprints(src) + new /obj/item/pipe_dispenser(src) /obj/structure/closet/secure_closet/engineering_electrical name = "electrical supplies locker" @@ -34,13 +35,18 @@ /obj/structure/closet/secure_closet/engineering_electrical/PopulateContents() ..() var/static/items_inside = list( - /obj/item/clothing/gloves/color/yellow = 2, /obj/item/inducer = 2, /obj/item/storage/toolbox/electrical = 3, /obj/item/electronics/apc = 3, /obj/item/multitool = 3) generate_items_inside(items_inside,src) +/obj/structure/closet/secure_closet/engineering_electrical/populate_contents_immediate() + . = ..() + + new /obj/item/clothing/gloves/color/yellow(src) + new /obj/item/clothing/gloves/color/yellow(src) + /obj/structure/closet/secure_closet/engineering_welding name = "welding supplies locker" req_access = list(ACCESS_ENGINE_EQUIP) @@ -79,7 +85,7 @@ /obj/structure/closet/secure_closet/atmospherics/PopulateContents() ..() new /obj/item/radio/headset/headset_eng(src) - new /obj/item/pipe_dispenser(src) + new /obj/item/storage/toolbox/mechanical(src) new /obj/item/tank/internals/emergency_oxygen/engi(src) new /obj/item/holosign_creator/atmos(src) @@ -90,3 +96,8 @@ new /obj/item/clothing/head/utility/hardhat/welding/atmos(src) new /obj/item/clothing/glasses/meson/engine/tray(src) new /obj/item/extinguisher/advanced(src) + +/obj/structure/closet/secure_closet/atmospherics/populate_contents_immediate() + . = ..() + + new /obj/item/pipe_dispenser(src) diff --git a/code/modules/antagonists/traitor/objectives/demoralise_assault.dm b/code/modules/antagonists/traitor/objectives/demoralise_assault.dm new file mode 100644 index 00000000000..095c646cb99 --- /dev/null +++ b/code/modules/antagonists/traitor/objectives/demoralise_assault.dm @@ -0,0 +1,133 @@ +/datum/traitor_objective_category/demoralise + name = "Demoralise Crew" + objectives = list( + /datum/traitor_objective/target_player/assault = 1, + /datum/traitor_objective/destroy_item/demoralise = 1, + ) + weight = OBJECTIVE_WEIGHT_UNLIKELY + +/datum/traitor_objective/target_player/assault + name = "Assault %TARGET% the %JOB TITLE%" + description = "%TARGET% has been identified as a potential future agent. \ + Pick a fight and give them a good beating. \ + %COUNT% hits should reduce their morale and have them questioning their loyalties. \ + Try not to kill them just yet, we may want to recruit them in the future." + + abstract_type = /datum/traitor_objective/target_player + duplicate_type = /datum/traitor_objective/target_player + + progression_minimum = 0 MINUTES + progression_maximum = 30 MINUTES + progression_reward = list(4 MINUTES, 8 MINUTES) + telecrystal_reward = list(0, 1) + + /// Min attacks required to pass the objective. Picked at random between this and max. + var/min_attacks_required = 2 + /// Max attacks required to pass the objective. Picked at random between this and min. + var/max_attacks_required = 5 + /// The random number picked for the number of required attacks to pass this objective. + var/attacks_required = 0 + /// Total number of successful attacks recorded. + var/attacks_inflicted = 0 + +/datum/traitor_objective/target_player/assault/on_objective_taken(mob/user) + . = ..() + + target.AddElement(/datum/element/relay_attackers) + RegisterSignal(target, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(on_attacked)) + +/datum/traitor_objective/target_player/assault/proc/on_attacked(mob/source, mob/living/attacker, attack_flags) + SIGNAL_HANDLER + + // Only care about attacks from the objective's owner. + if(attacker != handler.owner.current) + return + + // We want some sort of damaging attack to trigger this, rather than shoves and non-lethals. + if(!(attack_flags & ATTACKER_DAMAGING_ATTACK)) + return + + attacks_inflicted++ + + if(attacks_inflicted == attacks_required) + succeed_objective() + +/datum/traitor_objective/target_player/assault/ungenerate_objective() + UnregisterSignal(target, COMSIG_ATOM_WAS_ATTACKED) + UnregisterSignal(target, COMSIG_LIVING_DEATH) + UnregisterSignal(target, COMSIG_QDELETING) + + target = null + +/datum/traitor_objective/target_player/assault/generate_objective(datum/mind/generating_for, list/possible_duplicates) + var/list/already_targeting = list() //List of minds we're already targeting. The possible_duplicates is a list of objectives, so let's not mix things + for(var/datum/objective/task as anything in handler.primary_objectives) + if(!istype(task.target, /datum/mind)) + continue + already_targeting += task.target //Removing primary objective kill targets from the list + + var/list/possible_targets = list() + + for(var/datum/mind/possible_target as anything in get_crewmember_minds()) + if(possible_target in already_targeting) + continue + + if(possible_target == generating_for) + continue + + if(!ishuman(possible_target.current)) + continue + + if(possible_target.current.stat == DEAD) + continue + + if(possible_target.has_antag_datum(/datum/antagonist/traitor)) + continue + + possible_targets += possible_target + + for(var/datum/traitor_objective/target_player/objective as anything in possible_duplicates) + possible_targets -= objective.target?.mind + + if(generating_for.late_joiner) + var/list/all_possible_targets = possible_targets.Copy() + for(var/datum/mind/possible_target as anything in all_possible_targets) + if(!possible_target.late_joiner) + possible_targets -= possible_target + if(!possible_targets.len) + possible_targets = all_possible_targets + + if(!possible_targets.len) + return FALSE + + var/datum/mind/target_mind = pick(possible_targets) + + target = target_mind.current + replace_in_name("%TARGET%", target.real_name) + replace_in_name("%JOB TITLE%", target_mind.assigned_role.title) + + attacks_required = rand(min_attacks_required, max_attacks_required) + replace_in_name("%COUNT%", attacks_required) + + RegisterSignal(target, COMSIG_LIVING_DEATH, PROC_REF(on_target_death)) + RegisterSignal(target, COMSIG_QDELETING, PROC_REF(on_target_qdeleted)) + + return TRUE + +/datum/traitor_objective/target_player/assault/generate_ui_buttons(mob/user) + var/list/buttons = list() + if(attacks_required > attacks_inflicted) + buttons += add_ui_button("[attacks_required - attacks_inflicted]", "This tells you how many more times you have to attack the target player to succeed.", "hand-rock-o", "none") + return buttons + +/datum/traitor_objective/target_player/assault/proc/on_target_qdeleted() + SIGNAL_HANDLER + + //don't take an objective target of someone who is already obliterated + fail_objective() + +/datum/traitor_objective/target_player/assault/proc/on_target_death() + SIGNAL_HANDLER + + //don't take an objective target of someone who is already dead + fail_objective() diff --git a/code/modules/antagonists/traitor/objectives/demoralise_crew.dm b/code/modules/antagonists/traitor/objectives/demoralise_crew.dm deleted file mode 100644 index 4529273f5e2..00000000000 --- a/code/modules/antagonists/traitor/objectives/demoralise_crew.dm +++ /dev/null @@ -1,53 +0,0 @@ -#define MAX_CREW_RATIO 0.33 -#define MIN_CREW_DEMORALISED 8 -#define MAX_CREW_DEMORALISED 16 - -/datum/traitor_objective_category/demoralise - name = "Demoralise Crew" - objectives = list( - /datum/traitor_objective/demoralise/poster = 2, - /datum/traitor_objective/demoralise/graffiti = 1, - ) - weight = OBJECTIVE_WEIGHT_UNLIKELY - -/datum/traitor_objective/demoralise - name = "Debug your code." - description = "If you actually get this objective someone fucked up." - - abstract_type = /datum/traitor_objective/demoralise - - /// How many 'mood events' are required? - var/demoralised_crew_required = 0 - /// How many 'mood events' have happened so far? - var/demoralised_crew_events = 0 - -/datum/traitor_objective/demoralise/can_generate_objective(datum/mind/generating_for, list/possible_duplicates) - if(length(possible_duplicates) > 0) - return FALSE - return TRUE - -/datum/traitor_objective/demoralise/generate_objective(datum/mind/generating_for, list/possible_duplicates) - demoralised_crew_required = (clamp(rand(MIN_CREW_DEMORALISED, length(get_crewmember_minds()) * MAX_CREW_RATIO), MIN_CREW_DEMORALISED, MAX_CREW_DEMORALISED)) - replace_in_name("%VIEWS%", demoralised_crew_required) - return TRUE - -/** - * Handles an event which increases your progress towards success. - * - * Arguments - * * source - Source atom of the signal. - * * victim - Mind of whoever it was you just triggered some kind of effect on. - */ -/datum/traitor_objective/demoralise/proc/on_mood_event(atom/source, datum/mind/victim) - SIGNAL_HANDLER - if (victim == handler.owner) - return - - demoralised_crew_events++ - if (demoralised_crew_events >= demoralised_crew_required) - to_chat(handler.owner, span_nicegreen("The crew look despondent. Mission accomplished.")) - succeed_objective() - -#undef MAX_CREW_RATIO -#undef MIN_CREW_DEMORALISED -#undef MAX_CREW_DEMORALISED diff --git a/code/modules/antagonists/traitor/objectives/destroy_item.dm b/code/modules/antagonists/traitor/objectives/destroy_item.dm index 965c49de27e..ec247eac9ed 100644 --- a/code/modules/antagonists/traitor/objectives/destroy_item.dm +++ b/code/modules/antagonists/traitor/objectives/destroy_item.dm @@ -34,6 +34,27 @@ /datum/objective_item/steal/blackbox, ) +/// Super early-game destroy objective intended to be items easily tided that the crew tends to value. +/datum/traitor_objective/destroy_item/demoralise + description = "Find %ITEM% and destroy it using any means necessary. \ + We believe this luxury item is important for crew morale. \ + Destruction of this item will help our recruitment efforts." + + progression_minimum = 0 MINUTES + progression_maximum = 10 MINUTES + progression_reward = list(4 MINUTES, 8 MINUTES) + telecrystal_reward = list(0, 1) + + possible_items = list( + /datum/objective_item/steal/traitor/rpd, + /datum/objective_item/steal/traitor/space_law, + /datum/objective_item/steal/traitor/granted_stamp, + /datum/objective_item/steal/traitor/denied_stamp, + /datum/objective_item/steal/traitor/lizard_plush, + /datum/objective_item/steal/traitor/moth_plush, + /datum/objective_item/steal/traitor/insuls, + ) + /datum/traitor_objective/destroy_item/generate_objective(datum/mind/generating_for, list/possible_duplicates) for(var/datum/traitor_objective/destroy_item/objective as anything in possible_duplicates) possible_items -= objective.target_item.type diff --git a/code/modules/antagonists/traitor/objectives/steal.dm b/code/modules/antagonists/traitor/objectives/steal.dm index b4d8b171274..61d4796d66f 100644 --- a/code/modules/antagonists/traitor/objectives/steal.dm +++ b/code/modules/antagonists/traitor/objectives/steal.dm @@ -97,6 +97,9 @@ GLOBAL_DATUM_INIT(steal_item_handler, /datum/objective_item_handler, new()) possible_items = list( /datum/objective_item/steal/traitor/cargo_budget, /datum/objective_item/steal/traitor/clown_shoes, + /datum/objective_item/steal/traitor/lawyers_badge, + /datum/objective_item/steal/traitor/chef_moustache, + /datum/objective_item/steal/traitor/pka, ) /datum/traitor_objective/steal_item/somewhat_risky diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm index c72c7e2668f..aae28fcf476 100644 --- a/code/modules/mining/mine_items.dm +++ b/code/modules/mining/mine_items.dm @@ -69,7 +69,6 @@ new /obj/item/storage/bag/plants(src) new /obj/item/storage/bag/ore(src) new /obj/item/t_scanner/adv_mining_scanner/lesser(src) - new /obj/item/gun/energy/recharge/kinetic_accelerator(src) new /obj/item/clothing/glasses/meson(src) if (HAS_TRAIT(SSstation, STATION_TRAIT_SMALLER_PODS)) new /obj/item/survivalcapsule/bathroom(src) @@ -78,6 +77,11 @@ new /obj/item/assault_pod/mining(src) +/obj/structure/closet/secure_closet/miner/populate_contents_immediate() + . = ..() + + new /obj/item/gun/energy/recharge/kinetic_accelerator(src) + /**********************Shuttle Computer**************************/ /obj/machinery/computer/shuttle/mining diff --git a/code/modules/uplink/uplink_items/badass.dm b/code/modules/uplink/uplink_items/badass.dm index 2469fe22104..93087be9dd0 100644 --- a/code/modules/uplink/uplink_items/badass.dm +++ b/code/modules/uplink/uplink_items/badass.dm @@ -90,3 +90,16 @@ desc = "Contains 8 random stickers precisely engineered to resemble suspicious objects, which may or may not be useful for fooling crew." item = /obj/item/storage/box/syndie_kit/stickers cost = 1 + +/datum/uplink_item/badass/demotivational_posters + name = "Syndicate Demotivational Poster Pack" + desc = "Contains a selection of demotivational posters to minimise productivity and maximise apathy in the workplace." + item = /obj/item/storage/box/syndie_kit/poster_box + cost = 1 + +/datum/uplink_item/badass/syndie_spraycan + name = "Syndicate Spraycan" + desc = "A stylish Syndicate spraycan. \ + Contains enough special solution to spray a single super-size seditious symbol, subjecting station staff to slippery suffering." + item = /obj/item/traitor_spraycan + cost = 1 diff --git a/tgstation.dme b/tgstation.dme index 5ec2e6a5f58..d1614134d3f 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1863,6 +1863,7 @@ #include "code\game\objects\effects\particle_holder.dm" #include "code\game\objects\effects\phased_mob.dm" #include "code\game\objects\effects\portals.dm" +#include "code\game\objects\effects\poster_demotivational.dm" #include "code\game\objects\effects\poster_motivational.dm" #include "code\game\objects\effects\powerup.dm" #include "code\game\objects\effects\spiderwebs.dm" @@ -2029,6 +2030,7 @@ #include "code\game\objects\items\skub.dm" #include "code\game\objects\items\spear.dm" #include "code\game\objects\items\sticker.dm" +#include "code\game\objects\items\syndie_spraycan.dm" #include "code\game\objects\items\tail_pin.dm" #include "code\game\objects\items\taster.dm" #include "code\game\objects\items\teleportation.dm" @@ -2868,9 +2870,7 @@ #include "code\modules\antagonists\traitor\components\traitor_objective_limit_per_time.dm" #include "code\modules\antagonists\traitor\components\traitor_objective_mind_tracker.dm" #include "code\modules\antagonists\traitor\objectives\assassination.dm" -#include "code\modules\antagonists\traitor\objectives\demoralise_crew.dm" -#include "code\modules\antagonists\traitor\objectives\demoralise_graffiti.dm" -#include "code\modules\antagonists\traitor\objectives\demoralise_poster.dm" +#include "code\modules\antagonists\traitor\objectives\demoralise_assault.dm" #include "code\modules\antagonists\traitor\objectives\destroy_heirloom.dm" #include "code\modules\antagonists\traitor\objectives\destroy_item.dm" #include "code\modules\antagonists\traitor\objectives\eyesnatching.dm"