From 7e1cea12c210be6a8e7a964dbbb9cc03c72aa11c Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Mon, 4 Nov 2024 21:31:24 +0000 Subject: [PATCH 01/31] A start --- .../PreferencesMenu/antagonists/antagonists/infiltrator.ts | 2 +- .../code/game/objects/items/implants/implant_infiltrator.dm | 3 ++- yogstation/code/modules/events/infiltrators.dm | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/infiltrator.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/infiltrator.ts index fae77d2500d35..ed055c8b23262 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/infiltrator.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/infiltrator.ts @@ -19,7 +19,7 @@ const Infiltrator: Antagonist = { `, INFILTRATOR_MECHANICAL_DESCRIPTION, ], - category: Category.Roundstart, + category: Category.Midround, priority: -1, }; diff --git a/yogstation/code/game/objects/items/implants/implant_infiltrator.dm b/yogstation/code/game/objects/items/implants/implant_infiltrator.dm index d4738a22850ba..8c04138945ea0 100644 --- a/yogstation/code/game/objects/items/implants/implant_infiltrator.dm +++ b/yogstation/code/game/objects/items/implants/implant_infiltrator.dm @@ -9,7 +9,7 @@ . = ..() ADD_TRAIT(src, TRAIT_EMPPROOF_SELF, "innate_empproof") ADD_TRAIT(src, TRAIT_EMPPROOF_CONTENTS, "innate_empproof") - var/datum/component/uplink/uplink = AddComponent(/datum/component/uplink, _owner, TRUE, FALSE, null, 20) + var/datum/component/uplink/uplink = AddComponent(/datum/component/uplink, _owner, TRUE, FALSE, null, 14) uplink.set_antagonist(ROLE_INFILTRATOR) alert_radio = new(src) alert_radio.make_syndie() @@ -81,6 +81,7 @@ else pinpointer.scan_target = targets[pinpointer_chosen] to_chat(imp_in, span_notice("Pinpointer target set to [pinpointer.scan_target]")) + message_admins(pinpointer.scan_target) pinpointer.point_to_target() if ("Send Ship Away") alert_radio.talk_into(alert_radio, "The infiltration cruiser has been remotely sent to the base by [imp_in.real_name]") diff --git a/yogstation/code/modules/events/infiltrators.dm b/yogstation/code/modules/events/infiltrators.dm index d6f15582f1065..0e69177226499 100644 --- a/yogstation/code/modules/events/infiltrators.dm +++ b/yogstation/code/modules/events/infiltrators.dm @@ -2,9 +2,9 @@ name = "Infiltrators" typepath = /datum/round_event/ghost_role/infiltrators - weight = 0 + weight = 5 max_occurrences = 1 - earliest_start = 30 MINUTES + earliest_start = 50 MINUTES track = EVENT_TRACK_MAJOR tags = list(TAG_COMBAT, TAG_EXTERNAL) description = "Infiltrators will... infiltrate." From b597cb955f2a74e1d51343099e0456bc3adc92a9 Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Wed, 6 Nov 2024 23:06:38 +0000 Subject: [PATCH 02/31] 10 TC --- .../code/game/objects/items/implants/implant_infiltrator.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yogstation/code/game/objects/items/implants/implant_infiltrator.dm b/yogstation/code/game/objects/items/implants/implant_infiltrator.dm index 8c04138945ea0..d5d5f1b55d953 100644 --- a/yogstation/code/game/objects/items/implants/implant_infiltrator.dm +++ b/yogstation/code/game/objects/items/implants/implant_infiltrator.dm @@ -9,7 +9,7 @@ . = ..() ADD_TRAIT(src, TRAIT_EMPPROOF_SELF, "innate_empproof") ADD_TRAIT(src, TRAIT_EMPPROOF_CONTENTS, "innate_empproof") - var/datum/component/uplink/uplink = AddComponent(/datum/component/uplink, _owner, TRUE, FALSE, null, 14) + var/datum/component/uplink/uplink = AddComponent(/datum/component/uplink, _owner, TRUE, FALSE, null, 10) uplink.set_antagonist(ROLE_INFILTRATOR) alert_radio = new(src) alert_radio.make_syndie() From b38711b941e09ae6379849a36cd83f193c7f7147 Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Fri, 8 Nov 2024 14:38:56 +0000 Subject: [PATCH 03/31] Fixes PDAs and gives them the rest of the chameleon kit --- .../computers/item/pda/pda_presets.dm | 8 ++- .../computers/item/tablet/tablet_presets.dm | 2 +- yogstation.dme | 1 - .../gamemodes/infiltration/infiltration.dm | 54 ------------------- .../modules/antagonists/infiltrator/outfit.dm | 5 +- 5 files changed, 12 insertions(+), 58 deletions(-) delete mode 100644 yogstation/code/game/gamemodes/infiltration/infiltration.dm diff --git a/code/modules/modular_computers/computers/item/pda/pda_presets.dm b/code/modules/modular_computers/computers/item/pda/pda_presets.dm index 3e564abba1c1b..f35a6db335a2a 100644 --- a/code/modules/modular_computers/computers/item/pda/pda_presets.dm +++ b/code/modules/modular_computers/computers/item/pda/pda_presets.dm @@ -233,11 +233,17 @@ ) return ..() -//for inside one of the nukie lockers +//for inside one of the nukie lockers and the ones infiltrators spawn with /obj/item/modular_computer/tablet/pda/preset/syndicate desc = "Based off Nanotrasen's PDAs, this one has been reverse-engineered and loaded with illegal software provided by the Syndicate." greyscale_config = /datum/greyscale_config/tablet/stripe_thick greyscale_colors = "#A80001#5C070F#000000" + starting_components = list( /obj/item/computer_hardware/processor_unit/small, + /obj/item/stock_parts/cell/computer, + /obj/item/computer_hardware/hard_drive/small/syndicate, + /obj/item/computer_hardware/network_card/advanced, + /obj/item/computer_hardware/card_slot, + /obj/item/computer_hardware/printer/mini) /obj/item/modular_computer/tablet/pda/preset/syndicate/Initialize(mapload) obj_flags |= EMAGGED //starts emagged diff --git a/code/modules/modular_computers/computers/item/tablet/tablet_presets.dm b/code/modules/modular_computers/computers/item/tablet/tablet_presets.dm index 49f2ab88c79e7..f2b9830bd3f10 100644 --- a/code/modules/modular_computers/computers/item/tablet/tablet_presets.dm +++ b/code/modules/modular_computers/computers/item/tablet/tablet_presets.dm @@ -69,7 +69,7 @@ starting_components = list( /obj/item/computer_hardware/processor_unit/small, /obj/item/stock_parts/cell/computer, /obj/item/computer_hardware/hard_drive/small/nukeops, - /obj/item/computer_hardware/network_card) + /obj/item/computer_hardware/network_card/advanced) starting_files = list(new /datum/computer_file/program/radar/fission360) initial_program = /datum/computer_file/program/radar/fission360 diff --git a/yogstation.dme b/yogstation.dme index 58551705d9d95..3f3def6cdc29d 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -4086,7 +4086,6 @@ #include "yogstation\code\game\gamemodes\clean_this_shit_up\blood_cult.dm" #include "yogstation\code\game\gamemodes\clean_this_shit_up\clock_cult.dm" #include "yogstation\code\game\gamemodes\clean_this_shit_up\other.dm" -#include "yogstation\code\game\gamemodes\infiltration\infiltration.dm" #include "yogstation\code\game\machinery\suit_storage_unit.dm" #include "yogstation\code\game\machinery\computer\arcade.dm" #include "yogstation\code\game\machinery\computer\atmos_sim.dm" diff --git a/yogstation/code/game/gamemodes/infiltration/infiltration.dm b/yogstation/code/game/gamemodes/infiltration/infiltration.dm deleted file mode 100644 index 06b940dc295a4..0000000000000 --- a/yogstation/code/game/gamemodes/infiltration/infiltration.dm +++ /dev/null @@ -1,54 +0,0 @@ -// /datum/game_mode/infiltration -// name = "infiltration" -// config_tag = "infiltration" -// false_report_weight = 10 -// required_players = 25 -// required_enemies = 3 -// recommended_enemies = 5 -// enemy_minimum_age = 21 -// antag_flag = ROLE_INFILTRATOR - -// var/agents_possible = 5 -// var/agents_left = 1 -// var/list/pre_sit = list() - -// var/datum/team/infiltrator/sit_team - -// var/static/list/areas_that_can_finish = typecacheof(list(/area/shuttle/yogs/stealthcruiser, /area/yogs/infiltrator_base)) - -// /datum/game_mode/infiltration/pre_setup() -// var/n_agents = min(max(CEILING(num_players() / 7, 1), 1), antag_candidates.len, agents_possible) -// if(GLOB.Debug2 || n_agents >= required_enemies) -// for(var/i = 0, i < n_agents, ++i) -// var/datum/mind/new_sit = pick_n_take(antag_candidates) -// pre_sit += new_sit -// new_sit.assigned_role = "Syndicate Infiltrator" -// new_sit.special_role = "Syndicate Infiltrator" -// log_game("[key_name(new_sit)] has been selected as a syndicate infiltrator") -// return TRUE -// setup_error = "Not enough infiltrator candidates" -// message_admins("Not enough infiltrator candidates! Was making [n_agents], but we need [required_enemies]!") -// return FALSE - -// /datum/game_mode/infiltration/post_setup() -// sit_team = new /datum/team/infiltrator -// for(var/datum/mind/sit_mind in pre_sit) -// sit_mind.add_antag_datum(ANTAG_DATUM_INFILTRATOR, sit_team) -// sit_team.update_objectives() -// return ..() - -// /datum/game_mode/infiltration/generate_report() //make this less shit -// return "Reports show that the Syndicate is rounding up it's elite agents, possibly for a raid on a Nanotrasen-controlled station. Keep an eye out for unusual people." - -// /datum/game_mode/infiltration/set_round_result() -// ..() -// var/result = sit_team.get_result() -// switch(result) -// if(INFILTRATION_ALLCOMPLETE) -// SSticker.mode_result = "major win - objectives complete" -// if(INFILTRATION_MOSTCOMPLETE) -// SSticker.mode_result = "minor win - most objectives complete" -// if(INFILTRATION_SOMECOMPLETE) -// SSticker.mode_result = "neutral - some objectives complete" -// else -// SSticker.mode_result = "loss - no objectives complete" diff --git a/yogstation/code/modules/antagonists/infiltrator/outfit.dm b/yogstation/code/modules/antagonists/infiltrator/outfit.dm index f3881e535af06..a4af35415c82f 100644 --- a/yogstation/code/modules/antagonists/infiltrator/outfit.dm +++ b/yogstation/code/modules/antagonists/infiltrator/outfit.dm @@ -1,13 +1,16 @@ -/datum/outfit/infiltrator // RIP +/datum/outfit/infiltrator // We're so back name = "Syndicate Infiltrator" uniform = /obj/item/clothing/under/chameleon/syndicate + suit = /obj/item/clothing/suit/chameleon/syndicate + glasses = /obj/item/clothing/glasses/chameleon/syndicate shoes = /obj/item/clothing/shoes/chameleon/noslip/syndicate gloves = /obj/item/clothing/gloves/chameleon/syndicate back = /obj/item/storage/backpack/chameleon/syndicate ears = /obj/item/radio/headset/chameleon/syndicate id = /obj/item/card/id/syndicate mask = /obj/item/clothing/mask/chameleon/syndicate + head = /obj/item/clothing/head/chameleon/syndicate belt = /obj/item/modular_computer/tablet/pda/preset/syndicate box = /obj/item/storage/box/survival/engineer backpack_contents = list(/obj/item/kitchen/knife/combat/survival=1,\ From 8994341711fc61c1dd2217a0b38104eaf0035999 Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Sat, 9 Nov 2024 02:28:11 +0000 Subject: [PATCH 04/31] Fixes chameleon hardsuits and them unduly calling their own proc hundreds of times --- code/modules/clothing/chameleon.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 3a830612c3ca7..75ae62fbd02d6 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -277,7 +277,6 @@ var/obj/item/clothing/suit/space/hardsuit/HS = picked_item var/obj/item/clothing/head/helmet/helmet = initial(HS.helmettype) I.head_piece.initial_state = initial(helmet.icon_state) - update_item(helmet, I.head_piece) I.head_piece.update_appearance(UPDATE_ICON) qdel(helmet) //YOGS END From 3a76e3ac0238c8374e01771f8e4c87ceb23149b8 Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Sat, 9 Nov 2024 23:23:21 +0000 Subject: [PATCH 05/31] Helmet light respects sprites --- code/modules/clothing/chameleon.dm | 9 ++++- .../antagonists/infiltrator/items/hardsuit.dm | 35 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 75ae62fbd02d6..d923f45dd5751 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -275,9 +275,16 @@ if(istype(atom_target, /obj/item/clothing/suit/space/hardsuit/infiltration)) //YOGS START var/obj/item/clothing/suit/space/hardsuit/infiltration/I = target var/obj/item/clothing/suit/space/hardsuit/HS = picked_item - var/obj/item/clothing/head/helmet/helmet = initial(HS.helmettype) + var/obj/item/clothing/head/helmet/space/hardsuit/helmet = initial(HS.helmettype) I.head_piece.initial_state = initial(helmet.icon_state) I.head_piece.update_appearance(UPDATE_ICON) + I.head_piece.current_disguise = picked_item + I.head_piece.new_type = helmet.hardsuit_type + var/datum/action/A + for(var/X in I.actions) + A = X + A.build_all_button_icons() + qdel(helmet) //YOGS END diff --git a/yogstation/code/modules/antagonists/infiltrator/items/hardsuit.dm b/yogstation/code/modules/antagonists/infiltrator/items/hardsuit.dm index f54efc3426ab6..1525f9fa9d3ba 100644 --- a/yogstation/code/modules/antagonists/infiltrator/items/hardsuit.dm +++ b/yogstation/code/modules/antagonists/infiltrator/items/hardsuit.dm @@ -4,6 +4,27 @@ item_state = "eng_helm" armor = list(MELEE = 35, BULLET = 15, LASER = 30,ENERGY = 10, BOMB = 10, BIO = 100, RAD = 50, FIRE = 75, ACID = 75) syndicate = TRUE + var/current_disguise = /obj/item/clothing/suit/space/hardsuit/infiltration + var/new_type = "engineering" + var/list/bad_hardsuits = list( + /obj/item/clothing/suit/space/hardsuit/darktemplar, + /obj/item/clothing/suit/space/hardsuit/darktemplar/chap, + /obj/item/clothing/suit/space/hardsuit/cult, + /obj/item/clothing/suit/space/hardsuit/syndi, + /obj/item/clothing/suit/space/hardsuit/syndi/elite, + /obj/item/clothing/suit/space/hardsuit/syndi/owl, + /obj/item/clothing/suit/space/hardsuit/syndi/debug, + /obj/item/clothing/suit/space/hardsuit/carp, + /obj/item/clothing/suit/space/hardsuit/carp/dragon, + /obj/item/clothing/suit/space/hardsuit/swat, + /obj/item/clothing/suit/space/hardsuit/swat/captain, + /obj/item/clothing/suit/space/hardsuit/ert/paranormal, + /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor, + /obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker, + /obj/item/clothing/suit/space/hardsuit/shielded/swat, + /obj/item/clothing/suit/space/hardsuit/shielded/swat/honk, + /obj/item/clothing/suit/space/hardsuit/deathsquad + ) /obj/item/clothing/head/helmet/space/hardsuit/infiltration/Initialize(mapload) . = ..() @@ -11,6 +32,20 @@ var/obj/item/clothing/suit/space/hardsuit/infiltration/I = loc I.head_piece = src +/obj/item/clothing/head/helmet/space/hardsuit/infiltration/attack_self(mob/user) + if(bad_hardsuits.Find(current_disguise)) + to_chat(user, span_warning("You can't use the hardsuit's helmet light with this current disguise, change to another one!")) + else //Copied from original hardsuit attack_self and modified slightly + on = !on + icon_state = "[basestate][on]-[new_type]" + user.update_inv_head() //so our mob-overlays update + + set_light_on(on) + + for(var/X in actions) + var/datum/action/A = X + A.build_all_button_icons() + /obj/item/clothing/suit/space/hardsuit/infiltration name = "engineering hardsuit" icon_state = "hardsuit-engineering" From d552719659794ec5fd2712adb73d4c3b4c6a115c Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Sun, 10 Nov 2024 17:26:09 +0000 Subject: [PATCH 06/31] Surgery dufflebag --- _maps/shuttles/infiltrator_cutter.dmm | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/_maps/shuttles/infiltrator_cutter.dmm b/_maps/shuttles/infiltrator_cutter.dmm index a37ff62f9cc37..3821dfab66717 100644 --- a/_maps/shuttles/infiltrator_cutter.dmm +++ b/_maps/shuttles/infiltrator_cutter.dmm @@ -204,13 +204,6 @@ /area/shuttle/yogs/stealthcruiser) "aC" = ( /obj/structure/table, -/obj/item/circular_saw, -/obj/item/scalpel{ - pixel_y = 12 - }, -/obj/item/cautery{ - pixel_x = 4 - }, /obj/machinery/light/small{ dir = 8 }, @@ -312,8 +305,7 @@ /area/shuttle/yogs/stealthcruiser) "aN" = ( /obj/structure/table, -/obj/item/retractor, -/obj/item/hemostat, +/obj/item/storage/backpack/duffelbag/med/surgery, /obj/effect/decal/cleanable/dirt, /turf/open/floor/plasteel, /area/shuttle/yogs/stealthcruiser) From e855a6d8cef0301f5f00fadb905362cee0657646 Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Sun, 10 Nov 2024 22:53:55 +0000 Subject: [PATCH 07/31] Fixes the infiltrator cutter's bolt airlocks button --- _maps/shuttles/infiltrator_cutter.dmm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/_maps/shuttles/infiltrator_cutter.dmm b/_maps/shuttles/infiltrator_cutter.dmm index 3821dfab66717..f2a3b0126e7e5 100644 --- a/_maps/shuttles/infiltrator_cutter.dmm +++ b/_maps/shuttles/infiltrator_cutter.dmm @@ -7,7 +7,7 @@ dir = 2 }, /obj/machinery/door/airlock/external{ - id_tag = "syndicatecutter_bolt_port" + id_tag = "bolt_port" }, /obj/docking_port/mobile{ callTime = 150; @@ -69,7 +69,7 @@ dir = 1 }, /obj/machinery/door/airlock/external{ - id_tag = "syndicatecutter_bolt_port" + id_tag = "bolt_port" }, /obj/effect/mapping_helpers/airlock/access/all/syndicate/general, /turf/open/floor/plating, @@ -749,7 +749,7 @@ }, /obj/effect/mapping_helpers/airlock/locked, /obj/machinery/door/airlock/external{ - id_tag = "syndicatecutter_bolt_starboard" + id_tag = "bolt_starboard" }, /obj/effect/mapping_helpers/airlock/access/all/syndicate/general, /turf/open/floor/plating, @@ -772,7 +772,7 @@ }, /obj/effect/mapping_helpers/airlock/locked, /obj/machinery/door/airlock/external{ - id_tag = "syndicatecutter_bolt_starboard" + id_tag = "bolt_starboard" }, /obj/effect/mapping_helpers/airlock/access/all/syndicate/general, /turf/open/floor/plating, From 624d14889bcf0e83c8085bff9f4cb914681aff65 Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Tue, 12 Nov 2024 19:41:04 +0000 Subject: [PATCH 08/31] Puts it back to the old preview --- .../modules/antagonists/infiltrator/infiltrator.dm | 2 +- .../code/modules/antagonists/infiltrator/outfit.dm | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/yogstation/code/modules/antagonists/infiltrator/infiltrator.dm b/yogstation/code/modules/antagonists/infiltrator/infiltrator.dm index 6b96bc2666963..d4e216f5178cf 100644 --- a/yogstation/code/modules/antagonists/infiltrator/infiltrator.dm +++ b/yogstation/code/modules/antagonists/infiltrator/infiltrator.dm @@ -10,7 +10,7 @@ var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team. var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint. var/dress_up = TRUE - preview_outfit = /datum/outfit/infiltrator + preview_outfit = /datum/outfit/infiltrator_preview /datum/antagonist/infiltrator/apply_innate_effects(mob/living/mob_override) var/mob/living/M = mob_override || owner.current diff --git a/yogstation/code/modules/antagonists/infiltrator/outfit.dm b/yogstation/code/modules/antagonists/infiltrator/outfit.dm index a4af35415c82f..4133f65ed53ae 100644 --- a/yogstation/code/modules/antagonists/infiltrator/outfit.dm +++ b/yogstation/code/modules/antagonists/infiltrator/outfit.dm @@ -45,3 +45,15 @@ var/obj/item/modular_computer/worn_computer = H.belt if(istype(worn_computer)) worn_computer.update_label(card) + +/datum/outfit/infiltrator_preview + name = "Syndicate Infiltrator (Preview)" + uniform = /obj/item/clothing/under/chameleon/syndicate + glasses = /obj/item/clothing/glasses/chameleon/syndicate + shoes = /obj/item/clothing/shoes/chameleon/noslip/syndicate + gloves = /obj/item/clothing/gloves/chameleon/syndicate + back = /obj/item/storage/backpack/chameleon/syndicate + ears = /obj/item/radio/headset/chameleon/syndicate + id = /obj/item/card/id/syndicate + mask = /obj/item/clothing/mask/chameleon/syndicate + belt = /obj/item/modular_computer/tablet/pda/preset/syndicate From 901ec4fc10fe1a1d3a453693bad2c739f101e2b1 Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Wed, 13 Nov 2024 18:45:12 +0000 Subject: [PATCH 09/31] Escape disguised objective --- .../antagonists/infiltrator/objectives.dm | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/yogstation/code/modules/antagonists/infiltrator/objectives.dm b/yogstation/code/modules/antagonists/infiltrator/objectives.dm index d149d7affce55..da3b271a9c280 100644 --- a/yogstation/code/modules/antagonists/infiltrator/objectives.dm +++ b/yogstation/code/modules/antagonists/infiltrator/objectives.dm @@ -113,3 +113,59 @@ GLOBAL_LIST_INIT(infiltrator_kidnap_areas, typecacheof(list(/area/shuttle/yogs/s /datum/objective/infiltrator/kidnap/check_completion() var/target_area = get_area(target.current) return QDELETED(target) || (target.current && (!target.current.ckey || target.current.suiciding)) || (considered_alive(target) && is_type_in_typecache(target_area, GLOB.infiltrator_kidnap_areas)) + +/datum/objective/infiltrator/escape_disguised //Sort of based on the escape with identity objective for changelings, most of the code is from that with modifications + explanation_text = "Have one member of your team disguise as a crewmember using your chameleon kit, and escape on the shuttle while wearing their identification card." + var/target_real_name + var/target_missing_id + +/datum/objective/infiltrator/escape_disguised/proc/potential_targets() + var/list/possible_targets = list() + for(var/datum/mind/M in SSticker.minds) + if(!M || !considered_alive(M) || considered_afk(M) || !M.current || !M.current.client || !ishuman(M.current) || M.quiet_round) + continue + if(M.has_antag_datum(/datum/antagonist/infiltrator) || M.has_antag_datum(/datum/antagonist/traitor) || M.has_antag_datum(/datum/antagonist/nukeop)) + continue + if(M.assigned_role in GLOB.command_positions) + possible_targets[M] = 25 + else //Either command or crew, stealing IDs from security officers and then having to impersonate them on shuttle simply doesn't work well + possible_targets[M] = 5 + return possible_targets + +/datum/objective/infiltrator/escape_disguised/is_possible() + return LAZYLEN(potential_targets()) + +/datum/objective/infiltrator/escape_disguised/find_target(dupe_search_range, blacklist) + target = pickweight(potential_targets()) + update_explanation_text() + return target + +/datum/objective/infiltrator/escape_disguised/update_explanation_text() + if(target && target.current) + target_real_name = target.current.real_name + explanation_text = "Have one member of your team disguise as [target.name], the [target.assigned_role] using your chameleon kit, and escape on the shuttle or an escape pod" + var/mob/living/carbon/human/H + if(ishuman(target.current)) + H = target.current + if(H && H.get_id_name() != target_real_name) + target_missing_id = 1 + else + explanation_text += " while wearing their identification card" + explanation_text += "." + else + explanation_text = "Free Objective" + +/datum/objective/infiltrator/escape_disguised/check_completion() + . = ..() + if(completed) + return TRUE + if(!target || !target_real_name) + return TRUE + var/list/infiltrators = get_antag_minds(/datum/antagonist/infiltrator, TRUE) + for(var/datum/mind/M in infiltrators) + if(!considered_escaped(M)) + continue + var/mob/living/carbon/human/H = M.current + if(H.get_id_name() == target_real_name || target_missing_id) + return TRUE + return FALSE From 5d2d2489e8b50a0e288cf98c58ea2dcf1261f7ac Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Thu, 14 Nov 2024 12:56:40 +0000 Subject: [PATCH 10/31] Chameleon copying --- code/modules/clothing/chameleon.dm | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index d923f45dd5751..79c2a7d367f7f 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -142,6 +142,16 @@ qdel(O) return TRUE +/datum/action/chameleon_copy + name = "Copy person" + button_icon_state = "chameleon_outfit" //Temporary, just to test it works + var/syndicate = FALSE + +/datum/action/chameleon_copy/Grant(mob/user) + if(syndicate) + owner_has_control = is_syndicate(user) + return ..() + /datum/action/item_action/chameleon/change name = "Chameleon Change" From e342e6f5dfae1db937f13cd795602e4f57f94dfa Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Thu, 14 Nov 2024 22:36:18 +0000 Subject: [PATCH 11/31] Revert "Chameleon copying" This reverts commit 5d2d2489e8b50a0e288cf98c58ea2dcf1261f7ac. --- code/modules/clothing/chameleon.dm | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 79c2a7d367f7f..d923f45dd5751 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -142,16 +142,6 @@ qdel(O) return TRUE -/datum/action/chameleon_copy - name = "Copy person" - button_icon_state = "chameleon_outfit" //Temporary, just to test it works - var/syndicate = FALSE - -/datum/action/chameleon_copy/Grant(mob/user) - if(syndicate) - owner_has_control = is_syndicate(user) - return ..() - /datum/action/item_action/chameleon/change name = "Chameleon Change" From 00cea31347ea479f5d57223d0d9710717a6646d3 Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Mon, 18 Nov 2024 00:13:42 +0000 Subject: [PATCH 12/31] Do not go to the base to end the round --- yogstation/code/modules/antagonists/infiltrator/infiltrator.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/yogstation/code/modules/antagonists/infiltrator/infiltrator.dm b/yogstation/code/modules/antagonists/infiltrator/infiltrator.dm index d4e216f5178cf..4862f26bdd0c1 100644 --- a/yogstation/code/modules/antagonists/infiltrator/infiltrator.dm +++ b/yogstation/code/modules/antagonists/infiltrator/infiltrator.dm @@ -24,7 +24,6 @@ to_chat(owner, span_notice("You also have an internal radio, for communicating with your team-mates at all times.")) to_chat(owner, span_notice("You have a dusting implant, to ensure that Nanotrasen does not get their hands on Syndicate gear. Only activate it, if you are compromised.")) to_chat(owner, span_boldnotice(span_italics("Do NOT kill or destroy needlessly, as this defeats the purpose of an 'infiltration'!"))) - to_chat(owner, span_boldnotice("Once your objectives are complete, return to base, with all living infiltrators, to end the round.")) owner.announce_objectives() /datum/antagonist/infiltrator/on_gain() From 8c907d82ae40459aa5288fdfa7145e75699b97e8 Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Tue, 19 Nov 2024 00:22:15 +0000 Subject: [PATCH 13/31] Back to chameleon copying, I guess --- code/modules/clothing/chameleon.dm | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index d923f45dd5751..44c8be5115142 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -142,6 +142,26 @@ qdel(O) return TRUE +/datum/action/chameleon_copy + name = "Copy person" + button_icon_state = "default" //Temporary, just to test it works + var/syndicate = FALSE + var/active = FALSE + var/copying = FALSE + +/datum/action/chameleon_copy/Grant(mob/M) + if(syndicate) + owner_has_control = is_syndicate(M) + return ..() + +/datum/action/chameleon_copy/Trigger(trigger_flags, atom/target) + if(active) + active = !active + build_all_button_icons() + return FALSE + to_chat(owner, span_announce("Whom shall your chameleon kit copy?")) //Bad wording, need to improve it + active = !active + build_all_button_icons() /datum/action/item_action/chameleon/change name = "Chameleon Change" @@ -160,6 +180,9 @@ var/datum/action/chameleon_outfit/O = new /datum/action/chameleon_outfit() O.syndicate = syndicate O.Grant(M) + var/datum/action/chameleon_copy/C = new /datum/action/chameleon_copy() + C.syndicate = syndicate + C.Grant(M) else M.chameleon_item_actions |= src if(syndicate) From 8b682efc84880f0a299769f097f5224b8b3f6379 Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Tue, 19 Nov 2024 12:14:00 +0000 Subject: [PATCH 14/31] Actually make it do something --- code/modules/clothing/chameleon.dm | 54 ++++++++++++++++--- .../items/implants/implant_infiltrator.dm | 1 - 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 44c8be5115142..22475190c4e68 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -142,26 +142,68 @@ qdel(O) return TRUE -/datum/action/chameleon_copy +/datum/action/cooldown/chameleon_copy name = "Copy person" button_icon_state = "default" //Temporary, just to test it works + var/target_range = 3 var/syndicate = FALSE var/active = FALSE var/copying = FALSE + var/in_use = FALSE -/datum/action/chameleon_copy/Grant(mob/M) +/datum/action/cooldown/chameleon_copy/Grant(mob/M) if(syndicate) owner_has_control = is_syndicate(M) return ..() -/datum/action/chameleon_copy/Trigger(trigger_flags, atom/target) +/datum/action/cooldown/chameleon_copy/Trigger(trigger_flags, atom/target) if(active) - active = !active + active = FALSE build_all_button_icons() return FALSE to_chat(owner, span_announce("Whom shall your chameleon kit copy?")) //Bad wording, need to improve it - active = !active + active = TRUE build_all_button_icons() + if(target) + return InterceptClickOn(owner, null, target) + +/datum/action/cooldown/chameleon_copy/proc/CheckValidTarget(atom/target_atom) + if(target_atom == owner) + return FALSE + return TRUE + +/datum/action/cooldown/chameleon_copy/proc/CheckCanTarget(atom/target_atom) + if(target_range) + if(!(target_atom in view(target_range, owner))) + return FALSE + return istype(target_atom) + +/datum/action/cooldown/chameleon_copy/proc/click_with_power(atom/target_atom) + if(in_use || !CheckValidTarget(target_atom)) + return FALSE + if(!CheckCanTarget(target_atom)) + return TRUE + in_use = TRUE + FireTargetedPower(target_atom) + in_use = FALSE + return TRUE + +/datum/action/cooldown/chameleon_copy/proc/FireTargetedPower(atom/target_atom) + . = ..() + var/mob/living/target = target_atom + var/mob/living/user = owner + var/datum/outfit/O = new() + to_chat(owner, span_notice("Attempting to copy [target]...")) + if(!do_after(user, 5 SECONDS, target)) + return + for(var/item in target.contents) + message_admins(item) + to_chat(owner, span_notice("Successfully copied [target]!")) + active = FALSE + + +/datum/action/cooldown/chameleon_copy/InterceptClickOn(/mob/living/caller, params, atom/target) + click_with_power() /datum/action/item_action/chameleon/change name = "Chameleon Change" @@ -180,7 +222,7 @@ var/datum/action/chameleon_outfit/O = new /datum/action/chameleon_outfit() O.syndicate = syndicate O.Grant(M) - var/datum/action/chameleon_copy/C = new /datum/action/chameleon_copy() + var/datum/action/cooldown/chameleon_copy/C = new /datum/action/cooldown/chameleon_copy() C.syndicate = syndicate C.Grant(M) else diff --git a/yogstation/code/game/objects/items/implants/implant_infiltrator.dm b/yogstation/code/game/objects/items/implants/implant_infiltrator.dm index d5d5f1b55d953..7c4507d8f6ccc 100644 --- a/yogstation/code/game/objects/items/implants/implant_infiltrator.dm +++ b/yogstation/code/game/objects/items/implants/implant_infiltrator.dm @@ -81,7 +81,6 @@ else pinpointer.scan_target = targets[pinpointer_chosen] to_chat(imp_in, span_notice("Pinpointer target set to [pinpointer.scan_target]")) - message_admins(pinpointer.scan_target) pinpointer.point_to_target() if ("Send Ship Away") alert_radio.talk_into(alert_radio, "The infiltration cruiser has been remotely sent to the base by [imp_in.real_name]") From bc4e49d2fae229b681fc22edd549e01db63c873e Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Tue, 19 Nov 2024 12:18:06 +0000 Subject: [PATCH 15/31] This is why I need to think sometimes --- code/modules/clothing/chameleon.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 22475190c4e68..dad2674340dcc 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -189,7 +189,6 @@ return TRUE /datum/action/cooldown/chameleon_copy/proc/FireTargetedPower(atom/target_atom) - . = ..() var/mob/living/target = target_atom var/mob/living/user = owner var/datum/outfit/O = new() From 69d76d1a9e3e28908efffa0933738259a6ce289c Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Wed, 20 Nov 2024 23:23:39 +0000 Subject: [PATCH 16/31] Even more of a mess --- code/modules/clothing/chameleon.dm | 46 ++++++++++++++++-------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index dad2674340dcc..89ef567214b24 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -156,53 +156,57 @@ owner_has_control = is_syndicate(M) return ..() -/datum/action/cooldown/chameleon_copy/Trigger(trigger_flags, atom/target) +/datum/action/cooldown/chameleon_copy/Trigger(trigger_flags, mob/living/copy_target) if(active) active = FALSE + background_icon_state = "bg_default" build_all_button_icons() + unset_click_ability(owner) return FALSE to_chat(owner, span_announce("Whom shall your chameleon kit copy?")) //Bad wording, need to improve it active = TRUE + background_icon_state = "bg_default_on" build_all_button_icons() - if(target) - return InterceptClickOn(owner, null, target) + if(copy_target) + return InterceptClickOn(owner, null, copy_target) + return set_click_ability(owner) -/datum/action/cooldown/chameleon_copy/proc/CheckValidTarget(atom/target_atom) - if(target_atom == owner) +/datum/action/cooldown/chameleon_copy/proc/CheckValidTarget(mob/living/copy_target) + if(copy_target == owner) return FALSE return TRUE -/datum/action/cooldown/chameleon_copy/proc/CheckCanTarget(atom/target_atom) +/datum/action/cooldown/chameleon_copy/proc/CheckCanTarget(mob/living/copy_target) + var/mob/living/carbon/human/user = owner if(target_range) - if(!(target_atom in view(target_range, owner))) + if(!(get_dist(user, copy_target) <= target_range)) //get_dist really hates datums for some reason return FALSE - return istype(target_atom) + return istype(target) -/datum/action/cooldown/chameleon_copy/proc/click_with_power(atom/target_atom) - if(in_use || !CheckValidTarget(target_atom)) +/datum/action/cooldown/chameleon_copy/proc/click_with_power(mob/living/copy_target) + if(in_use || !CheckValidTarget(copy_target)) return FALSE - if(!CheckCanTarget(target_atom)) + if(!CheckCanTarget(copy_target)) return TRUE in_use = TRUE - FireTargetedPower(target_atom) + FireTargetedPower(copy_target) in_use = FALSE return TRUE -/datum/action/cooldown/chameleon_copy/proc/FireTargetedPower(atom/target_atom) - var/mob/living/target = target_atom - var/mob/living/user = owner - var/datum/outfit/O = new() - to_chat(owner, span_notice("Attempting to copy [target]...")) - if(!do_after(user, 5 SECONDS, target)) +/datum/action/cooldown/chameleon_copy/proc/FireTargetedPower(mob/living/copy_target) + //var/datum/outfit/O = new() + to_chat(owner, span_notice("Attempting to copy [copy_target]...")) + if(!do_after(owner, 5 SECONDS, copy_target)) return - for(var/item in target.contents) + for(var/item in copy_target.contents) message_admins(item) - to_chat(owner, span_notice("Successfully copied [target]!")) + to_chat(owner, span_notice("Successfully copied [copy_target]!")) active = FALSE /datum/action/cooldown/chameleon_copy/InterceptClickOn(/mob/living/caller, params, atom/target) - click_with_power() + var/mob/living/copy_target = target + click_with_power(copy_target) /datum/action/item_action/chameleon/change name = "Chameleon Change" From f0afe832893d57d27c0e8c3768b2324bf65b2d82 Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Thu, 21 Nov 2024 14:02:37 +0000 Subject: [PATCH 17/31] Semi working but still not working --- code/modules/clothing/chameleon.dm | 41 +++++++++++++++++------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 89ef567214b24..a091cf37a13a5 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -157,6 +157,8 @@ return ..() /datum/action/cooldown/chameleon_copy/Trigger(trigger_flags, mob/living/copy_target) + message_admins("Trigger called") + message_admins("Trigger: [copy_target]") if(active) active = FALSE background_icon_state = "bg_default" @@ -172,41 +174,46 @@ return set_click_ability(owner) /datum/action/cooldown/chameleon_copy/proc/CheckValidTarget(mob/living/copy_target) + message_admins("CheckValidTarget called") if(copy_target == owner) return FALSE return TRUE -/datum/action/cooldown/chameleon_copy/proc/CheckCanTarget(mob/living/copy_target) - var/mob/living/carbon/human/user = owner - if(target_range) - if(!(get_dist(user, copy_target) <= target_range)) //get_dist really hates datums for some reason - return FALSE - return istype(target) +/datum/action/cooldown/chameleon_copy/proc/CheckCanTarget(atom/target) + return !isnull(target) -/datum/action/cooldown/chameleon_copy/proc/click_with_power(mob/living/copy_target) - if(in_use || !CheckValidTarget(copy_target)) +/datum/action/cooldown/chameleon_copy/proc/click_with_power(atom/target) + message_admins("click_with_power called") + message_admins("Click: [target]") + if(in_use || !CheckValidTarget(target)) + message_admins("Failed click_with_power 1") return FALSE - if(!CheckCanTarget(copy_target)) + if(!CheckCanTarget(target)) + message_admins("Failed click_with_power 2") return TRUE in_use = TRUE - FireTargetedPower(copy_target) + FireTargetedPower(target) in_use = FALSE return TRUE -/datum/action/cooldown/chameleon_copy/proc/FireTargetedPower(mob/living/copy_target) +/datum/action/cooldown/chameleon_copy/proc/FireTargetedPower(atom/target) + message_admins("FireTargetedPower called") + var/mob/M = target + message_admins("Mob: [M]") //var/datum/outfit/O = new() - to_chat(owner, span_notice("Attempting to copy [copy_target]...")) - if(!do_after(owner, 5 SECONDS, copy_target)) + to_chat(owner, span_notice("Attempting to copy [M]...")) + if(!do_after(owner, 5 SECONDS, target)) return - for(var/item in copy_target.contents) + for(var/item in target.contents) message_admins(item) - to_chat(owner, span_notice("Successfully copied [copy_target]!")) + to_chat(owner, span_notice("Successfully copied [M]!")) active = FALSE /datum/action/cooldown/chameleon_copy/InterceptClickOn(/mob/living/caller, params, atom/target) - var/mob/living/copy_target = target - click_with_power(copy_target) + message_admins("InterceptClickOn called") + message_admins("Intercept: [target]") + click_with_power(target) /datum/action/item_action/chameleon/change name = "Chameleon Change" From 397575c414bee96a132810a942747db2148dac7c Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Thu, 21 Nov 2024 20:55:21 +0000 Subject: [PATCH 18/31] Back to atoms I guess --- code/modules/clothing/chameleon.dm | 31 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index a091cf37a13a5..14dd0fd097f74 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -156,9 +156,9 @@ owner_has_control = is_syndicate(M) return ..() -/datum/action/cooldown/chameleon_copy/Trigger(trigger_flags, mob/living/copy_target) +/datum/action/cooldown/chameleon_copy/Trigger(trigger_flags, atom/target) message_admins("Trigger called") - message_admins("Trigger: [copy_target]") + message_admins("Trigger: [target]") if(active) active = FALSE background_icon_state = "bg_default" @@ -169,42 +169,43 @@ active = TRUE background_icon_state = "bg_default_on" build_all_button_icons() - if(copy_target) - return InterceptClickOn(owner, null, copy_target) - return set_click_ability(owner) + if(target) + return InterceptClickOn(owner, null, target) + set_click_ability(owner) -/datum/action/cooldown/chameleon_copy/proc/CheckValidTarget(mob/living/copy_target) +/datum/action/cooldown/chameleon_copy/proc/CheckValidTarget(atom/target) message_admins("CheckValidTarget called") - if(copy_target == owner) + if(target == owner) return FALSE return TRUE /datum/action/cooldown/chameleon_copy/proc/CheckCanTarget(atom/target) return !isnull(target) -/datum/action/cooldown/chameleon_copy/proc/click_with_power(atom/target) +/datum/action/cooldown/chameleon_copy/proc/click_with_power(atom/target_atom) message_admins("click_with_power called") - message_admins("Click: [target]") - if(in_use || !CheckValidTarget(target)) + message_admins("Click: [target_atom]") + if(in_use || !CheckValidTarget(target_atom)) message_admins("Failed click_with_power 1") return FALSE - if(!CheckCanTarget(target)) + if(!CheckCanTarget(target_atom)) message_admins("Failed click_with_power 2") return TRUE in_use = TRUE - FireTargetedPower(target) + FireTargetedPower(target_atom) in_use = FALSE return TRUE -/datum/action/cooldown/chameleon_copy/proc/FireTargetedPower(atom/target) +/datum/action/cooldown/chameleon_copy/proc/FireTargetedPower(atom/target_atom) message_admins("FireTargetedPower called") var/mob/M = target + message_admins("Atom: [target_atom]") message_admins("Mob: [M]") //var/datum/outfit/O = new() to_chat(owner, span_notice("Attempting to copy [M]...")) - if(!do_after(owner, 5 SECONDS, target)) + if(!do_after(owner, 5 SECONDS, target_atom)) return - for(var/item in target.contents) + for(var/item in target_atom.contents) message_admins(item) to_chat(owner, span_notice("Successfully copied [M]!")) active = FALSE From 7acb94a674b3a17a9c63dd6493623fb91dd55a58 Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Thu, 21 Nov 2024 22:36:34 +0000 Subject: [PATCH 19/31] Just to confirm it isn't this --- code/modules/clothing/chameleon.dm | 2 -- 1 file changed, 2 deletions(-) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 14dd0fd097f74..3666e1dd3c54f 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -169,8 +169,6 @@ active = TRUE background_icon_state = "bg_default_on" build_all_button_icons() - if(target) - return InterceptClickOn(owner, null, target) set_click_ability(owner) /datum/action/cooldown/chameleon_copy/proc/CheckValidTarget(atom/target) From 13851bf1c89e756e60d8b3c1bdec31cfc6f83b85 Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Sat, 23 Nov 2024 18:45:40 +0000 Subject: [PATCH 20/31] Finally works --- code/modules/clothing/chameleon.dm | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 3666e1dd3c54f..d515d18c694a3 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -142,6 +142,7 @@ qdel(O) return TRUE + /datum/action/cooldown/chameleon_copy name = "Copy person" button_icon_state = "default" //Temporary, just to test it works @@ -151,10 +152,15 @@ var/copying = FALSE var/in_use = FALSE +/datum/action/cooldown/chameleon_copy/InterceptClickOn(mob/living/caller, params, atom/target) + message_admins("InterceptClickOn called") + message_admins("Intercept: [target]") + click_with_power(target) + /datum/action/cooldown/chameleon_copy/Grant(mob/M) if(syndicate) owner_has_control = is_syndicate(M) - return ..() + . = ..() /datum/action/cooldown/chameleon_copy/Trigger(trigger_flags, atom/target) message_admins("Trigger called") @@ -177,18 +183,12 @@ return FALSE return TRUE -/datum/action/cooldown/chameleon_copy/proc/CheckCanTarget(atom/target) - return !isnull(target) - /datum/action/cooldown/chameleon_copy/proc/click_with_power(atom/target_atom) message_admins("click_with_power called") message_admins("Click: [target_atom]") if(in_use || !CheckValidTarget(target_atom)) message_admins("Failed click_with_power 1") return FALSE - if(!CheckCanTarget(target_atom)) - message_admins("Failed click_with_power 2") - return TRUE in_use = TRUE FireTargetedPower(target_atom) in_use = FALSE @@ -196,7 +196,7 @@ /datum/action/cooldown/chameleon_copy/proc/FireTargetedPower(atom/target_atom) message_admins("FireTargetedPower called") - var/mob/M = target + var/mob/M = target_atom message_admins("Atom: [target_atom]") message_admins("Mob: [M]") //var/datum/outfit/O = new() @@ -207,12 +207,7 @@ message_admins(item) to_chat(owner, span_notice("Successfully copied [M]!")) active = FALSE - -/datum/action/cooldown/chameleon_copy/InterceptClickOn(/mob/living/caller, params, atom/target) - message_admins("InterceptClickOn called") - message_admins("Intercept: [target]") - click_with_power(target) /datum/action/item_action/chameleon/change name = "Chameleon Change" From 7b55b8c7aade7c0c5079eb85b7086f9e731111bd Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Mon, 25 Nov 2024 07:11:05 +0000 Subject: [PATCH 21/31] Chameleon working, but badly --- code/modules/clothing/chameleon.dm | 106 ++++++++++++++++++----------- 1 file changed, 65 insertions(+), 41 deletions(-) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index d515d18c694a3..395ccbf794dab 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -99,30 +99,45 @@ /datum/action/chameleon_outfit/Trigger() return select_outfit(owner) -/datum/action/chameleon_outfit/proc/select_outfit(mob/user) +/datum/action/chameleon_outfit/proc/select_outfit(mob/user, datum/outfit/outfit = null) + message_admins("select_outfit called") if(!user || !IsAvailable(feedback = FALSE)) return FALSE - var/selected = tgui_input_list(user, "Select outfit to change into", "Chameleon Outfit", outfit_options) - if(!IsAvailable(feedback = FALSE) || QDELETED(src) || QDELETED(user)) - return FALSE - var/outfit_type = outfit_options[selected] - if(!outfit_type) - return FALSE - var/datum/outfit/O = new outfit_type() - var/list/outfit_types = O.get_chameleon_disguise_info() - - for(var/V in user.chameleon_item_actions) - var/datum/action/item_action/chameleon/change/A = V - var/done = FALSE - for(var/T in outfit_types) - for(var/name in A.chameleon_list) - if(A.chameleon_list[name] == T) - A.update_look(user, T) - outfit_types -= T - done = TRUE + var/datum/outfit/O + if(isnull(outfit)) //If no outfit is passed, get the user to decide + var/selected = tgui_input_list(user, "Select outfit to change into", "Chameleon Outfit", outfit_options) + if(!IsAvailable(feedback = FALSE) || QDELETED(src) || QDELETED(user)) + return FALSE + var/outfit_type = outfit_options[selected] + if(!outfit_type) + return FALSE + message_admins(outfit_type) + O = new outfit_type() + message_admins(O) + var/list/outfit_types = O.get_chameleon_disguise_info() + for(var/V in user.chameleon_item_actions) + var/datum/action/item_action/chameleon/change/A = V + var/done = FALSE + for(var/T in outfit_types) + for(var/name in A.chameleon_list) + if(A.chameleon_list[name] == T) + message_admins("List: [A.chameleon_list[name]], T: [T]") + A.update_look(user, T) + outfit_types -= T + done = TRUE + break + if(done) break - if(done) - break + else //If a specific outfit is passed through + var/list/types = outfit.get_chameleon_disguise_info() + message_admins(outfit) + message_admins("Uniform: [outfit.uniform]") + message_admins("Suit: [outfit.suit]") + for(var/i in 1 to types.len) + var/datum/action/item_action/chameleon/change/A = user.chameleon_item_actions[i] + message_admins("T: [types[i]]") + A.update_look(user, types[i]) + return TRUE //hardsuit helmets/suit hoods if(O.toggle_helmet && (ispath(O.suit, /obj/item/clothing/suit/space/hardsuit) || ispath(O.suit, /obj/item/clothing/suit/hooded)) && ishuman(user)) var/mob/living/carbon/human/H = user @@ -153,8 +168,6 @@ var/in_use = FALSE /datum/action/cooldown/chameleon_copy/InterceptClickOn(mob/living/caller, params, atom/target) - message_admins("InterceptClickOn called") - message_admins("Intercept: [target]") click_with_power(target) /datum/action/cooldown/chameleon_copy/Grant(mob/M) @@ -162,32 +175,35 @@ owner_has_control = is_syndicate(M) . = ..() -/datum/action/cooldown/chameleon_copy/Trigger(trigger_flags, atom/target) - message_admins("Trigger called") - message_admins("Trigger: [target]") +/datum/action/cooldown/chameleon_copy/proc/toggle_button() if(active) active = FALSE background_icon_state = "bg_default" build_all_button_icons() unset_click_ability(owner) return FALSE - to_chat(owner, span_announce("Whom shall your chameleon kit copy?")) //Bad wording, need to improve it active = TRUE background_icon_state = "bg_default_on" build_all_button_icons() set_click_ability(owner) +/datum/action/cooldown/chameleon_copy/Trigger(trigger_flags, atom/target) + if(active) + toggle_button() + else + to_chat(owner, span_announce("Whom shall your chameleon kit copy?")) //Bad wording, need to improve it + toggle_button() + + /datum/action/cooldown/chameleon_copy/proc/CheckValidTarget(atom/target) - message_admins("CheckValidTarget called") if(target == owner) return FALSE + if(!ishuman(target)) + return FALSE return TRUE /datum/action/cooldown/chameleon_copy/proc/click_with_power(atom/target_atom) - message_admins("click_with_power called") - message_admins("Click: [target_atom]") if(in_use || !CheckValidTarget(target_atom)) - message_admins("Failed click_with_power 1") return FALSE in_use = TRUE FireTargetedPower(target_atom) @@ -195,18 +211,24 @@ return TRUE /datum/action/cooldown/chameleon_copy/proc/FireTargetedPower(atom/target_atom) - message_admins("FireTargetedPower called") - var/mob/M = target_atom - message_admins("Atom: [target_atom]") - message_admins("Mob: [M]") - //var/datum/outfit/O = new() - to_chat(owner, span_notice("Attempting to copy [M]...")) + var/mob/living/carbon/human/T = target_atom + var/datum/outfit/O = new() + to_chat(owner, span_notice("Attempting to copy [T]...")) if(!do_after(owner, 5 SECONDS, target_atom)) return - for(var/item in target_atom.contents) - message_admins(item) - to_chat(owner, span_notice("Successfully copied [M]!")) - active = FALSE + O.uniform = T.w_uniform + O.suit = T.wear_suit + O.head = T.head + O.shoes = T.shoes + O.gloves = T.gloves + O.ears = T.ears + O.glasses = T.glasses + O.mask = T.wear_mask + O.neck = T.wear_neck + var/datum/action/chameleon_outfit/select = locate(/datum/action/chameleon_outfit) in owner.actions + select.select_outfit(owner, O) + to_chat(owner, span_notice("Successfully copied [T]!")) + toggle_button() /datum/action/item_action/chameleon/change @@ -691,6 +713,8 @@ chameleon_action.emp_randomise(INFINITY) /obj/item/clothing/mask/chameleon/attack_self(mob/user) + if(!is_syndicate(user)) //Wouldn't want someone to randomly find a switch on a mask, would we? + return vchange = !vchange to_chat(user, span_notice("The voice changer is now [vchange ? "on" : "off"]!")) if(vchange) From 89461c755c92c816882e442318b5102ffbc8c1b6 Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Mon, 25 Nov 2024 12:03:04 +0000 Subject: [PATCH 22/31] Might be more reasonable --- code/modules/clothing/chameleon.dm | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 395ccbf794dab..ce3dbb57eeb5c 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -134,9 +134,11 @@ message_admins("Uniform: [outfit.uniform]") message_admins("Suit: [outfit.suit]") for(var/i in 1 to types.len) - var/datum/action/item_action/chameleon/change/A = user.chameleon_item_actions[i] - message_admins("T: [types[i]]") - A.update_look(user, types[i]) + for(var/V in user.chameleon_item_actions) + var/datum/action/item_action/chameleon/change/A = V + if(istype(types[i], A.chameleon_type)) + message_admins("T: [types[i]]") + A.update_look(user, types[i]) return TRUE //hardsuit helmets/suit hoods if(O.toggle_helmet && (ispath(O.suit, /obj/item/clothing/suit/space/hardsuit) || ispath(O.suit, /obj/item/clothing/suit/hooded)) && ishuman(user)) From 7c2d2c7ca538808f36030ca304659f0b7769c2a3 Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Mon, 25 Nov 2024 18:56:00 +0000 Subject: [PATCH 23/31] Moves it to 10 seconds instead --- code/modules/clothing/chameleon.dm | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index ce3dbb57eeb5c..5deddf6deeb99 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -100,7 +100,6 @@ return select_outfit(owner) /datum/action/chameleon_outfit/proc/select_outfit(mob/user, datum/outfit/outfit = null) - message_admins("select_outfit called") if(!user || !IsAvailable(feedback = FALSE)) return FALSE var/datum/outfit/O @@ -111,9 +110,7 @@ var/outfit_type = outfit_options[selected] if(!outfit_type) return FALSE - message_admins(outfit_type) O = new outfit_type() - message_admins(O) var/list/outfit_types = O.get_chameleon_disguise_info() for(var/V in user.chameleon_item_actions) var/datum/action/item_action/chameleon/change/A = V @@ -121,7 +118,6 @@ for(var/T in outfit_types) for(var/name in A.chameleon_list) if(A.chameleon_list[name] == T) - message_admins("List: [A.chameleon_list[name]], T: [T]") A.update_look(user, T) outfit_types -= T done = TRUE @@ -130,15 +126,11 @@ break else //If a specific outfit is passed through var/list/types = outfit.get_chameleon_disguise_info() - message_admins(outfit) - message_admins("Uniform: [outfit.uniform]") - message_admins("Suit: [outfit.suit]") - for(var/i in 1 to types.len) + for(var/T in types) for(var/V in user.chameleon_item_actions) var/datum/action/item_action/chameleon/change/A = V - if(istype(types[i], A.chameleon_type)) - message_admins("T: [types[i]]") - A.update_look(user, types[i]) + if(istype(T, A.chameleon_type)) + A.update_look(user, T) return TRUE //hardsuit helmets/suit hoods if(O.toggle_helmet && (ispath(O.suit, /obj/item/clothing/suit/space/hardsuit) || ispath(O.suit, /obj/item/clothing/suit/hooded)) && ishuman(user)) @@ -216,7 +208,7 @@ var/mob/living/carbon/human/T = target_atom var/datum/outfit/O = new() to_chat(owner, span_notice("Attempting to copy [T]...")) - if(!do_after(owner, 5 SECONDS, target_atom)) + if(!do_after(owner, 10 SECONDS, target_atom)) return O.uniform = T.w_uniform O.suit = T.wear_suit @@ -226,7 +218,6 @@ O.ears = T.ears O.glasses = T.glasses O.mask = T.wear_mask - O.neck = T.wear_neck var/datum/action/chameleon_outfit/select = locate(/datum/action/chameleon_outfit) in owner.actions select.select_outfit(owner, O) to_chat(owner, span_notice("Successfully copied [T]!")) From ac064eb26038c45638ea7df193968d6805c869de Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Wed, 27 Nov 2024 17:19:57 +0000 Subject: [PATCH 24/31] Keeps chameleon copy to one proc --- code/modules/clothing/chameleon.dm | 65 ++++++++++--------- .../antagonists/infiltrator/objectives.dm | 11 ++++ 2 files changed, 45 insertions(+), 31 deletions(-) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 5deddf6deeb99..324b419f6c096 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -99,39 +99,30 @@ /datum/action/chameleon_outfit/Trigger() return select_outfit(owner) -/datum/action/chameleon_outfit/proc/select_outfit(mob/user, datum/outfit/outfit = null) +/datum/action/chameleon_outfit/proc/select_outfit(mob/user) if(!user || !IsAvailable(feedback = FALSE)) return FALSE var/datum/outfit/O - if(isnull(outfit)) //If no outfit is passed, get the user to decide - var/selected = tgui_input_list(user, "Select outfit to change into", "Chameleon Outfit", outfit_options) - if(!IsAvailable(feedback = FALSE) || QDELETED(src) || QDELETED(user)) - return FALSE - var/outfit_type = outfit_options[selected] - if(!outfit_type) - return FALSE - O = new outfit_type() - var/list/outfit_types = O.get_chameleon_disguise_info() - for(var/V in user.chameleon_item_actions) - var/datum/action/item_action/chameleon/change/A = V - var/done = FALSE - for(var/T in outfit_types) - for(var/name in A.chameleon_list) - if(A.chameleon_list[name] == T) - A.update_look(user, T) - outfit_types -= T - done = TRUE - break - if(done) - break - else //If a specific outfit is passed through - var/list/types = outfit.get_chameleon_disguise_info() - for(var/T in types) - for(var/V in user.chameleon_item_actions) - var/datum/action/item_action/chameleon/change/A = V - if(istype(T, A.chameleon_type)) + var/selected = tgui_input_list(user, "Select outfit to change into", "Chameleon Outfit", outfit_options) + if(!IsAvailable(feedback = FALSE) || QDELETED(src) || QDELETED(user)) + return FALSE + var/outfit_type = outfit_options[selected] + if(!outfit_type) + return FALSE + O = new outfit_type() + var/list/outfit_types = O.get_chameleon_disguise_info() + for(var/V in user.chameleon_item_actions) + var/datum/action/item_action/chameleon/change/A = V + var/done = FALSE + for(var/T in outfit_types) + for(var/name in A.chameleon_list) + if(A.chameleon_list[name] == T) A.update_look(user, T) - return TRUE + outfit_types -= T + done = TRUE + break + if(done) + break //hardsuit helmets/suit hoods if(O.toggle_helmet && (ispath(O.suit, /obj/item/clothing/suit/space/hardsuit) || ispath(O.suit, /obj/item/clothing/suit/hooded)) && ishuman(user)) var/mob/living/carbon/human/H = user @@ -218,8 +209,17 @@ O.ears = T.ears O.glasses = T.glasses O.mask = T.wear_mask - var/datum/action/chameleon_outfit/select = locate(/datum/action/chameleon_outfit) in owner.actions - select.select_outfit(owner, O) + O.back = T.back + var/list/types = O.get_chameleon_disguise_info() + for(var/Y in types) + for(var/V in owner.chameleon_item_actions) + var/datum/action/item_action/chameleon/change/A = V + if(A.chameleon_blacklist[Y]) + continue + if(istype(Y, A.chameleon_type)) //Need to make sure it's the right type, wouldn't want to wear an armour vest on your head. + A.update_look(owner, Y) + A.copying = TRUE + A.copy_target = T to_chat(owner, span_notice("Successfully copied [T]!")) toggle_button() @@ -233,6 +233,8 @@ var/emp_timer var/current_disguise = null var/syndicate = FALSE + var/copying = FALSE + var/mob/living/copy_target /datum/action/item_action/chameleon/change/Grant(mob/M) if(M && (owner != M)) @@ -279,6 +281,7 @@ if(!picked_item) return update_look(user, picked_item) + copying = FALSE /datum/action/item_action/chameleon/change/proc/random_look(mob/user) var/picked_name = pick(chameleon_list) diff --git a/yogstation/code/modules/antagonists/infiltrator/objectives.dm b/yogstation/code/modules/antagonists/infiltrator/objectives.dm index da3b271a9c280..f5edd488b21d3 100644 --- a/yogstation/code/modules/antagonists/infiltrator/objectives.dm +++ b/yogstation/code/modules/antagonists/infiltrator/objectives.dm @@ -166,6 +166,17 @@ GLOBAL_LIST_INIT(infiltrator_kidnap_areas, typecacheof(list(/area/shuttle/yogs/s if(!considered_escaped(M)) continue var/mob/living/carbon/human/H = M.current + var/clothing = H.chameleon_item_actions.len //8 possible clothes: Head, suit, ears, glasses, uniform, shoes, gloves, backpack + var/copied = TRUE + for(var/datum/action/item_action/chameleon/change/V in H.chameleon_item_actions) + if(!V.copying) + clothing -= 1 + if(V.copy_target != target) + clothing -= 1 + if(clothing<3) //Some leniency if you don't have the required clothes or your target isn't wearing many, but not complete leniency + copied = FALSE + if(!copied) + continue if(H.get_id_name() == target_real_name || target_missing_id) return TRUE return FALSE From 2e4beb5cb6a95a511a74a2cc32690d46309fefe1 Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Mon, 2 Dec 2024 23:28:02 +0000 Subject: [PATCH 25/31] Refinements --- code/modules/clothing/chameleon.dm | 7 ++++--- .../code/modules/antagonists/infiltrator/objectives.dm | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 324b419f6c096..156e3d6ffa7c0 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -102,15 +102,15 @@ /datum/action/chameleon_outfit/proc/select_outfit(mob/user) if(!user || !IsAvailable(feedback = FALSE)) return FALSE - var/datum/outfit/O var/selected = tgui_input_list(user, "Select outfit to change into", "Chameleon Outfit", outfit_options) if(!IsAvailable(feedback = FALSE) || QDELETED(src) || QDELETED(user)) return FALSE var/outfit_type = outfit_options[selected] if(!outfit_type) return FALSE - O = new outfit_type() + var/datum/outfit/O = new outfit_type() var/list/outfit_types = O.get_chameleon_disguise_info() + for(var/V in user.chameleon_item_actions) var/datum/action/item_action/chameleon/change/A = V var/done = FALSE @@ -214,7 +214,8 @@ for(var/Y in types) for(var/V in owner.chameleon_item_actions) var/datum/action/item_action/chameleon/change/A = V - if(A.chameleon_blacklist[Y]) + var/obj/item/I = Y + if(A.chameleon_blacklist[Y] || (initial(I.item_flags) & ABSTRACT || !initial(I.icon_state))) continue if(istype(Y, A.chameleon_type)) //Need to make sure it's the right type, wouldn't want to wear an armour vest on your head. A.update_look(owner, Y) diff --git a/yogstation/code/modules/antagonists/infiltrator/objectives.dm b/yogstation/code/modules/antagonists/infiltrator/objectives.dm index f5edd488b21d3..c24df1102824f 100644 --- a/yogstation/code/modules/antagonists/infiltrator/objectives.dm +++ b/yogstation/code/modules/antagonists/infiltrator/objectives.dm @@ -166,15 +166,17 @@ GLOBAL_LIST_INIT(infiltrator_kidnap_areas, typecacheof(list(/area/shuttle/yogs/s if(!considered_escaped(M)) continue var/mob/living/carbon/human/H = M.current + var/mob/living/carbon/human/T = target.current var/clothing = H.chameleon_item_actions.len //8 possible clothes: Head, suit, ears, glasses, uniform, shoes, gloves, backpack var/copied = TRUE for(var/datum/action/item_action/chameleon/change/V in H.chameleon_item_actions) if(!V.copying) clothing -= 1 - if(V.copy_target != target) + if(V.copy_target != T) clothing -= 1 if(clothing<3) //Some leniency if you don't have the required clothes or your target isn't wearing many, but not complete leniency copied = FALSE + break if(!copied) continue if(H.get_id_name() == target_real_name || target_missing_id) From 8cbf7919ffaf8db35653f28dd3f5014812bad8b6 Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Sat, 14 Dec 2024 23:57:22 +0000 Subject: [PATCH 26/31] Adds chameleon copy sprite --- code/modules/clothing/chameleon.dm | 3 ++- yogstation/icons/mob/actions.dmi | Bin 17864 -> 18052 bytes 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 156e3d6ffa7c0..4f8e7724349b8 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -145,7 +145,8 @@ /datum/action/cooldown/chameleon_copy name = "Copy person" - button_icon_state = "default" //Temporary, just to test it works + button_icon = 'yogstation/icons/mob/actions.dmi' + button_icon_state = "chameleon_copy" var/target_range = 3 var/syndicate = FALSE var/active = FALSE diff --git a/yogstation/icons/mob/actions.dmi b/yogstation/icons/mob/actions.dmi index bff8dfb738f3bb885239f7efe848c39cd771bc6e..dec36ba80cb6284c19bdbdebff784dc7b09dd25a 100644 GIT binary patch delta 17157 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 Date: Sun, 15 Dec 2024 12:31:26 +0000 Subject: [PATCH 27/31] Gives them break machinery --- yogstation/code/modules/antagonists/infiltrator/team.dm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/yogstation/code/modules/antagonists/infiltrator/team.dm b/yogstation/code/modules/antagonists/infiltrator/team.dm index f072492996771..613aff84e82d4 100644 --- a/yogstation/code/modules/antagonists/infiltrator/team.dm +++ b/yogstation/code/modules/antagonists/infiltrator/team.dm @@ -98,7 +98,10 @@ else add_objective(/datum/objective/assassinate) else - add_objective(/datum/objective/steal) + if(prob(60)) + add_objective(/datum/objective/steal) + else + add_objective(/datum/objective/break_machinery) /datum/team/infiltrator/proc/add_objective(type) var/datum/objective/O = type From c25e9815265ecbc23d86952f788e5c6be69df1be Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Fri, 20 Dec 2024 19:41:56 +0000 Subject: [PATCH 28/31] Makes bad hardsuit list static --- .../code/modules/antagonists/infiltrator/items/hardsuit.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yogstation/code/modules/antagonists/infiltrator/items/hardsuit.dm b/yogstation/code/modules/antagonists/infiltrator/items/hardsuit.dm index 1525f9fa9d3ba..0cf4f58baf9aa 100644 --- a/yogstation/code/modules/antagonists/infiltrator/items/hardsuit.dm +++ b/yogstation/code/modules/antagonists/infiltrator/items/hardsuit.dm @@ -6,7 +6,7 @@ syndicate = TRUE var/current_disguise = /obj/item/clothing/suit/space/hardsuit/infiltration var/new_type = "engineering" - var/list/bad_hardsuits = list( + var/static/list/bad_hardsuits = list( /obj/item/clothing/suit/space/hardsuit/darktemplar, /obj/item/clothing/suit/space/hardsuit/darktemplar/chap, /obj/item/clothing/suit/space/hardsuit/cult, From 1faa6f9f887fb7af31710898128f0d483b3e0b45 Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Mon, 23 Dec 2024 22:39:07 +0000 Subject: [PATCH 29/31] Prevents chameleon copy duplicating --- code/modules/clothing/chameleon.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 4f8e7724349b8..bd45c95efe56d 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -260,6 +260,8 @@ if(!LAZYLEN(M.chameleon_item_actions)) var/datum/action/chameleon_outfit/O = locate(/datum/action/chameleon_outfit) in M.actions qdel(O) + var/datum/action/chameleon_copy/C = locate(/datum/action/chameleon_copy) in M.actions + qdel(C) return ..() /datum/action/item_action/chameleon/change/proc/initialize_disguises() From 118f79635e90d76d1c3f77dd1e0558b4bcbcb3de Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Mon, 23 Dec 2024 22:43:45 +0000 Subject: [PATCH 30/31] Okay, maybe I should have checked the typepath --- code/modules/clothing/chameleon.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index bd45c95efe56d..fda7bec902204 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -260,7 +260,7 @@ if(!LAZYLEN(M.chameleon_item_actions)) var/datum/action/chameleon_outfit/O = locate(/datum/action/chameleon_outfit) in M.actions qdel(O) - var/datum/action/chameleon_copy/C = locate(/datum/action/chameleon_copy) in M.actions + var/datum/action/cooldown/chameleon_copy/C = locate(/datum/action/cooldown/chameleon_copy) in M.actions qdel(C) return ..() From e08bc191c41a8c118c986925c7176e58941b7e2d Mon Sep 17 00:00:00 2001 From: Oblisk234 <61151679+Oblisk234@users.noreply.github.com> Date: Sat, 28 Dec 2024 20:49:06 +0000 Subject: [PATCH 31/31] Temporary event minimum lowering --- yogstation/code/modules/events/infiltrators.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yogstation/code/modules/events/infiltrators.dm b/yogstation/code/modules/events/infiltrators.dm index 0e69177226499..c1cb4bf00dae0 100644 --- a/yogstation/code/modules/events/infiltrators.dm +++ b/yogstation/code/modules/events/infiltrators.dm @@ -10,7 +10,7 @@ description = "Infiltrators will... infiltrate." map_flags = EVENT_SPACE_ONLY - min_players = 23 + min_players = 15 //Temporary, only for testmerge /datum/round_event_control/infiltrators/canSpawnEvent(players_amt, allow_magic = FALSE, fake_check = FALSE) . = ..()