From 4375bd7432f83d20f232ccf5f38d9c0e9402c993 Mon Sep 17 00:00:00 2001 From: Gandalf <9026500+Gandalf2k15@users.noreply.github.com> Date: Thu, 20 Jan 2022 04:15:15 +0000 Subject: [PATCH] The Opposing Force (OPFOR) - Ready for review/testing (#10093) * OPFOR PART ONE * 0 * E * E * 0 * E * e * Update opposing_force_datum.dm * E * E * Admin stuffs * Admin control GUI * E * Chat * 0 * Update opposing_force_datum.dm * System messages, better admin chat procs, UI fixes. * Update _basemap.dm * who thought holding a ref to the client was a good fucking idea? * 0 * Update opposing_force_datum.dm * Update modular_skyrat/modules/opposing_force/code/opposing_force_datum.dm * Equipment tab * equipment part 2 * Tidy up, finishing up equipments panel, some font fixes * clarity and continuity * Update opposing_force_datum.dm * more logic fixes * Update opposing_force_datum.dm * weeee * Update opposing_force_datum.dm * chat commands * 0 * ee * Update opposing_force_datum.dm * Itemspawning * Assassinate objectives only need one kill * new commands * Update opposing_force_datum.dm * f * weee roundend report * E * ew * E * E * more fixes * E * E * Update opposing_force_datum.dm * Update opposing_force_datum.dm * Fixes * request opfor * Update admin_procs.dm * Update adminhelp.dm * Update opposing_force_datum.dm * fex * admin info panel, approve checks, queue position checks * panel improvements, better logging format * Barboza equipment list Vol 1 (#10386) * Update opposing_force_equipment.dm * silly little changes to the silly little code i doubt this will be seen by anyone teehee * OpFor Prep Balance Shotguns have been prepped into opfor catalog. Model 23-37 is now an 8 rounder pump action, M2 is untouched as a semi auto peacekeeper variation and SAS14 is semi auto as it was meant to be * OpFor Prep Balance Shotguns have been prepped into opfor catalog. Model 23-37 is now an 8 rounder pump action, M2 is untouched as a semi auto peacekeeper variation and SAS14 is semi auto as it was meant to be. 23-37 keeps its beanbag load while M2 comes with slugs as a proper combat shotgun * Gear Pass 1 * Mag Variety for SAS14 Since its gonna be an opfor exclusive why not add some choices. Refilling its ammo is nigh impossible so here comes new mags! * Gear Pass 2 yes I 'code' in github web * Gear Pass 3 just martial arts and some stuff for today, tomorrow i add the discord suggestions * opfor equipment up the ass woo spider * descs for everyone * g357 * altyn * Gear Pass 4 syndicakes and nri * Item Variety Document for Opfor * gunman loadout * gunman update * Gear Pass 5 gear harder * Update opposing_force_equipment.dm * big typo fuckup fix * lcoat desc fix Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com> * Update modular_skyrat/modules/opposing_force/code/opposing_force_equipment.dm Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com> * Update modular_skyrat/modules/opposing_force/code/opposing_force_equipment.dm Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com> * Update modular_skyrat/modules/opposing_force/code/opposing_force_equipment.dm Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com> * Update modular_skyrat/modules/opposing_force/code/opposing_force_equipment.dm Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com> * Update modular_skyrat/modules/opposing_force/code/opposing_force_equipment.dm Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com> * Update modular_skyrat/modules/opposing_force/code/opposing_force_equipment.dm Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com> * Update modular_skyrat/modules/opposing_force/code/opposing_force_equipment.dm Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com> * DocNameChange also no more shamwow * Update opposing_force_equipment.dm * Update modular_skyrat/modules/sec_haul/code/guns/guns.dm Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com> * Update modular_skyrat/modules/sec_haul/code/guns/guns.dm Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com> * Update items.dm * Update opposing_force_equipment.dm * Update modular_skyrat/modules/opposing_force/code/items.dm Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com> * More Categories and Expanded Title Adds loadouts and explosives tab, increases title limit to 40 instead of 20 for objectives * Apply suggestions from code review Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com> Co-authored-by: dawsonkeyes <76002401+dawsonkeyes@users.noreply.github.com> Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com> Co-authored-by: Gandalf <9026500+Gandalf2k15@users.noreply.github.com> * Automatic changelog generation for PR #10386 [ci skip] * E * Update opposing_force_equipment.dm * E * Update items.dm * Vol2Remastered (#10413) * Update modular_skyrat/modules/opposing_force/code/opposing_force_datum.dm Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com> * Bye bye high-frequency sword * Fixed the space cash too * Review comments * Update counter.dm * general antagonist ban * opfor ban * Update opposing_force_subsystem.dm Co-authored-by: ErdinyoBarboza Co-authored-by: dawsonkeyes <76002401+dawsonkeyes@users.noreply.github.com> Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com> Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: GoldenAlpharex Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com> --- .../Deltastation/DeltaStation2_skyrat.dmm | 86 +- code/__DEFINES/~skyrat_defines/banning.dm | 2 + .../~skyrat_defines/opposing_force_defines.dm | 50 ++ code/__HELPERS/roundend.dm | 2 + .../gamemodes/dynamic/dynamic_rulesets.dm | 4 + .../dynamic/dynamic_rulesets_midround.dm | 8 + code/game/gamemodes/objective.dm | 2 +- code/modules/admin/admin_verbs.dm | 1 + code/modules/admin/check_antagonists.dm | 2 + code/modules/admin/sql_ban_system.dm | 4 +- code/modules/admin/verbs/adminhelp.dm | 5 + html/changelogs/AutoChangeLog-pr-10386.yml | 6 + .../code/game/gamemodes/objective.dm | 9 + .../opposing_force/code/admin_procs.dm | 12 + .../modules/opposing_force/code/items.dm | 49 + .../modules/opposing_force/code/mind.dm | 32 + .../code/opposing_force_datum.dm | 843 ++++++++++++++++++ .../code/opposing_force_equipment.dm | 560 ++++++++++++ .../code/opposing_force_subsystem.dm | 196 ++++ .../modules/opposing_force/code/roundend.dm | 14 + .../sound/application_recieved.ogg | Bin 0 -> 28950 bytes .../modules/opposing_force/sound/approved.ogg | Bin 0 -> 27114 bytes .../modules/opposing_force/sound/denied.ogg | Bin 0 -> 28654 bytes .../opposing_force/sound/update_requested.ogg | Bin 0 -> 24936 bytes .../modules/sec_haul/code/guns/guns.dm | 29 +- .../modules/ticket_counter/code/counter.dm | 6 +- tgstation.dme | 9 + .../tgui-panel/styles/goon/chat-dark.scss | 5 + .../tgui-panel/styles/goon/chat-light.scss | 5 + .../tgui/interfaces/OpposingForcePanel.js | 777 ++++++++++++++++ 30 files changed, 2665 insertions(+), 53 deletions(-) create mode 100644 code/__DEFINES/~skyrat_defines/opposing_force_defines.dm create mode 100644 html/changelogs/AutoChangeLog-pr-10386.yml create mode 100644 modular_skyrat/master_files/code/game/gamemodes/objective.dm create mode 100644 modular_skyrat/modules/opposing_force/code/admin_procs.dm create mode 100644 modular_skyrat/modules/opposing_force/code/items.dm create mode 100644 modular_skyrat/modules/opposing_force/code/mind.dm create mode 100644 modular_skyrat/modules/opposing_force/code/opposing_force_datum.dm create mode 100644 modular_skyrat/modules/opposing_force/code/opposing_force_equipment.dm create mode 100644 modular_skyrat/modules/opposing_force/code/opposing_force_subsystem.dm create mode 100644 modular_skyrat/modules/opposing_force/code/roundend.dm create mode 100644 modular_skyrat/modules/opposing_force/sound/application_recieved.ogg create mode 100644 modular_skyrat/modules/opposing_force/sound/approved.ogg create mode 100644 modular_skyrat/modules/opposing_force/sound/denied.ogg create mode 100644 modular_skyrat/modules/opposing_force/sound/update_requested.ogg create mode 100644 tgui/packages/tgui/interfaces/OpposingForcePanel.js diff --git a/_maps/map_files/Deltastation/DeltaStation2_skyrat.dmm b/_maps/map_files/Deltastation/DeltaStation2_skyrat.dmm index 173a2a8dfd8..d188e220f80 100644 --- a/_maps/map_files/Deltastation/DeltaStation2_skyrat.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2_skyrat.dmm @@ -8590,6 +8590,21 @@ }, /turf/open/floor/iron/grimy, /area/service/chapel/office) +"bwU" = ( +/obj/structure/destructible/cult/item_dispenser/archives, +/obj/item/book/codex_gigas, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/turf/open/floor/iron/dark, +/area/service/library) "bwY" = ( /obj/structure/closet/wardrobe/botanist, /obj/effect/decal/cleanable/dirt, @@ -11505,24 +11520,6 @@ }, /turf/open/floor/iron/dark, /area/ai_monitored/security/armory) -"bPA" = ( -/obj/structure/closet/secure_closet/contraband/armory, -/obj/machinery/light/directional/east, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/obj/item/gun/ballistic/rifle/boltaction, -/obj/effect/spawner/random/maintenance/three, -/obj/effect/spawner/random/contraband/armory, -/turf/open/floor/iron/dark, -/area/ai_monitored/security/armory) "bPC" = ( /turf/closed/wall/r_wall, /area/ai_monitored/turret_protected/aisat_interior) @@ -50879,6 +50876,24 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/security/brig) +"iFP" = ( +/obj/structure/closet/secure_closet/contraband/armory, +/obj/machinery/light/directional/east, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/item/gun/ballistic/rifle/boltaction, +/obj/effect/spawner/random/maintenance/three, +/obj/effect/spawner/random/contraband/armory, +/turf/open/floor/iron/dark, +/area/ai_monitored/security/armory) "iFY" = ( /obj/structure/chair/office{ dir = 1 @@ -55417,6 +55432,13 @@ /obj/machinery/bluespace_vendor/directional/north, /turf/open/floor/iron, /area/hallway/primary/central/aft) +"jZH" = ( +/obj/structure/destructible/cult/item_dispenser/archives, +/obj/effect/decal/cleanable/cobweb, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/blood/old, +/turf/open/floor/plating, +/area/service/library/abandoned) "jZK" = ( /obj/structure/window/reinforced{ dir = 8 @@ -66476,21 +66498,6 @@ }, /turf/open/floor/iron/dark, /area/command/heads_quarters/ce) -"nbt" = ( -/obj/structure/destructible/cult/item_dispenser/archives, -/obj/item/book/codex_gigas, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/iron/dark, -/area/service/library) "nbv" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -81247,13 +81254,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/wood, /area/command/meeting_room/council) -"qXG" = ( -/obj/structure/destructible/cult/item_dispenser/archives, -/obj/effect/decal/cleanable/cobweb, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/blood/old, -/turf/open/floor/plating, -/area/service/library/abandoned) "qXO" = ( /obj/machinery/camera/directional/north{ c_tag = "Atmospherics - Aft"; @@ -138261,7 +138261,7 @@ lVS elW fHw ert -qXG +jZH oof ewK reb @@ -139492,7 +139492,7 @@ fVp qGH nJo ssD -nbt +bwU pAm nJo tHl @@ -161059,7 +161059,7 @@ aaa aad bLs bNt -bPA +iFP bRw bTk bVr diff --git a/code/__DEFINES/~skyrat_defines/banning.dm b/code/__DEFINES/~skyrat_defines/banning.dm index 5623762b86f..1b25b67f568 100644 --- a/code/__DEFINES/~skyrat_defines/banning.dm +++ b/code/__DEFINES/~skyrat_defines/banning.dm @@ -5,3 +5,5 @@ #define BAN_GHOST_ROLE_SPAWNER "Ghost role spawner ban" #define BAN_GHOST_TAKEOVER "Ghost candidate ban" #define BAN_EORG "EORG ban" +#define BAN_ANTAGONIST "General antagonist ban" +#define BAN_OPFOR "OPFOR ban" diff --git a/code/__DEFINES/~skyrat_defines/opposing_force_defines.dm b/code/__DEFINES/~skyrat_defines/opposing_force_defines.dm new file mode 100644 index 00000000000..0e998bbbf6a --- /dev/null +++ b/code/__DEFINES/~skyrat_defines/opposing_force_defines.dm @@ -0,0 +1,50 @@ +#define OPFOR_BACKSTORY_MIN_CHARS 100 +#define OPFOR_BACKSTORY_MAX_CHARS 500 + +#define OPFOR_MAX_OBJECTIVES 5 + +#define OPFOR_STATUS_NOT_SUBMITTED "Not submitted" +#define OPFOR_STATUS_APPROVED "Approved" +#define OPFOR_STATUS_DENIED "Denied" +#define OPFOR_STATUS_AWAITING_APPROVAL "Awaiting approval" +#define OPFOR_STATUS_CHANGES_REQUESTED "Changes requested" + +#define OPFOR_OBJECTIVE_STATUS_NOT_REVIEWED "Not Reviewed" +#define OPFOR_OBJECTIVE_STATUS_APPROVED "Approved" +#define OPFOR_OBJECTIVE_STATUS_DENIED "Denied" + +#define OPFOR_OBJECTIVE_INTENSITY_1 "1 - Minor theft or basic antagonizing" +#define OPFOR_OBJECTIVE_INTENSITY_2 "2 - Kidnapping / Theft" +#define OPFOR_OBJECTIVE_INTENSITY_3 "3 - Assassination / Grand Theft" +#define OPFOR_OBJECTIVE_INTENSITY_4 "4 - Mass sabotage (engine delamination)" +#define OPFOR_OBJECTIVE_INTENSITY_5 "5 - Mass destruction or mass killings" + +#define OPFOR_SUBSYSTEM_REJECT_CAP "OPFOR application system has reached the maximum number of applications" +#define OPFOR_SUBSYSTEM_REJECT_CLOSED "OPFOR application system is not accepting new applications" +#define OPFOR_SUBSYSTEM_READY "OPFOR application system is ready to accept new applications" + +#define OPFOR_REQUEST_UPDATE_COOLDOWN 1 MINUTES +#define OPFOR_PING_COOLDOWN 1 MINUTES + +#define OPFOR_TEXT_LIMIT_TITLE 40 +#define OPFOR_TEXT_LIMIT_BACKSTORY 1000 +#define OPFOR_TEXT_LIMIT_DESCRIPTION 500 +#define OPFOR_TEXT_LIMIT_JUSTIFICATION 500 +#define OPFOR_TEXT_LIMIT_MESSAGE 300 + +#define OPFOR_EQUIPMENT_LIMIT 10 +#define OPFOR_EQUIPMENT_COUNT_LIMIT 5 + +#define OPFOR_EQUIPMENT_STATUS_NOT_REVIEWED "Not Reviewed" +#define OPFOR_EQUIPMENT_STATUS_APPROVED "Approved" +#define OPFOR_EQUIPMENT_STATUS_DENIED "Denied" + +// EQUIPMENT CATEGORIES +#define OPFOR_EQUIPMENT_CATEGORY_RANGED_WEAPONS "Ranged Weapons" +#define OPFOR_EQUIPMENT_CATEGORY_MELEE_WEAPONS "Melee Weapons" +#define OPFOR_EQUIPMENT_CATEGORY_AMMUNITION "Ammunition" +#define OPFOR_EQUIPMENT_CATEGORY_CLOTHING "Clothing" +#define OPFOR_EQUIPMENT_CATEGORY_UTILITY "Utility" +#define OPFOR_EQUIPMENT_CATEGORY_EXPLOSIVES "Explosives" +#define OPFOR_EQUIPMENT_CATEGORY_LOADOUT "Loadouts" +#define OPFOR_EQUIPMENT_CATEGORY_OTHER "Other" diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index a5c91d88fda..2c2f2a82547 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -311,6 +311,8 @@ //Antagonists parts += antag_report() + parts += opfor_report() //SKYRAT EDIT ADDITION + parts += hardcore_random_report() CHECK_TICK diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets.dm b/code/game/gamemodes/dynamic/dynamic_rulesets.dm index e5e2cbfe836..896140985c3 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets.dm @@ -206,6 +206,10 @@ if(!candidate_client.prefs?.read_preference(/datum/preference/toggle/be_antag)) candidates.Remove(candidate_player) continue + + if(is_banned_from(candidate_client.ckey, BAN_ANTAGONIST)) + candidates.Remove(candidate_player) + continue //SKYRAT EDIT END if(candidate_client.get_remaining_days(minimum_required_age) > 0) diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index b1b60bb261c..532ca7b6692 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -43,6 +43,14 @@ if (!M.client) // Are they connected? trimmed_list.Remove(M) continue + //SKYRAT EDIT ADDITION + if(is_banned_from(M.client.ckey, BAN_ANTAGONIST)) + trimmed_list.Remove(M) + continue + if(!M.client?.prefs?.read_preference(/datum/preference/toggle/be_antag)) + trimmed_list.Remove(M) + continue + //SKYRAT EDIT END if(M.client.get_remaining_days(minimum_required_age) > 0) trimmed_list.Remove(M) continue diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 7e26167dcff..8f99273d6d4 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -201,7 +201,7 @@ GLOBAL_LIST_EMPTY(objectives) //SKYRAT EDIT ADDITION /datum/objective/assassinate/update_explanation_text() ..() if(target?.current) - explanation_text = "Assassinate [target.name], the [!target_role_type ? target.assigned_role.title : target.special_role]." + explanation_text = "Assassinate [target.name], the [!target_role_type ? target.assigned_role.title : target.special_role] ONCE." //SKYRAT EDIT CHANGE else explanation_text = "Free Objective" diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index c2776b46581..f9e68770a04 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -95,6 +95,7 @@ GLOBAL_PROTECT(admin_verbs_sounds) GLOBAL_LIST_INIT(admin_verbs_fun, list( /client/proc/one_click_antag, // SKYRAT EDIT ADDITION - ONE CLICK ANTAG /client/proc/spawn_mob_spawner, // SKYRAT EDIT ADDITION + /client/proc/request_more_opfor, //SKYRAT EDIT ADDITION /client/proc/cmd_select_equipment, /client/proc/cmd_admin_gib_self, /client/proc/drop_bomb, diff --git a/code/modules/admin/check_antagonists.dm b/code/modules/admin/check_antagonists.dm index 1c0581c0282..358e85f79eb 100644 --- a/code/modules/admin/check_antagonists.dm +++ b/code/modules/admin/check_antagonists.dm @@ -191,5 +191,7 @@ dat += build_antag_listing() + dat += SSopposing_force.get_check_antag_listing() //SKYRAT EDIT ADDITION + dat += "" usr << browse(dat.Join(), "window=roundstatus;size=500x500") diff --git a/code/modules/admin/sql_ban_system.dm b/code/modules/admin/sql_ban_system.dm index d4f3fc94ec6..3a9e3e92a24 100644 --- a/code/modules/admin/sql_ban_system.dm +++ b/code/modules/admin/sql_ban_system.dm @@ -367,7 +367,9 @@ BAN_MOB_CONTROL, BAN_GHOST_ROLE_SPAWNER, BAN_GHOST_TAKEOVER, - BAN_EORG + BAN_EORG, + BAN_ANTAGONIST, + BAN_OPFOR, ),//SKYRAT EDIT ADDITION - EXTRA_BANS ) for(var/department in long_job_lists) diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 8deb89e2199..29fbac6edb0 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -112,6 +112,11 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) L[++L.len] = list("Closed Tickets:", "[cstatclick.update("[closed_tickets.len]")]", null, REF(cstatclick)) L[++L.len] = list("Resolved Tickets:", "[rstatclick.update("[resolved_tickets.len]")]", null, REF(rstatclick)) + //SKYRAT EDIT ADDITION + if(LAZYLEN(SSopposing_force.submitted_applications)) + for(var/datum/opposing_force/opposing_force as anything in SSopposing_force.submitted_applications) + L[++L.len] = list("[opposing_force.handling_admin ? "H-[opposing_force.handling_admin]. " : ""]OPFOR: [opposing_force.ckey]", null, REF(opposing_force)) + //SKYRAT EDIT END return L //Reassociate still open ticket if one exists diff --git a/html/changelogs/AutoChangeLog-pr-10386.yml b/html/changelogs/AutoChangeLog-pr-10386.yml new file mode 100644 index 00000000000..444243dbce3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10386.yml @@ -0,0 +1,6 @@ +author: "ErdinyoBarboza" +delete-after: True +changes: + - rscadd: "added new variations of uplink and rag and more sas14 ammo +expansion: Added a load of items to opfor list" + - balance: "rebalanced armory shotguns to be used in opfor" diff --git a/modular_skyrat/master_files/code/game/gamemodes/objective.dm b/modular_skyrat/master_files/code/game/gamemodes/objective.dm new file mode 100644 index 00000000000..fc7d654c80f --- /dev/null +++ b/modular_skyrat/master_files/code/game/gamemodes/objective.dm @@ -0,0 +1,9 @@ +// For modularity, we hook into the update_explanation_text to be sure we have a target to register. +/datum/objective/assassinate/update_explanation_text() + RegisterSignal(target, COMSIG_LIVING_DEATH, .proc/register_target_death) + return ..() + +/datum/objective/assassinate/proc/register_target_death(mob/living/dead_guy, gibbed) + SIGNAL_HANDLER + completed = TRUE + UnregisterSignal(dead_guy, COMSIG_LIVING_DEATH) diff --git a/modular_skyrat/modules/opposing_force/code/admin_procs.dm b/modular_skyrat/modules/opposing_force/code/admin_procs.dm new file mode 100644 index 00000000000..f81d98b0bd8 --- /dev/null +++ b/modular_skyrat/modules/opposing_force/code/admin_procs.dm @@ -0,0 +1,12 @@ +/client/proc/request_more_opfor() + set category = "Admin.Fun" + set name = "Request OPFOR" + set desc = "Request players sign up for opfor if they have antag on." + + var/asked = 0 + for(var/mob/living/carbon/human/human in GLOB.alive_player_list) + if(human.client?.prefs?.read_preference(/datum/preference/toggle/be_antag)) + to_chat(human, examine_block(span_greentext("The admins are looking for OPFOR players, if you're interested, sign up in the OOC tab!"))) + asked++ + message_admins("[ADMIN_LOOKUP(usr)] has requested more OPFOR players! (Asked: [asked] players)") + diff --git a/modular_skyrat/modules/opposing_force/code/items.dm b/modular_skyrat/modules/opposing_force/code/items.dm new file mode 100644 index 00000000000..4908c63b78e --- /dev/null +++ b/modular_skyrat/modules/opposing_force/code/items.dm @@ -0,0 +1,49 @@ +//Use this to add item variations + +/obj/item/uplink/opfor + name = "old radio" + desc = "A dusty and old looking radio." + +/obj/item/uplink/opfor/Initialize(mapload, owner, tc_amount = 0) + . = ..() + var/datum/component/uplink/hidden_uplink = GetComponent(/datum/component/uplink) + hidden_uplink.name = "old radio" + + + +/obj/item/reagent_containers/glass/rag/large + volume = 30 + amount_per_transfer_from_this = 30 + desc = "A damp rag made from a highly absorbant materials. Can hold up to 30u liquids. You can also clean up messes I guess." + + +/obj/item/storage/box/syndie_kit/gunman_outfit + name = "Gunman Clothing Bundle" + desc = "A box filled with armored and stylish clothing for the aspiring gunmans." + +/obj/item/clothing/suit/armor/vest/leather/gunman + name = "leather overcoat" + desc = "An armored leather overcoat, intended as the go-to wear for any aspiring gunman." + body_parts_covered = CHEST|GROIN|ARMS + armor = list(MELEE = 45, BULLET = 40, LASER = 40, ENERGY = 50, BOMB = 25, BIO = 0, FIRE = 50, ACID = 50, WOUND = 10) //makes it in line with the rest of the armor + +/obj/item/storage/box/syndie_kit/gunman_outfit/PopulateContents() // 45, 40 armor on general without a helmet. + new /obj/item/clothing/under/pants/black/robohand(src) + new /obj/item/clothing/glasses/sunglasses/robohand(src) + new /obj/item/clothing/suit/armor/vest/leather/gunman(src) + new /obj/item/clothing/shoes/combat(src) + +/obj/item/ammo_box/magazine/m16/extended //i will add custom sprites to this + name = "m4a1 magazine (5.56×45mm)" + icon = 'modular_skyrat/modules/gunsgalore/icons/guns/m16/m16.dmi' + icon_state = "5.56mm" + ammo_type = /obj/item/ammo_casing/a556 + caliber = "a556" + max_ammo = 30 + multiple_sprites = AMMO_BOX_FULL_EMPTY + + + + +/obj/item/autosurgeon/organ/syndicate/hackerman + starting_organ = /obj/item/organ/cyberimp/arm/hacker diff --git a/modular_skyrat/modules/opposing_force/code/mind.dm b/modular_skyrat/modules/opposing_force/code/mind.dm new file mode 100644 index 00000000000..bc150beccb5 --- /dev/null +++ b/modular_skyrat/modules/opposing_force/code/mind.dm @@ -0,0 +1,32 @@ +/datum/mind + var/datum/opposing_force/opposing_force + +/datum/mind/Destroy() + QDEL_NULL(opposing_force) + return ..() + +/mob/verb/opposing_force() + set name = "Opposing Force" + set category = "OOC" + set desc = "View your opposing force panel, or request one." + // Mind checks + if(!mind) + var/fail_message = "You have no mind!" + if(isobserver(src)) + fail_message += " You have to be in the current round at some point to have one." + to_chat(src, span_warning(fail_message)) + return + + if(is_banned_from(ckey, BAN_ANTAGONIST)) + to_chat(src, span_warning("You are antagonist banned!")) + return + + if(is_banned_from(ckey, BAN_OPFOR)) + to_chat(src, span_warning("You are OPFOR banned!")) + return + + if(!mind.opposing_force) + var/datum/opposing_force/opposing_force = new(mind) + mind.opposing_force = opposing_force + SSopposing_force.new_opfor(opposing_force) + mind.opposing_force.ui_interact(usr) diff --git a/modular_skyrat/modules/opposing_force/code/opposing_force_datum.dm b/modular_skyrat/modules/opposing_force/code/opposing_force_datum.dm new file mode 100644 index 00000000000..c20e54c0d1c --- /dev/null +++ b/modular_skyrat/modules/opposing_force/code/opposing_force_datum.dm @@ -0,0 +1,843 @@ +/datum/opposing_force_selected_equipment + /// Reference to the selected equipment datum. + var/datum/opposing_force_equipment/opposing_force_equipment + /// Why does the user need this? + var/reason = "" + /// What is the status of this item? + var/status = OPFOR_EQUIPMENT_STATUS_NOT_REVIEWED + /// If denied, why? + var/denied_reason = "" + /// How many does the user want? + var/count = 1 + +/datum/opposing_force_selected_equipment/New(datum/opposing_force_equipment/opfor_equipment) + if(opfor_equipment) + opposing_force_equipment = opfor_equipment + +/datum/opposing_force_selected_equipment/Destroy(force, ...) + opposing_force_equipment = null + return ..() + +/datum/opposing_force_objective + /// The name of the objective + var/title = "" + /// The actual objective. + var/description = "" + /// The reason for the objective. + var/justification = "" + /// Was this specific objective approved by the admins? + var/status = OPFOR_OBJECTIVE_STATUS_NOT_REVIEWED + /// Why was this objective denied? If a reason was specified. + var/denied_reason = "" + /// How intense is this goal? + var/intensity = 1 + /// The text intensity of this goal + var/text_intensity = OPFOR_OBJECTIVE_INTENSITY_1 + +/datum/opposing_force + /// A list of objectives. + var/list/objectives = list() + /// A list of items they want spawned. + var/list/requested_items = list() + /// Justification for wanting to do bad things. + var/set_backstory = "" + /// Has this been approved? + var/status = OPFOR_STATUS_NOT_SUBMITTED + /// Hard ref to our mind. + var/datum/mind/mind_reference + /// For logging stuffs + var/list/modification_log = list() + /// Can we edit things? + var/can_edit = TRUE + /// The reason we were denied. + var/denied_reason = "" + /// Any changes required + var/requested_changes + /// Have we been request update muted by an admin? + var/request_updates_muted = FALSE + /// A text list of the admin chat. + var/list/admin_chat = list() + /// Have we issued the player their equipment? + var/equipment_issued = FALSE + /// A list of equipment that the user has requested. + var/list/selected_equipment = list() + /// Are we blocked from submitting a new request? + var/blocked = FALSE + /// What admin has this request been assigned to? + var/handling_admin = "" + /// What changes have the handling admin requested, if any? + var/admin_requested_changes = "" + /// The ckey of the person that made this application + var/ckey + + COOLDOWN_DECLARE(static/request_update_cooldown) + COOLDOWN_DECLARE(static/ping_cooldown) + +/datum/opposing_force/New(datum/mind/mind_reference) + src.mind_reference = mind_reference + ckey = ckey(mind_reference.key) + send_system_message("[ckey] created the application") + +/datum/opposing_force/Destroy(force) + mind_reference.opposing_force = null + mind_reference = null + SSopposing_force.remove_opfor(src) + QDEL_LIST(objectives) + QDEL_LIST(admin_chat) + QDEL_LIST(modification_log) + return ..() + +/datum/opposing_force/Topic(href, list/href_list) + if(href_list["admin_pref"]) + if(!check_rights(R_ADMIN)) + CRASH("Opposing_force TOPIC: Detected possible HREF exploit! ([usr])") + ui_interact(usr) + return TRUE + +/// Builds the HTML panel entry for the round end report +/datum/opposing_force/proc/build_html_panel_entry() + var/list/opfor_entry = list("[mind_reference.key] - ") + opfor_entry += "PM " + if(mind_reference.current) + opfor_entry += "FLW " + opfor_entry += "Show OPFOR Panel" + return opfor_entry.Join() + +/datum/opposing_force/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "OpposingForcePanel") + ui.open() + +/datum/opposing_force/ui_state(mob/user) + return GLOB.always_state + +/datum/opposing_force/ui_data(mob/user) + var/list/data = list() + + var/client/owner_client = GLOB.directory[ckey] + data["admin_mode"] = check_rights_for(user.client, R_DEFAULT) && user.client != owner_client + + data["creator_ckey"] = ckey + + data["owner_antag"] = (mind_reference.current in GLOB.current_living_antags) + + data["backstory"] = set_backstory + + data["raw_status"] = status + + data["status"] = get_status_string() + + data["can_submit"] = SSopposing_force.accepting_objectives && (status == OPFOR_STATUS_NOT_SUBMITTED || status == OPFOR_STATUS_CHANGES_REQUESTED) + + data["can_request_update"] = (status == OPFOR_STATUS_AWAITING_APPROVAL && COOLDOWN_FINISHED(src, request_update_cooldown)) + + data["request_updates_muted"] = request_updates_muted + + data["blocked"] = blocked + + data["can_edit"] = can_edit + + data["approved"] = status == OPFOR_STATUS_APPROVED ? TRUE : FALSE + + data["denied"] = status == OPFOR_STATUS_DENIED ? TRUE : FALSE + + data["handling_admin"] = handling_admin + + data["equipment_issued"] = equipment_issued + + data["owner_mob"] = mind_reference.current ? mind_reference.current.name : "No mob!" + + data["owner_role"] = mind_reference.assigned_role ? mind_reference.assigned_role.title : "No role!" + + var/list/messages = list() + for(var/message in admin_chat) + messages.Add(list(list( + "msg" = message + ))) + data["messages"] = messages + + data["objectives"] = list() + var/objective_num = 1 + for(var/datum/opposing_force_objective/opfor as anything in objectives) + var/list/objective_data = list( + "id" = objective_num, + "ref" = REF(opfor), + "title" = opfor.title, + "description" = opfor.description, + "intensity" = opfor.intensity, + "text_intensity" = opfor.text_intensity, + "justification" = opfor.justification, + "approved" = opfor.status == OPFOR_OBJECTIVE_STATUS_APPROVED ? TRUE : FALSE, + "status_text" = opfor.status, + "denied_text" = opfor.denied_reason, + ) + objective_num++ + data["objectives"] += list(objective_data) + + data["equipment_issued"] = equipment_issued + + data["equipment_list"] = list() + for(var/equipment_category in SSopposing_force.equipment_list) + var/category_items = list() + for(var/datum/opposing_force_equipment/opfor_equipment as anything in SSopposing_force.equipment_list[equipment_category]) + category_items += list(list( + "ref" = REF(opfor_equipment), + "name" = opfor_equipment.name, + "description" = opfor_equipment.description, + "equipment_category" = opfor_equipment.category, + )) + data["equipment_list"] += list(list( + "category" = equipment_category, + "items" = category_items, + )) + + data["selected_equipment"] = list() + for(var/datum/opposing_force_selected_equipment/equipment as anything in selected_equipment) + var/list/equipment_data = list( + "ref" = REF(equipment), + "name" = equipment.opposing_force_equipment.name, + "description" = equipment.opposing_force_equipment.description, + "item" = equipment.opposing_force_equipment.item_type, + "status" = equipment.status, + "approved" = equipment.status == OPFOR_EQUIPMENT_STATUS_APPROVED ? TRUE : FALSE, + "reason" = equipment.reason, + "denied_reason" = equipment.denied_reason, + "count" = equipment.count, + ) + data["selected_equipment"] += list(equipment_data) + + return data + +/datum/opposing_force/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + var/datum/opposing_force_objective/edited_objective + if(params["objective_ref"]) + edited_objective = locate(params["objective_ref"]) in objectives + if(!edited_objective) + return + + switch(action) + // General control + if("set_backstory") + set_backstory(usr, params["backstory"]) + if("request_update") + request_update(usr) + if("modify_request") + modify_request(usr) + if("close_application") + close_application(usr) + if("submit") + submit_to_subsystem(usr) + if("send_message") + send_message(usr, params["message"]) + // Objective control + if("add_objective") + add_objective(usr) + if("remove_objective") + remove_objective(usr, edited_objective) + if("set_objective_title") + set_objective_title(usr, edited_objective, params["title"]) + if("set_objective_description") + set_objective_description(usr, edited_objective, params["new_desciprtion"]) + if("set_objective_justification") + set_objective_justification(usr, edited_objective, params["new_justification"]) + if("set_objective_intensity") + set_objective_intensity(usr, edited_objective, params["new_intensity_level"]) + // Equipment control + if("select_equipment") + var/datum/opposing_force_equipment/equipment + for(var/category in SSopposing_force.equipment_list) + equipment = locate(params["equipment_ref"]) in SSopposing_force.equipment_list[category] + if(equipment) + break + if(!equipment) + return + select_equipment(usr, equipment) + if("remove_equipment") + var/datum/opposing_force_selected_equipment/equipment = locate(params["selected_equipment_ref"]) in selected_equipment + if(!equipment) + return + remove_equipment(usr, equipment) + if("set_equipment_reason") + var/datum/opposing_force_selected_equipment/equipment = locate(params["selected_equipment_ref"]) in selected_equipment + if(!equipment) + return + set_equipment_reason(usr, equipment, params["new_equipment_reason"]) + if("set_equipment_count") + var/datum/opposing_force_selected_equipment/equipment = locate(params["selected_equipment_ref"]) in selected_equipment + if(!equipment) + return + set_equipment_count(usr, equipment, params["new_equipment_count"]) + + //Admin protected procs + if("approve") + if(!check_rights(R_ADMIN)) + return + for(var/datum/opposing_force_objective/objective as anything in objectives) + if(objective.status == OPFOR_OBJECTIVE_STATUS_NOT_REVIEWED) + to_chat(usr, examine_block(span_command_headset(span_pink("OPFOR: ERROR, some objectives have not been reviewed. Please approve/deny all objectives.")))) + return + for(var/datum/opposing_force_selected_equipment/equipment as anything in selected_equipment) + if(equipment.status == OPFOR_EQUIPMENT_STATUS_NOT_REVIEWED) + to_chat(usr, examine_block(span_command_headset(span_pink("OPFOR: ERROR, some equipment requests have not been reviewed. Please approve/deny all equipment requests.")))) + return + SSopposing_force.approve(src, usr) + if("approve_all") + if(!check_rights(R_ADMIN)) + return + approve_all(usr) + if("handle") + handle(usr) + if("issue_gear") + if(!check_rights(R_ADMIN)) + return + issue_gear(usr) + if("deny") + if(!check_rights(R_ADMIN)) + return + var/denied_reason = tgui_input_text(usr, "Denial Reason", "Enter a reason for denying this application:") + // Checking to see if the user is spamming the button, async and all. + if(status == OPFOR_STATUS_DENIED) + return + SSopposing_force.deny(src, denied_reason, usr) + if("mute_request_updates") + if(!check_rights(R_ADMIN)) + return + mute_request_updates(usr) + if("toggle_block") + if(!check_rights(R_ADMIN)) + return + toggle_block(usr) + if("approve_objective") + if(!check_rights(R_ADMIN)) + return + approve_objective(usr, edited_objective) + if("deny_objective") + if(!check_rights(R_ADMIN)) + return + var/denied_reason = tgui_input_text(usr, "Denial Reason", "Enter a reason for denying this objective:") + deny_objective(usr, edited_objective, denied_reason) + if("approve_equipment") + var/datum/opposing_force_selected_equipment/equipment = locate(params["selected_equipment_ref"]) in selected_equipment + if(!equipment) + return + if(!check_rights(R_ADMIN)) + return + approve_equipment(usr, equipment) + if("deny_equipment") + var/datum/opposing_force_selected_equipment/equipment = locate(params["selected_equipment_ref"]) in selected_equipment + if(!equipment) + return + if(!check_rights(R_ADMIN)) + return + var/denied_reason = tgui_input_text(usr, "Denial Reason", "Enter a reason for denying this objective:") + deny_equipment(usr, equipment, denied_reason) + if("flw_user") + if(!check_rights(R_ADMIN)) + return + flw_user(usr) + +/datum/opposing_force/proc/flw_user(mob/user) + user.client?.admin_follow(mind_reference.current) + +/datum/opposing_force/proc/set_equipment_count(mob/user, datum/opposing_force_selected_equipment/equipment, new_count) + var/sanitized_newcount = sanitize_integer(new_count, 1, OPFOR_EQUIPMENT_COUNT_LIMIT) + equipment.count = new_count + add_log(user.ckey, "Set equipment '[equipment.opposing_force_equipment.name] count to [sanitized_newcount]") + +/datum/opposing_force/proc/handle(mob/user) + if(handling_admin) + var/choice = tgui_alert(user, "Another admin is currently handling this application, do you want to override them?", "Admin Handling", list("Yes", "No")) + if(choice == "No") + return + handling_admin = get_admin_ckey(user) + to_chat(mind_reference.current, examine_block(span_nicegreen("Your OPFOR application is now being handled by [handling_admin]."))) + send_admins_opfor_message("HANDLE: [ADMIN_LOOKUPFLW(user)] is handling [mind_reference.key]'s OPFOR application.") + send_system_message("[handling_admin] has assigned themselves to this application") + add_log(user.ckey, "Assigned self to application") + +/datum/opposing_force/proc/mute_request_updates(mob/user, override = "none") + if(override != "none") + request_updates_muted = override + else + request_updates_muted = !request_updates_muted + send_system_message("[user ? get_admin_ckey(user) : "The OPFOR subsystem"] [request_updates_muted ? "muted" : "unmuted"] the help requests function") + add_log(user.ckey, "[request_updates_muted ? "Muted" : "Unmuted"] user from opposing force help requests.") + +/datum/opposing_force/proc/toggle_block(mob/user, override = "none") + if(override != "none") + blocked = override + else + blocked = !blocked + send_system_message("[user ? get_admin_ckey(user) : "The OPFOR subsystem"] blocked you from submitting new requests") + add_log(user.ckey, "Blocked user from opposing force requests.") + +/** + * Equipment procs + */ + +/datum/opposing_force/proc/deny_equipment(mob/user, datum/opposing_force_selected_equipment/incoming_equipment, denied_reason = "") + if(incoming_equipment.status == OPFOR_EQUIPMENT_STATUS_DENIED) + return + incoming_equipment.status = OPFOR_EQUIPMENT_STATUS_DENIED + incoming_equipment.denied_reason = denied_reason + send_system_message("[user ? get_admin_ckey(user) : "The OPFOR subsystem"] has denied equipment '[incoming_equipment.opposing_force_equipment.name]'[denied_reason ? " with the reason '[denied_reason]'" : ""]") + add_log(user.ckey, "Denied equipment: [incoming_equipment.opposing_force_equipment.name] with reason: [denied_reason]") + +/datum/opposing_force/proc/approve_equipment(mob/user, datum/opposing_force_selected_equipment/incoming_equipment) + if(incoming_equipment.status == OPFOR_EQUIPMENT_STATUS_APPROVED) + return + incoming_equipment.status = OPFOR_EQUIPMENT_STATUS_APPROVED + incoming_equipment.denied_reason = "" + send_system_message("[user ? get_admin_ckey(user) : "The OPFOR subsystem"] has approved equipment '[incoming_equipment.opposing_force_equipment.name]'") + add_log(user.ckey, "Approved equipment: [incoming_equipment.opposing_force_equipment.name]") + +/datum/opposing_force/proc/set_equipment_reason(mob/user, datum/opposing_force_selected_equipment/incoming_equipment, new_reason) + if(!can_edit) + return + if(!incoming_equipment) + CRASH("set_equipment_reason tried to update a non existent opfor equipment datum!") + var/sanitized_reason = STRIP_HTML_SIMPLE(new_reason, OPFOR_TEXT_LIMIT_DESCRIPTION) + add_log(user.ckey, "Updated equipment([incoming_equipment.opposing_force_equipment.name]) REASON from: [incoming_equipment.reason] to: [sanitized_reason]") + incoming_equipment.reason = sanitized_reason + return TRUE + +/datum/opposing_force/proc/remove_equipment(mob/user, datum/opposing_force_selected_equipment/incoming_equipment) + if(!can_edit) + return + add_log(user.ckey, "Removed equipment: [incoming_equipment.opposing_force_equipment.name]") + selected_equipment -= incoming_equipment + qdel(incoming_equipment) + +/datum/opposing_force/proc/select_equipment(mob/user, datum/opposing_force_equipment/incoming_equipment, reason) + if(!can_edit) + return + if(LAZYLEN(selected_equipment) >= OPFOR_EQUIPMENT_LIMIT) + to_chat(user, span_warning("You have too many items, please remove one!")) + return + var/datum/opposing_force_selected_equipment/new_selected = new(incoming_equipment) + selected_equipment += new_selected + add_log(user.ckey, "Selected equipment: [incoming_equipment.name]") + +/datum/opposing_force/proc/issue_gear(mob/user) + if(!selected_equipment.len || !isliving(mind_reference.current) || status != OPFOR_STATUS_APPROVED || equipment_issued) + return + var/mob/living/target = mind_reference.current + var/obj/item/storage/box/spawned_box = new(get_turf(target)) + for(var/datum/opposing_force_selected_equipment/iterating_equipment as anything in selected_equipment) + if(iterating_equipment.status != OPFOR_EQUIPMENT_STATUS_APPROVED) + continue + for(var/i in 1 to iterating_equipment.count) + new iterating_equipment.opposing_force_equipment.item_type(spawned_box) + if(ishuman(target)) + var/mob/living/carbon/human/human = target + human.put_in_hands(spawned_box) + + add_log(user.ckey, "Issued gear") + send_system_message("[user ? get_admin_ckey(user) : "The OPFOR subsystem"] has issued all approved equipment") + equipment_issued = TRUE + +/** + * Control procs + */ + +/datum/opposing_force/proc/request_update(mob/user) + if(request_updates_muted) + to_chat(user, span_warning("You are currently blocked from requesting updates!")) + return + if(status != OPFOR_STATUS_AWAITING_APPROVAL || !COOLDOWN_FINISHED(src, request_update_cooldown)) + return + + send_admins_opfor_message(span_command_headset("UPDATE REQUEST: [ADMIN_LOOKUPFLW(user)] has requested an update on their OPFOR application!")) + add_log(user.ckey, "Requested an update") + + for(var/client/staff as anything in GLOB.admins) + if(staff?.prefs?.toggles & SOUND_ADMINHELP) + SEND_SOUND(staff, sound('sound/effects/adminhelp.ogg')) + window_flash(staff) + + COOLDOWN_START(src, request_update_cooldown, OPFOR_REQUEST_UPDATE_COOLDOWN) + +/datum/opposing_force/proc/submit_to_subsystem(mob/user) + if(blocked) + to_chat(user, span_warning("You are currently blocked from submitting new requests!")) + return + if(status != OPFOR_STATUS_NOT_SUBMITTED && status != OPFOR_STATUS_CHANGES_REQUESTED) + return FALSE + // Subsystem checks, no point in bloating the system if it's not accepting more. + var/availability = SSopposing_force.check_availability() + if(availability != OPFOR_SUBSYSTEM_READY) + to_chat(usr, span_warning("Error, the OPFOR subsystem rejected your request. Reason: [availability]")) + return FALSE + + var/queue_position = SSopposing_force.add_to_queue(src) + + for(var/client/staff as anything in GLOB.admins) + if(staff?.prefs?.toggles & SOUND_ADMINHELP) + SEND_SOUND(staff, sound('sound/effects/adminhelp.ogg')) + window_flash(staff, ignorepref = TRUE) + + status = OPFOR_STATUS_AWAITING_APPROVAL + can_edit = FALSE + add_log(user.ckey, "Submitted to the OPFOR subsystem") + send_system_message("[user ? get_admin_ckey(user) : "The OPFOR subsystem"] has submitted the application for review") + send_admins_opfor_message(span_command_headset("SUBMISSION: [ADMIN_LOOKUPFLW(user)] has submitted their OPFOR application. They are number [queue_position] in the queue.")) + to_chat(usr, examine_block(span_nicegreen(("You have been added to the queue for the OPFOR subsystem. You are number [queue_position] in line.")))) + +/datum/opposing_force/proc/modify_request(mob/user) + if(status == OPFOR_STATUS_CHANGES_REQUESTED) + return + var/choice = tgui_alert(user, "Are you sure you want to request changes? This will unapprove all objectives.", "Confirm", list("Yes", "No")) + if(choice != "Yes") + return + if(status == OPFOR_STATUS_CHANGES_REQUESTED) // The alert is not async, so this could change, thus being spammed. + return + for(var/datum/opposing_force_objective/opfor in objectives) + opfor.status = OPFOR_OBJECTIVE_STATUS_NOT_REVIEWED + status = OPFOR_STATUS_CHANGES_REQUESTED + SSopposing_force.modify_request(src) + can_edit = TRUE + + add_log(user.ckey, "Modify request submitted") + send_system_message("[user ? get_admin_ckey(user) : "The OPFOR subsystem"] has requested modifications to the application") + send_admins_opfor_message("CHANGES REQUESTED: [ADMIN_LOOKUPFLW(user)] has submitted a modify request, their application has been reset.") + +/datum/opposing_force/proc/deny(mob/denier, reason = "") + if(status == OPFOR_STATUS_DENIED) + return + status = OPFOR_STATUS_DENIED + can_edit = FALSE + denied_reason = reason + + for(var/datum/opposing_force_selected_equipment/iterating_equipment as anything in selected_equipment) + iterating_equipment.status = OPFOR_EQUIPMENT_STATUS_DENIED + for(var/datum/opposing_force_objective/opfor in objectives) + opfor.status = OPFOR_OBJECTIVE_STATUS_DENIED + SEND_SOUND(mind_reference.current, sound('modular_skyrat/modules/opposing_force/sound/denied.ogg')) + add_log(denier.ckey, "Denied application") + to_chat(mind_reference.current, examine_block(span_redtext("Your OPFOR application has been denied by [denier ? get_admin_ckey(denier) : "the OPFOR subsystem"]!"))) + send_system_message(get_admin_ckey(denier) + " has denied the application with the following reason: [reason]") + send_admins_opfor_message("[span_red("DENIED")]: [ADMIN_LOOKUPFLW(denier)] has denied [ckey]'s application([reason ? reason : "No reason specified"])") + ticket_counter_add_handled(denier.key, 1) + +/datum/opposing_force/proc/approve(mob/approver) + if(status == OPFOR_STATUS_APPROVED) + return + status = OPFOR_STATUS_APPROVED + can_edit = FALSE + + SEND_SOUND(mind_reference.current, sound('modular_skyrat/modules/opposing_force/sound/approved.ogg')) + add_log(approver.ckey, "Approved application") + to_chat(mind_reference.current, examine_block(span_greentext("Your OPFOR application has been approved by [approver ? get_admin_ckey(approver) : "the OPFOR subsystem"]!"))) + send_system_message("[approver ? get_admin_ckey(approver) : "The OPFOR subsystem"] has approved the application") + send_admins_opfor_message("[span_green("APPROVED")]: [ADMIN_LOOKUPFLW(approver)] has approved [ckey]'s application") + ticket_counter_add_handled(approver.key, 1) + +/datum/opposing_force/proc/close_application(mob/user) + if(status == OPFOR_STATUS_NOT_SUBMITTED) + return + var/choice = tgui_alert(user, "Are you sure you want withdraw your application?", "Confirm", list("Yes", "No")) + if(choice != "Yes") + return + if(status == OPFOR_STATUS_NOT_SUBMITTED) // The alert is not async, so this could change, thus being spammed. + return + SSopposing_force.unsubmit_opfor(src) + status = OPFOR_STATUS_NOT_SUBMITTED + can_edit = TRUE + + for(var/datum/opposing_force_selected_equipment/iterating_equipment as anything in selected_equipment) + iterating_equipment.status = OPFOR_EQUIPMENT_STATUS_NOT_REVIEWED + for(var/datum/opposing_force_objective/opfor as anything in objectives) + opfor.status = OPFOR_OBJECTIVE_STATUS_NOT_REVIEWED + + add_log(user.ckey, "Withdrew application") + send_system_message("[user ? get_admin_ckey(user) : "The OPFOR subsystem"] has closed the application") + +/datum/opposing_force/proc/set_backstory(mob/user, incoming_backstory) + if(!can_edit) + return + var/sanitized_backstory = STRIP_HTML_SIMPLE(incoming_backstory, OPFOR_TEXT_LIMIT_BACKSTORY) + add_log(user.ckey, "Updated BACKSTORY from: [set_backstory] to: [sanitized_backstory]") + set_backstory = sanitized_backstory + return TRUE + +/datum/opposing_force/proc/approve_all(mob/user) + if(SSopposing_force.approve(src, user)) + for(var/datum/opposing_force_selected_equipment/iterating_equipment as anything in selected_equipment) + iterating_equipment.status = OPFOR_EQUIPMENT_STATUS_APPROVED + for(var/datum/opposing_force_objective/opfor as anything in objectives) + opfor.status = OPFOR_OBJECTIVE_STATUS_APPROVED + send_system_message("[user ? get_admin_ckey(user) : "The OPFOR subsystem"] has approved the application and ALL objectives and equipment") + add_log(user.ckey, "Approved application and all objectives and equipment") + + +/** + * Objective procs + */ + +/datum/opposing_force/proc/set_objective_intensity(mob/user, datum/opposing_force_objective/opposing_force_objective, new_intensity) + if(!can_edit) + return + if(!opposing_force_objective) + CRASH("set_objective_intensity tried to update a non existent opfor objective!") + var/sanitized_intensity = sanitize_integer(new_intensity, 1, 500) + switch(sanitized_intensity) + if(0 to 100) + opposing_force_objective.text_intensity = OPFOR_OBJECTIVE_INTENSITY_1 + if(101 to 200) + opposing_force_objective.text_intensity = OPFOR_OBJECTIVE_INTENSITY_2 + if(201 to 300) + opposing_force_objective.text_intensity = OPFOR_OBJECTIVE_INTENSITY_3 + if(301 to 400) + opposing_force_objective.text_intensity = OPFOR_OBJECTIVE_INTENSITY_4 + if(401 to 501) + opposing_force_objective.text_intensity = OPFOR_OBJECTIVE_INTENSITY_5 + add_log(user.ckey, "Set updated an objective intensity from [opposing_force_objective.intensity] to [sanitized_intensity].") + opposing_force_objective.intensity = sanitized_intensity + return TRUE + +/datum/opposing_force/proc/set_objective_description(mob/user, datum/opposing_force_objective/opposing_force_objective, new_description) + if(!can_edit) + return + if(!opposing_force_objective) + CRASH("set_objective_description tried to update a non existent opfor objective!") + var/sanitized_description = STRIP_HTML_SIMPLE(new_description, OPFOR_TEXT_LIMIT_DESCRIPTION) + opposing_force_objective.description = sanitized_description + add_log(user.ckey, "Updated objective([opposing_force_objective.title]) DESCRIPTION from: [opposing_force_objective.description] to: [sanitized_description]") + return TRUE + +/datum/opposing_force/proc/set_objective_justification(mob/user, datum/opposing_force_objective/opposing_force_objective, new_justification) + if(!can_edit) + return + if(!opposing_force_objective) + CRASH("set_objective_description tried to update a non existent opfor objective!") + var/sanitize_justification = STRIP_HTML_SIMPLE(new_justification, OPFOR_TEXT_LIMIT_JUSTIFICATION) + opposing_force_objective.justification = sanitize_justification + add_log(user.ckey, "Updated objective([opposing_force_objective.title]) JUSTIFICATION from: [opposing_force_objective.justification] to: [sanitize_justification]") + return TRUE + +/datum/opposing_force/proc/remove_objective(mob/user, datum/opposing_force_objective/opposing_force_objective) + if(!can_edit) + return + if(!opposing_force_objective) + CRASH("set_objective_description tried to remove a non existent opfor objective!") + objectives -= opposing_force_objective + add_log(user.ckey, "Removed the following objective from their OPFOR application: [opposing_force_objective.title]") + qdel(opposing_force_objective) + return TRUE + +/datum/opposing_force/proc/add_objective(mob/user) + if(!can_edit) + return + if(LAZYLEN(objectives) >= OPFOR_MAX_OBJECTIVES) + to_chat(user, span_warning("You have too many objectives, please remove one!")) + return + objectives += new /datum/opposing_force_objective + add_log(user.ckey, "Added a new blank objective") + return TRUE + +/datum/opposing_force/proc/set_objective_title(mob/user, datum/opposing_force_objective/opposing_force_objective, new_title) + if(!can_edit) + return + var/sanitized_title = STRIP_HTML_SIMPLE(new_title, OPFOR_TEXT_LIMIT_TITLE) + if(!opposing_force_objective) + CRASH("set_objective_description tried to update a non existent opfor objective!") + add_log(user.ckey, "Updated objective([opposing_force_objective.title]) TITLE from: [opposing_force_objective.title] to: [sanitized_title]") + opposing_force_objective.title = sanitized_title + return TRUE + +/datum/opposing_force/proc/deny_objective(mob/user, datum/opposing_force_objective/opposing_force_objective, deny_reason) + opposing_force_objective.status = OPFOR_OBJECTIVE_STATUS_DENIED + opposing_force_objective.denied_reason = deny_reason + add_log(user.ckey, "Denied objective([opposing_force_objective.title]) WITH REASON: [deny_reason]") + send_system_message("[user ? get_admin_ckey(user) : "The OPFOR subsystem"] has denied objective '[opposing_force_objective.title]' with the reason '[deny_reason]'") + +/datum/opposing_force/proc/approve_objective(mob/user, datum/opposing_force_objective/opposing_force_objective) + opposing_force_objective.status = OPFOR_OBJECTIVE_STATUS_APPROVED + add_log(user.ckey, "Approved objective([opposing_force_objective.title])") + send_system_message("[user ? get_admin_ckey(user) : "The OPFOR subsystem"] has approved objective '[opposing_force_objective.title]'") + +/** + * System procs + */ + +/datum/opposing_force/proc/add_log(logger_ckey, new_log) + var/msg = "OPFOR([ckey]): [logger_ckey ? logger_ckey : "SYSTEM"] - [new_log]" + modification_log += msg + log_admin(msg) + +/datum/opposing_force/proc/send_admins_opfor_message(message) + message = "[span_pink("OPFOR:")] [span_admin("[message] (Show Panel)")]" + to_chat(GLOB.admins, + type = MESSAGE_TYPE_ADMINLOG, + html = message, + confidential = TRUE) + +/datum/opposing_force/proc/get_status_string() + var/subsystem_status = SSopposing_force.check_availability() + if(subsystem_status != OPFOR_SUBSYSTEM_READY) + return subsystem_status + switch(status) + if(OPFOR_STATUS_AWAITING_APPROVAL) + return "Awaiting approval, you are number [SSopposing_force.get_queue_position(src)] in the queue" + if(OPFOR_STATUS_APPROVED) + return "Approved, please check your objectives for specific approval" + if(OPFOR_STATUS_DENIED) + return "Denied, do not attempt any of your objectives" + if(OPFOR_STATUS_CHANGES_REQUESTED) + return "Changes requested, please review your application" + if(OPFOR_STATUS_NOT_SUBMITTED) + return OPFOR_STATUS_NOT_SUBMITTED + else + return "ERROR" + +/datum/opposing_force/proc/get_admin_ckey(mob/user) + if(user.client?.holder?.fakekey) + return user.client.holder.fakekey + return user.ckey + +/datum/opposing_force/proc/broadcast_queue_change() + var/queue_number = SSopposing_force.get_queue_position(src) + to_chat(mind_reference.current, examine_block(span_nicegreen("Your OPFOR application is now number [queue_number] in the queue."))) + send_system_message("Application is now number [queue_number] in the queue") + +/datum/opposing_force/proc/send_message(mob/user, message) + if(!message) + return + message = STRIP_HTML_SIMPLE(message, OPFOR_TEXT_LIMIT_MESSAGE) + var/message_string + var/real_round_time = world.timeofday - SSticker.real_round_start_time + if(check_rights_for(user.client, R_ADMIN) && user != mind_reference) + message_string = "[time2text(real_round_time, "hh:mm:ss", 0)] (ADMIN) [get_admin_ckey(user)]: " + message + else + message_string = "[time2text(real_round_time, "hh:mm:ss", 0)] (USER) [user.ckey]: " + message + admin_chat += message_string + + // We support basic commands, see run_command for compatible commands, the operator is / + if(findtext(message, "/", 1, 2)) + // We remove the command indentifier before we try running the command. + var/command = replacetext(message, "/", "", 1, 2) + run_command(user, command) + + add_log(user.ckey, "Sent message: [message]") + + +/datum/opposing_force/proc/send_system_message(message) + var/real_round_time = world.timeofday - SSticker.real_round_start_time + var/message_string = "[time2text(real_round_time, "hh:mm:ss", 0)] SYSTEM: " + message + admin_chat += message_string + +/datum/opposing_force/proc/run_command(mob/user, message) + var/list/params = splittext(message, " ") + + var/command = params[1] + + switch(command) + if("item") + check_item(params[2]) + if("help") + print_help(user) + if("ping_admin") + ping_admin(user) + if("ping_user") + ping_user(user) + if("unlock_equipment") + unlock_equipment(user) // Admin only proc + else + send_system_message("Unknown command: [command]") + +/datum/opposing_force/proc/print_help(mob/user) + send_system_message("Available commands:") + send_system_message("/item 'item_name' - Check an items quick stats") + send_system_message("/ping_admin - Ping the handling admin, if there is one.") + send_system_message("/help - Print this help") + // Admin commands. + if(check_rights_for(user.client, R_ADMIN)) + send_system_message("Admin commands:") + send_system_message("/unlock_equipment - Unlock all equipment, useful if you need to give the user more stuff.") + send_system_message("/ping_user - Pings the user.") + +/** + * System commands + */ +/datum/opposing_force/proc/check_item(type) + var/obj/item/processed_item = text2path(type) + if(!processed_item) + send_system_message("Unknown type: [type]") + return + if(!ispath(processed_item, /obj/item)) + send_system_message("Error: [processed_item] is not an item") + return + + send_system_message("Here are the item specifications for [type]:") + send_system_message("Name: [initial(processed_item.name)]") + send_system_message("Description: [initial(processed_item.desc)]") + send_system_message("Weight class: [initial(processed_item.w_class)]") + send_system_message("Tool behaviour: [initial(processed_item.tool_behaviour)]") + send_system_message("Weak against armor: [initial(processed_item.weak_against_armour) ? "Yes" : "No"]") + send_system_message("Damage type: [initial(processed_item.damtype)]") + send_system_message("Wound bonus: [initial(processed_item.wound_bonus)]") + send_system_message("Bare wound bonus: [initial(processed_item.bare_wound_bonus)]") + send_system_message("Force: [initial(processed_item.force)]") + +/datum/opposing_force/proc/unlock_equipment(mob/user) + if(!check_rights_for(user.client, R_ADMIN)) + send_system_message("ERROR: You do not have permission to do that.") + return + if(!equipment_issued) + send_system_message("ERROR: Equipment not yet issued.") + return + equipment_issued = TRUE + send_system_message("Equipment unlocked.") + +/datum/opposing_force/proc/ping_admin(mob/user) + if(!handling_admin) + send_system_message("ERROR: No admin is handling the application.") + return + if(!COOLDOWN_FINISHED(src, ping_cooldown)) + send_system_message("ERROR: Ping is on cooldown.") + return + if(request_updates_muted) + send_system_message("ERROR: You are muted.") + return + if(user.ckey != handling_admin && GLOB.directory[handling_admin]) + to_chat(GLOB.directory[handling_admin], span_pink("OPFOR: [user] has pinged their OPFOR admin chat! (Show Panel)")) + SEND_SOUND(GLOB.directory[handling_admin], sound('sound/misc/bloop.ogg')) + send_system_message("Handling admin pinged.") + COOLDOWN_START(src, ping_cooldown, OPFOR_PING_COOLDOWN) + else + send_system_message("ERROR: Ping failed.") + +/datum/opposing_force/proc/ping_user(mob/user) + if(!check_rights_for(user.client, R_ADMIN)) + send_system_message("ERROR: You do not have permission to do that.") + return + send_system_message("User pinged.") + to_chat(mind_reference.current, span_pink("OPFOR: [get_admin_ckey(user)] has pinged your OPFOR chat, check it!")) + SEND_SOUND(mind_reference.current, sound('sound/misc/bloop.ogg')) + +/datum/opposing_force/proc/roundend_report() + var/list/report = list("
") + report += span_greentext(mind_reference.current.real_name) + if(objectives.len) + report += "Had an approved OPFOR appliation with the following objectives:
" + for(var/datum/opposing_force_objective/opfor_objective in objectives) + if(opfor_objective.status != OPFOR_OBJECTIVE_STATUS_APPROVED) + continue + report += "Title: [opfor_objective.title]
" + report += "
Description: [opfor_objective.description]
" + report += "
" + + if(selected_equipment.len) + report += "And had the following approved equipment:
" + for(var/datum/opposing_force_selected_equipment/opfor_equipment in selected_equipment) + if(opfor_equipment.status != OPFOR_EQUIPMENT_STATUS_APPROVED) + continue + report += "
[opfor_equipment.opposing_force_equipment.name]
" + report += "
" + + return report.Join("\n") diff --git a/modular_skyrat/modules/opposing_force/code/opposing_force_equipment.dm b/modular_skyrat/modules/opposing_force/code/opposing_force_equipment.dm new file mode 100644 index 00000000000..0b1814e1a83 --- /dev/null +++ b/modular_skyrat/modules/opposing_force/code/opposing_force_equipment.dm @@ -0,0 +1,560 @@ +/** + * OPFOR EQUIPMENT DATUM + * + * The OPFOR subsystem will gather all of these on initialisation and populate a list, which is then passed + * into the OPFOR UI, which can be selected by the user. + * + * The User will be equipped with whatever they have selected if the approving admin authorises it. + */ + + +/datum/opposing_force_equipment + /// The name of the equipment used in the listing, if not set, it will use the items name. + var/name + /// The description of the equipment used in the listing, if not set, it will use the items description. + var/description + /// The item path that we refer to when equipping. + var/obj/item_type + /// Category of the item. See opposing_force_defines.dm for a list of categories. + var/category = "" + +/** + * GUNS + */ + +/datum/opposing_force_equipment/gun + category = OPFOR_EQUIPMENT_CATEGORY_RANGED_WEAPONS +/datum/opposing_force_equipment/gun/m1911 + item_type = /obj/item/gun/ballistic/automatic/pistol/m1911 + description = "A semi-automatic .45 caliber pistol. Gold standard for sidearms." + +/datum/opposing_force_equipment/gun/m16 + item_type = /obj/item/gun/ballistic/automatic/assault_rifle/m16 + +/datum/opposing_force_equipment/gun/m16m + item_type = /obj/item/gun/ballistic/automatic/assault_rifle/m16/modern + +/datum/opposing_force_equipment/gun/m16patriot + item_type = /obj/item/gun/ballistic/automatic/assault_rifle/m16/modern/v2 + +/datum/opposing_force_equipment/gun/akm + item_type = /obj/item/gun/ballistic/automatic/assault_rifle/akm + +/datum/opposing_force_equipment/gun/akmm + item_type = /obj/item/gun/ballistic/automatic/assault_rifle/akm/modern + +/datum/opposing_force_equipment/gun/mp40 + item_type = /obj/item/gun/ballistic/automatic/submachine_gun/mp40 + +/datum/opposing_force_equipment/gun/mp40m/modern + item_type = /obj/item/gun/ballistic/automatic/submachine_gun/mp40 + +/datum/opposing_force_equipment/gun/pps + item_type = /obj/item/gun/ballistic/automatic/submachine_gun/pps + description = "A very cheap, barely reliable reproduction of a personal defense weapon based on the original Soviet model. Not nearly as infamous as the Mosin. \ + Compact enough to fit in your backpack!" + +/datum/opposing_force_equipment/gun/ppsh + item_type = /obj/item/gun/ballistic/automatic/submachine_gun/ppsh + +/datum/opposing_force_equipment/gun/ppshm + item_type = /obj/item/gun/ballistic/automatic/submachine_gun/ppsh/modern + +/datum/opposing_force_equipment/gun/stg + item_type = /obj/item/gun/ballistic/automatic/assault_rifle/stg + +/datum/opposing_force_equipment/gun/stgm + item_type = /obj/item/gun/ballistic/automatic/assault_rifle/stg/modern + +/datum/opposing_force_equipment/gun/fg42 + item_type = /obj/item/gun/ballistic/automatic/battle_rifle/fg42 + +/datum/opposing_force_equipment/gun/fg42m + item_type = /obj/item/gun/ballistic/automatic/battle_rifle/fg42/modern + +/datum/opposing_force_equipment/gun/uzi + item_type = /obj/item/gun/ballistic/automatic/mini_uzi + description = "The uzi nine millimeter, a timeless submachinegun for a warrior out of time." + +/datum/opposing_force_equipment/gun/mg34 + item_type = /obj/item/gun/ballistic/automatic/mg34 + +/datum/opposing_force_equipment/gun/cfa + item_type = /obj/item/gun/ballistic/automatic/cfa_rifle + +/datum/opposing_force_equipment/gun/m23 + item_type = /obj/item/gun/ballistic/shotgun/m23 + description = "An eight-round pump-action shotgun found in an old station. Comes loaded with beanbag shells but can take any 12 gauge load." + +/datum/opposing_force_equipment/gun/as2 + item_type = /obj/item/gun/ballistic/shotgun/automatic/as2 + description = "A compact version of the combat shotgun. Comes with a four-round tube and can be silenced as well as holstered to your belt or vest. \ + Comes loaded with slugs but can take any 12 gauge load." + +/datum/opposing_force_equipment/gun/sas14 + item_type = /obj/item/gun/ballistic/shotgun/sas14 + description = "A semi-automatic, magazine-fed shotgun chambered in 14 gauge. Standard mags can take five rounds. \ + Despite the lower damage of 14 gauge, it can load the highly praised taser shots." + +/datum/opposing_force_equipment/gun/g357 + item_type = /obj/item/gun/ballistic/revolver + description = "A .357 magnum revolver. Seven shots, more than enough to kill anything that moves." + +/datum/opposing_force_equipment/gun/mateba + item_type = /obj/item/gun/ballistic/revolver/mateba + +/datum/opposing_force_equipment/gun/nagant + item_type = /obj/item/gun/ballistic/revolver/nagant + +/datum/opposing_force_equipment/gun/snub + item_type = /obj/item/gun/ballistic/automatic/pistol/cfa_snub + +/datum/opposing_force_equipment/gun/ruby + item_type = /obj/item/gun/ballistic/automatic/pistol/cfa_ruby + +/datum/opposing_force_equipment/gun/wildcat + item_type = /obj/item/gun/ballistic/automatic/cfa_wildcat + +//oddities +/datum/opposing_force_equipment/gun/ninjastar + item_type = /obj/item/throwing_star + description = "Be the maintenance ninja you always wanted to be. Does not come with multi-throwing cybernetics" + +/datum/opposing_force_equipment/gun/throwing_weapons + item_type = /obj/item/storage/box/syndie_kit/throwing_weapons + description = "A box of shurikens and reinforced bolas from ancient Earth martial arts. They are highly effective \ + throwing weapons. The bolas can knock a target down and the shurikens will embed into limbs." + name = "Box of Throwing Weapons" + +/datum/opposing_force_equipment/gun/origami + item_type = /obj/item/storage/box/syndie_kit/origami_bundle + description = "A box containing a guide on how to craft masterful works of origami, allowing you to transform normal pieces of paper into \ + perfectly aerodynamic (and potentially lethal) paper airplanes." + + + +/** + * AMMO + */ +/datum/opposing_force_equipment/ammo + category = OPFOR_EQUIPMENT_CATEGORY_AMMUNITION + +/datum/opposing_force_equipment/ammo/m45 + item_type = /obj/item/ammo_box/magazine/m45 + description = "An eight-round magazine for the M1911 pistol. Uses .45 caliber ammunition." + +/datum/opposing_force_equipment/ammo/m16 + item_type = /obj/item/ammo_box/magazine/m16 + description = "A twenty-round magazine for the M16 assault rifle. Uses 5.56x45mm ammunition." + +/datum/opposing_force_equipment/ammo/akm + item_type = /obj/item/ammo_box/magazine/akm + +/datum/opposing_force_equipment/ammo/akmbanan + item_type = /obj/item/ammo_box/magazine/akm/banana + +/datum/opposing_force_equipment/ammo/mp40 + item_type = /obj/item/ammo_box/magazine/mp40 + description = "A thirty-two round magazine for the MP-40. Uses 9x19mm ammunition." + +/datum/opposing_force_equipment/ammo/pps + item_type = /obj/item/ammo_box/magazine/pps + +/datum/opposing_force_equipment/ammo/ppsh + item_type = /obj/item/ammo_box/magazine/ppsh + +/datum/opposing_force_equipment/ammo/stg + item_type = /obj/item/ammo_box/magazine/stg + +/datum/opposing_force_equipment/ammo/fg42 + item_type = /obj/item/ammo_box/magazine/fg42 + description = "A twenty round magazine for the FG-42. Uses 7.92×57mm ammunition." + +/datum/opposing_force_equipment/ammo/m9mm + item_type = /obj/item/ammo_box/magazine/uzim9mm + description = "A thirty-two round magazine for the mini uzi. Uses 9x19mm ammunition." + +/datum/opposing_force_equipment/ammo/mg34 + item_type = /obj/item/ammo_box/magazine/mg34 + +/datum/opposing_force_equipment/ammo/cm762 + item_type = /obj/item/ammo_box/magazine/cm762 + description = "7.62 bullets in a ten round magazine for Cantanheim 7.62 rifle." + +/datum/opposing_force_equipment/ammo/a357 + item_type = /obj/item/ammo_box/a357 + description = "A seven-round .357 magnum speedloader for a revolver." + +/datum/opposing_force_equipment/ammo/a357match + item_type = /obj/item/ammo_box/a357/match + description = "A seven-round .357 magnum speedloader for a revolver, loaded with match-grade ammunition that bounces off walls several times." + +/datum/opposing_force_equipment/ammo/cfa_snub + item_type = /obj/item/ammo_box/magazine/multi_sprite/cfa_snub + +/datum/opposing_force_equipment/ammo/cfa_snubap + item_type = /obj/item/ammo_box/magazine/multi_sprite/cfa_snub/ap + +/datum/opposing_force_equipment/ammo/cfa_snubrubber + item_type = /obj/item/ammo_box/magazine/multi_sprite/cfa_snub/rubber + +/datum/opposing_force_equipment/ammo/cfa_snubincendiary + item_type = /obj/item/ammo_box/magazine/multi_sprite/cfa_snub/incendiary + +/datum/opposing_force_equipment/ammo/cfa_ruby + item_type = /obj/item/ammo_box/magazine/multi_sprite/cfa_ruby + +/datum/opposing_force_equipment/ammo/cfa_rubyap + item_type = /obj/item/ammo_box/magazine/multi_sprite/cfa_ruby/ap + +/datum/opposing_force_equipment/ammo/cfa_rubyrubber + item_type = /obj/item/ammo_box/magazine/multi_sprite/cfa_ruby/rubber + +/datum/opposing_force_equipment/ammo/cfa_rubyhp + item_type = /obj/item/ammo_box/magazine/multi_sprite/cfa_ruby/hp + +/datum/opposing_force_equipment/ammo/cfa_rubyincendiary + item_type = /obj/item/ammo_box/magazine/multi_sprite/cfa_ruby/incendiary + +/datum/opposing_force_equipment/ammo/wildcat + item_type = /obj/item/ammo_box/magazine/multi_sprite/cfa_wildcat + +/datum/opposing_force_equipment/ammo/wildcatap + item_type = /obj/item/ammo_box/magazine/multi_sprite/cfa_wildcat/ap + +/datum/opposing_force_equipment/ammo/wildcatrubber + item_type = /obj/item/ammo_box/magazine/multi_sprite/cfa_wildcat/rubber + +/datum/opposing_force_equipment/ammo/wildcatincendiary + item_type = /obj/item/ammo_box/magazine/multi_sprite/cfa_wildcat/incendiary +/** + * MELEE WEAPONS + */ +/datum/opposing_force_equipment/melee + category = OPFOR_EQUIPMENT_CATEGORY_MELEE_WEAPONS + +/datum/opposing_force_equipment/melee/switchblade + item_type = /obj/item/switchblade + +/datum/opposing_force_equipment/melee/metalbat + item_type = /obj/item/melee/baseball_bat/ablative + description = "A highly reflective baseball bat for when you need to crack skulls and run away from security in the same night." + +/datum/opposing_force_equipment/melee/esword + item_type = /obj/item/melee/energy/sword + description = "The energy sword is an edged weapon with a blade of pure energy. The sword is small enough to be \ + pocketed when inactive. Activating it produces a loud, distinctive noise." + +/datum/opposing_force_equipment/melee/epirate + item_type = /obj/item/melee/energy/sword/pirate + description = "A variant of the energy sword styled as a cutlass. Pirate costume sold separately. Warranty void if bought." + +/datum/opposing_force_equipment/melee/edagger + item_type = /obj/item/pen/edagger + name = "Energy Dagger" + description = "A dagger made of energy that looks and functions as a pen when off." + +/datum/opposing_force_equipment/melee/cutlass + item_type = /obj/item/claymore/cutlass + +/datum/opposing_force_equipment/melee/claymore + item_type = /obj/item/claymore + description = "An extremely sharp and robust sword perfect to cleave through any opposition. Also highly illegal." + +/datum/opposing_force_equipment/melee/katana + item_type = /obj/item/katana + description = "An extremely sharp and robust sword folded over nine thousand times until perfection. Highly lethal and illegal." + +/datum/opposing_force_equipment/melee/ekatana + item_type = /obj/item/energy_katana + description = "An energy katana seized from a dead Spider Clan ninja. As well as being highly robust, it allows the \ + user to teleport short distances using right-click." + +/datum/opposing_force_equipment/melee/eswordarm + item_type = /obj/item/autosurgeon/organ/syndicate/esword_arm + name = "Energy Sword Arm Implant" + description = "It's an energy sword, in your arm. Pretty decent for getting past stop-searches and assassinating people. Comes loaded in a Syndicate brand autosurgeon to boot!" + +/datum/opposing_force_equipment/melee/powerfist + item_type = /obj/item/melee/powerfist + name = "Power Fist" + description = "The power-fist is a metal gauntlet with a built-in piston-ram powered by an external gas supply.\ + Upon hitting a target, the piston-ram will extend forward to make contact for some serious damage. \ + Using a wrench on the piston valve will allow you to tweak the amount of gas used per punch to \ + deal extra damage and hit targets further. Use a screwdriver to take out any attached tanks." + +//martialarts + +/datum/opposing_force_equipment/melee/cqc + item_type = /obj/item/book/granter/martial/cqc + description = "A manual that teaches a single user tactical Close-Quarters Combat before self-destructing." + +/datum/opposing_force_equipment/melee/carp + item_type = /obj/item/book/granter/martial/carp + description = "This scroll contains the secrets of an ancient martial arts technique. You will master unarmed combat \ + and gain the ability to swat bullets from the air, but you will also refuse to use dishonorable ranged weaponry." + +/datum/opposing_force_equipment/melee/kravmaga + item_type = /obj/item/clothing/gloves/krav_maga/combatglovesplus //yes its a glove but it exists to give krav maga martial arts so its here + +/** + * ARMOR AND CLOTHES + */ +/datum/opposing_force_equipment/clothing + category = OPFOR_EQUIPMENT_CATEGORY_CLOTHING + +/datum/opposing_force_equipment/clothing/syndiebag + item_type = /obj/item/storage/backpack/duffelbag/syndie + name = "Syndicate Brand Duffelbag" + description = "Thanks to being made from a lighter yet sturdier material, this duffelbag holds just the same as any other duffelbag without the speed penalty of its counterparts." + +/datum/opposing_force_equipment/clothing/vest + item_type = /obj/item/clothing/suit/armor/vest + description = "A basic armored vest, rated for all manner of protections." + +/datum/opposing_force_equipment/clothing/ballistic + item_type = /obj/item/clothing/suit/armor/bulletproof + description = "A bulletproof vest, for the aspiring warfighter." + +/datum/opposing_force_equipment/clothing/laser + item_type = /obj/item/clothing/suit/armor/laserproof + description = "A laserproof vest, for the aspiring bane of security." + +/datum/opposing_force_equipment/clothing/heavy + item_type = /obj/item/clothing/suit/armor/heavy + description = "A superheavy armor suit purpose-built to ensure all injuries are pushovers. WARNING: Not spaceproof." + +/datum/opposing_force_equipment/clothing/infiltrator + name = "Infiltrator Gear" + item_type = /obj/item/storage/toolbox/infiltrator + description = "A box of equipment specially made for an infiltration expert, including sound-insulated boots, nanochip apprehension gloves, \ + and a voice-masking balaclava. Too bad it's made in such a red color..." + +/datum/opposing_force_equipment/clothing/helmet + item_type = /obj/item/clothing/head/helmet/swat + description = "A red-striped SWAT helmet. More robust than the standard-issue Nanotrasen security issue helmet, and spaceproof to boot." + +/datum/opposing_force_equipment/clothing/syndierig + item_type = /obj/item/storage/belt/military + +/datum/opposing_force_equipment/clothing/assaultbelt + item_type = /obj/item/storage/belt/military/assault + +/datum/opposing_force_equipment/clothing/bandolier + item_type = /obj/item/storage/belt/bandolier + +/datum/opposing_force_equipment/clothing/grenades + item_type = /obj/item/storage/belt/grenade + description = "A belt for holding grenades. Does not come with grenades unfortunately." + +//NRI larping equipment here + +/datum/opposing_force_equipment/clothing/nrihelm + item_type = /obj/item/clothing/head/helmet/rus_helmet/nri + +/datum/opposing_force_equipment/clothing/nriberet + item_type = /obj/item/clothing/head/beret/sec/nri + name = "NRI Commander Beret" + description = "An armored beret worn by high-ranking NRI officers" + +/datum/opposing_force_equipment/clothing/reduthelm + item_type = /obj/item/clothing/head/helmet/nri_heavy + description = "A specialized ultra-heavy composite ballistic helmet stolen from space russians. Purpose-built for heavy duty combat, \ + or murder with a frying pan." + +/datum/opposing_force_equipment/clothing/nrivest + item_type = /obj/item/clothing/suit/armor/vest/russian/nri + +/datum/opposing_force_equipment/clothing/redut + item_type = /obj/item/clothing/suit/armor/heavy/nri + +/datum/opposing_force_equipment/clothing/nrijumpsuit + item_type = /obj/item/clothing/under/costume/nri + +/datum/opposing_force_equipment/clothing/nribelt + item_type = /obj/item/storage/belt/military/nri + +//end of NRI larp equipment + +/datum/opposing_force_equipment/clothing/holster + item_type = /obj/item/storage/belt/holster/chameleon + description = "A chameleon holster that fits into your belt. Designed to hold one sidearm and a spare load of ammunition, it also allows you to spin \ + your revolver, if you have one." + +/datum/opposing_force_equipment/clothing/holsternk + item_type = /obj/item/storage/belt/holster/nukie + description = "A holster retrieved from a nuclear operative. Able to hold any two types of weaponry or ammo as long as it is not extremely large. \ + Expect security to be not so friendly if they see you wearing one of these..." + +//modsuits in 2022 + +/datum/opposing_force_equipment/clothing/basicmod + item_type = /obj/item/mod/control/pre_equipped/advanced + +/datum/opposing_force_equipment/clothing/syndiemod + item_type = /obj/item/mod/control/pre_equipped/traitor + +/datum/opposing_force_equipment/clothing/nukiemod + item_type = /obj/item/mod/control/pre_equipped/nuclear + +/datum/opposing_force_equipment/clothing/elitemod + item_type = /obj/item/mod/control/pre_equipped/elite + +/** + * UTILITY ITEMS + */ +/datum/opposing_force_equipment/gear/ + category = OPFOR_EQUIPMENT_CATEGORY_UTILITY + +/datum/opposing_force_equipment/gear/stoolbox + item_type = /obj/item/storage/toolbox/syndicate + description = "A fully-kitted toolbox scavenged from maintenance by our highly-paid monkeys. The toolbox \ + itself is weighted especially to bash any head in and comes with a free pair of insulated combat gloves." + +/datum/opposing_force_equipment/gear/engichip + item_type = /obj/item/skillchip/job/engineer + description = "A skillchip that, when installed, allows the user to recognise airlock and APC wire layouts and understand their functionality at a glance. Highly valuable and sought after." + +/datum/opposing_force_equipment/gear/roboticist + item_type = /obj/item/skillchip/job/roboticist + description = "A skillchip that, when installed, allows the user to recognise cyborg wire layouts and understand their functionality at a glance." + +/datum/opposing_force_equipment/gear/tacticool + item_type = /obj/item/skillchip/chameleon/reload + +/datum/opposing_force_equipment/gear/thermalgoggles + item_type = /obj/item/clothing/glasses/thermal + description = "A pair of thermal goggles. Cannot be chameleon disguised." + +/datum/opposing_force_equipment/gear/xraygoggles + item_type = /obj/item/clothing/glasses/thermal/xray + description = "A pair of low-light x-ray goggles manufactured by the Syndicate. Cannot be chameleon disguised. Makes wearer more vulnerable to bright lights." + +/datum/opposing_force_equipment/gear/thermalgogglessyndi + item_type = /obj/item/clothing/glasses/thermal/syndi + description = "A Syndicate take on the classic thermal goggles, complete with chameleon disguise functionality." + +/datum/opposing_force_equipment/gear/cloakerbelt + item_type = /obj/item/shadowcloak + description = "A belt that allows its wearer to temporarily turn invisible. Only recharges in dark areas. Use wisely." + +/datum/opposing_force_equipment/gear/projector + item_type = /obj/item/chameleon + description = "A projector that allows its user to turn into any scanned object. Pairs well with a cluttered room and ambush weapon." + +/datum/opposing_force_equipment/gear/box + item_type = /obj/item/implanter/stealth + description = "An implanter that grants you the ability to wield the ultimate in invisible box technology. Best used in conjunction with \ + a tape recorder playing Snake Eater." + +/datum/opposing_force_equipment/gear/sechud + item_type = /obj/item/clothing/glasses/hud/security/chameleon + description = "A stolen Security HUD refitted with chameleon technology. Provides flash protection." + +/datum/opposing_force_equipment/gear/aidetector + item_type = /obj/item/multitool/ai_detect + description = "A multitool that lets you see the AI's vision cone with an overlaid HUD and know if you're being watched." + +/datum/opposing_force_equipment/gear/noslip + item_type = /obj/item/clothing/shoes/chameleon/noslip + description = "No-slip chameleon shoes, for when you plan on running through hell and back." + +/datum/opposing_force_equipment/gear/cloakmod + item_type = /obj/item/mod/module/stealth/ninja + description = "An upgraded MODsuit cloaking module stolen from the Spider Clan's finest. Consumes less power than the standard, but is obviously illegal." + +/datum/opposing_force_equipment/gear/suppressor + item_type = /obj/item/suppressor + +/datum/opposing_force_equipment/gear/extendedrag + item_type = /obj/item/reagent_containers/glass/rag/large + description = "A damp rag made with extra absorbant materials. The perfectly innocent tool to kidnap your local assistant. \ + Apply up to 30u liquids and use combat mode to smother anyone not covering their mouth." + +/datum/opposing_force_equipment/gear/nodrop + item_type = /obj/item/autosurgeon/organ/syndicate/nodrop + name = "Anti Drop Implant" + description = "An implant that prevents you from dropping items in your hand involuntarily. Comes loaded in a syndicate autosurgeon" + +/datum/opposing_force_equipment/gear/hackerman + item_type = /obj/item/autosurgeon/organ/syndicate/hackerman + name = "Hacking Arm Implant" + description = "An advanced arm implant that comes with cutting edge hacking tools. Perfect for the cybernetically enhanced wirerunners." + +/** + * EXPLOSIVES + */ +/datum/opposing_force_equipment/bomb + category = OPFOR_EQUIPMENT_CATEGORY_EXPLOSIVES + +/datum/opposing_force_equipment/bomb/henade + item_type = /obj/item/grenade/syndieminibomb/concussion + description = "A grenade intended to concuss and incapacitate enemies. Still rather explosive." + +/datum/opposing_force_equipment/bomb/fragnade + item_type = /obj/item/grenade/frag + description = "A fragmentation grenade that looses pieces of shrapnel after detonating for maximum injury." + +/datum/opposing_force_equipment/bomb/radnade + item_type = /obj/item/grenade/gluon + description = "A prototype grenade that freezes the target area and unleashes a wave of deadly radiation." + +/datum/opposing_force_equipment/bomb/c4 + item_type = /obj/item/grenade/c4 + description = "A brick of plastic explosives, for breaking open walls, doors, and optionally people." + +/datum/opposing_force_equipment/bomb/x4 + item_type = /obj/item/grenade/c4/x4 + description = "Similar to C4, but with a stronger blast that is directional instead of circular." + +/** + * LOADOUTS + */ +/datum/opposing_force_equipment/loadout + category = OPFOR_EQUIPMENT_CATEGORY_LOADOUT + +/datum/opposing_force_equipment/loadout/gunman + item_type = /obj/item/storage/box/syndie_kit/gunman_outfit + +/datum/opposing_force_equipment/loadout/grenadier + item_type = /obj/item/storage/belt/grenade/full + name = "Grenadier Kit" + description = "A belt full of grenades and bombs. May gods have mercy upon us if they approve this." + +/** + * OTHER + */ +/datum/opposing_force_equipment/other + category = OPFOR_EQUIPMENT_CATEGORY_OTHER + +/datum/opposing_force_equipment/other/uplink + item_type = /obj/item/uplink/opfor + name = "Syndicate Uplink" + description = "An old-school syndicate uplink without a password and an empty TC account. Perfect for the aspiring operatives." + +/datum/opposing_force_equipment/other/tc1 + item_type = /obj/item/stack/telecrystal + name = "1 Raw Telecrystal" + description = "A telecrystal in its rawest and purest form; can be utilized on active uplinks to increase their telecrystal count." + +/datum/opposing_force_equipment/other/tc5 + item_type = /obj/item/stack/telecrystal/five + name = "5 Raw Telecrystals" + description = "A bunch of telecrystals in their rawest and purest form; can be utilized on active uplinks to increase their telecrystal count." + +/datum/opposing_force_equipment/other/tc20 + item_type = /obj/item/stack/telecrystal/twenty + name = "20 Raw Telecrystals" + description = "A bundle of telecrystals in their rawest and purest form; can be utilized on active uplinks to increase their telecrystal count." + +/datum/opposing_force_equipment/other/cashcase + item_type = /obj/item/storage/secure/briefcase/syndie + name = "Syndicate Briefcase Full of Cash" + description = "A secure briefcase containing 5000 space credits. Useful for bribing personnel, or purchasing goods \ + and services at lucrative prices. The briefcase also feels a little heavier to hold; it has been \ + manufactured to pack a little bit more of a punch if your client needs some convincing." + +/datum/opposing_force_equipment/other/c10k + name = "10000 Space Cash Bill" + item_type = /obj/item/stack/spacecash/c10000 + description = "Cold hard cash. When you REALLY need to bribe or buy your way in. Or to payroll your gangmembers." diff --git a/modular_skyrat/modules/opposing_force/code/opposing_force_subsystem.dm b/modular_skyrat/modules/opposing_force/code/opposing_force_subsystem.dm new file mode 100644 index 00000000000..fa98138fdc2 --- /dev/null +++ b/modular_skyrat/modules/opposing_force/code/opposing_force_subsystem.dm @@ -0,0 +1,196 @@ +SUBSYSTEM_DEF(opposing_force) + name = "Opposing Force" + flags = SS_NO_FIRE + + /// A precompiled list of all equipment datums, processed on init + var/list/equipment_list = list() + /// A list of all currently active objectives + var/list/unsubmitted_applications = list() + /// A list of all currently submitted objectives + var/list/submitted_applications = list() + /// A list of all approved applications + var/list/approved_applications = list() + /// The max amount of objectives that can be tracked + var/max_objectives = 5 + /// Are we allowing players to make objectives? + var/accepting_objectives = TRUE + /// The status of the subsystem + var/status = OPFOR_SUBSYSTEM_READY + +/datum/controller/subsystem/opposing_force/stat_entry(msg) + msg = "UNSUB: [LAZYLEN(unsubmitted_applications)] | SUB: [LAZYLEN(submitted_applications)] | APPR: [LAZYLEN(approved_applications)]" + return ..() + +/datum/controller/subsystem/opposing_force/Initialize(start_timeofday) + for(var/datum/opposing_force_equipment/opfor_equipment as anything in subtypesof(/datum/opposing_force_equipment)) + // Set up our categories so we can add items to them + if(initial(opfor_equipment.category)) + var/category = initial(opfor_equipment.category) + if(!(category in equipment_list)) + // We instansiate the category list so we can add items to it later + equipment_list[category] = list() + // These can be considered abstract types, thus do not need to be added. + if(isnull(initial(opfor_equipment.item_type))) + continue + var/datum/opposing_force_equipment/spawned_opfor_equipment = new opfor_equipment() + // Datums without a name will assume the items name + spawned_opfor_equipment.name ||= initial(spawned_opfor_equipment.item_type.name) + // ditto for the description + spawned_opfor_equipment.description ||= initial(spawned_opfor_equipment.item_type.desc) + // Now that we've set up our datum, we can add it to the correct category + if(spawned_opfor_equipment.category) + // We have a category, let's add it to the associated list + equipment_list[spawned_opfor_equipment.category] += spawned_opfor_equipment + else + // Because of how the UI system works, categories cannot exist with nothing in them, so we + // only set the OTHER category if something can go inside it! + if(!(OPFOR_EQUIPMENT_CATEGORY_OTHER in equipment_list)) + equipment_list[OPFOR_EQUIPMENT_CATEGORY_OTHER] = list() + // We don't have home :( add us to the other category. + equipment_list[OPFOR_EQUIPMENT_CATEGORY_OTHER] += spawned_opfor_equipment + return ..() + +/datum/controller/subsystem/opposing_force/proc/check_availability() + if(get_current_applications() >= max_objectives) + status = OPFOR_SUBSYSTEM_REJECT_CAP + if(!accepting_objectives) + status = OPFOR_SUBSYSTEM_REJECT_CLOSED + status = OPFOR_SUBSYSTEM_READY + return status + +/datum/controller/subsystem/opposing_force/proc/close_objectives() + accepting_objectives = FALSE + +/datum/controller/subsystem/opposing_force/proc/get_queue_position(datum/opposing_force/opposing_force) + if(!(opposing_force in submitted_applications)) + return "ERROR" + var/position = 1 + for(var/opfor as anything in submitted_applications) + if(opposing_force == opfor) + break + position++ + return position + +/datum/controller/subsystem/opposing_force/proc/add_to_queue(datum/opposing_force/opposing_force) + if(!LAZYFIND(unsubmitted_applications, opposing_force)) + CRASH("Opposing_force_subsystem: Attempted to add an opposing force to the queue but it was not registered to the subsystem!") + + submitted_applications += opposing_force + unsubmitted_applications -= opposing_force + + return LAZYLEN(submitted_applications) + +/datum/controller/subsystem/opposing_force/proc/broadcast_queue_change(datum/opposing_force/updating_opposing_force) + for(var/datum/opposing_force/opposing_force in submitted_applications) + if(opposing_force == updating_opposing_force) + continue + opposing_force.broadcast_queue_change() + +/datum/controller/subsystem/opposing_force/proc/approve(datum/opposing_force/opposing_force, mob/approver) + if(!is_admin(approver.client)) + message_admins("Oppoding_force_subsystem: [ADMIN_LOOKUPFLW(approver)] attempted to approve an OPFOR application but was not an admin!") + CRASH("Opposing_force_subsystem: Attempted to approve an opposing force but the approver ([approver?.ckey]) was not an admin!") + + if(!LAZYFIND(unsubmitted_applications, opposing_force)) + unsubmitted_applications -= opposing_force + + if(LAZYFIND(submitted_applications, opposing_force)) + submitted_applications -= opposing_force + + if(LAZYFIND(approved_applications, opposing_force)) + return + + approved_applications += opposing_force + + opposing_force.approve(approver) + + broadcast_queue_change(opposing_force) + + return TRUE + +/datum/controller/subsystem/opposing_force/proc/deny(datum/opposing_force/opposing_force, reason, mob/denier) + if(!is_admin(denier.client)) + message_admins("Oppoding_force_subsystem: [ADMIN_LOOKUPFLW(denier)] attempted to deny an OPFOR application but was not an admin!") + CRASH("Opposing_force_subsystem: Attempted to deny an opposing force but the denier ([denier?.ckey]) was not an admin!") + + if(LAZYFIND(submitted_applications, opposing_force)) + submitted_applications -= opposing_force + + if(LAZYFIND(approved_applications, opposing_force)) + approved_applications -= opposing_force + + if(!LAZYFIND(unsubmitted_applications, opposing_force)) + unsubmitted_applications += opposing_force + + opposing_force.deny(denier, reason) + + broadcast_queue_change(opposing_force) + + return TRUE + +/datum/controller/subsystem/opposing_force/proc/modify_request(datum/opposing_force/opposing_force, changes) + if(LAZYFIND(submitted_applications, opposing_force)) + submitted_applications -= opposing_force + + if(LAZYFIND(approved_applications, opposing_force)) + approved_applications -= opposing_force + + if(!LAZYFIND(unsubmitted_applications, opposing_force)) + unsubmitted_applications += opposing_force + + broadcast_queue_change(opposing_force) + +/datum/controller/subsystem/opposing_force/proc/get_current_applications() + return LAZYLEN(submitted_applications) + LAZYLEN(approved_applications) + +/datum/controller/subsystem/opposing_force/proc/new_opfor(datum/opposing_force/opposing_force) + unsubmitted_applications += opposing_force + +/datum/controller/subsystem/opposing_force/proc/remove_opfor(datum/opposing_force/opposing_force) + if(LAZYFIND(unsubmitted_applications, opposing_force)) + unsubmitted_applications -= opposing_force + if(LAZYFIND(submitted_applications, opposing_force)) + submitted_applications -= opposing_force + if(LAZYFIND(approved_applications, opposing_force)) + approved_applications -= opposing_force + + broadcast_queue_change() + +/datum/controller/subsystem/opposing_force/proc/unsubmit_opfor(datum/opposing_force/opposing_force) + if(LAZYFIND(approved_applications, opposing_force)) + approved_applications -= opposing_force + if(LAZYFIND(submitted_applications, opposing_force)) + submitted_applications -= opposing_force + if(!LAZYFIND(unsubmitted_applications, opposing_force)) + unsubmitted_applications += opposing_force + + + broadcast_queue_change() + +/datum/controller/subsystem/opposing_force/proc/view_opfor(datum/opposing_force/opposing_force, mob/viewer) + if(!is_admin(viewer.client)) + message_admins("Oppoding_force_subsystem: [ADMIN_LOOKUPFLW(viewer)] attempted to view an OPFOR application but was not an admin!") + CRASH("Opposing_force_subsystem: Attempted to view an opposing force but the viewer was not an admin!") + + opposing_force.ui_interact(viewer) + +/datum/controller/subsystem/opposing_force/proc/get_check_antag_listing() + var/list/returned_html = list("
") + + returned_html += "OPFOR Applications" + + returned_html += "Submitted - FOLLOW QUEUE!" + var/queue_count = 1 + for(var/datum/opposing_force/opposing_force in submitted_applications) + returned_html += " - [queue_count]. [opposing_force.build_html_panel_entry()]" + queue_count++ + + returned_html += "Approved" + for(var/datum/opposing_force/opposing_force in approved_applications) + returned_html += " - [opposing_force.build_html_panel_entry()]" + + returned_html += "Unsubmitted" + for(var/datum/opposing_force/opposing_force in unsubmitted_applications) + returned_html += " - [opposing_force.build_html_panel_entry()]" + + return returned_html.Join("
") diff --git a/modular_skyrat/modules/opposing_force/code/roundend.dm b/modular_skyrat/modules/opposing_force/code/roundend.dm new file mode 100644 index 00000000000..07b81ff4e8a --- /dev/null +++ b/modular_skyrat/modules/opposing_force/code/roundend.dm @@ -0,0 +1,14 @@ +/datum/controller/subsystem/ticker/proc/opfor_report() + var/list/result = list() + + result += "
Opposing Force Report:
" + + if(!SSopposing_force.approved_applications.len) + result += span_red("No applications were approved.") + else + for(var/datum/opposing_force/opfor in SSopposing_force.approved_applications) + result += opfor.roundend_report() + + result += "
" + + return result.Join() diff --git a/modular_skyrat/modules/opposing_force/sound/application_recieved.ogg b/modular_skyrat/modules/opposing_force/sound/application_recieved.ogg new file mode 100644 index 0000000000000000000000000000000000000000..2ddef0c0b02aac12b179d8280722a2e03e5c7955 GIT binary patch literal 28950 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 literal 0 HcmV?d00001 diff --git a/modular_skyrat/modules/opposing_force/sound/denied.ogg b/modular_skyrat/modules/opposing_force/sound/denied.ogg new file mode 100644 index 0000000000000000000000000000000000000000..627c1f3c847cb9d3e855ac1fcb467d0a2d30741e GIT binary patch literal 28654 zcmagG1ymhDvo1Othu{)C*|@s}CuneYcXtax6D+txa0u?f10lG(ySqzpf1Bh#_ndd% zTldatdi8WoS9Mi=)l)Om8+mhcWdI8J&r$U8UxVWNo;BzV$j#o#$kO?x3nW_lpG(|9 ze;YqR@-HL**YPs)g)(+cCxOoU{Qo-op#L$VgU~fB9V{5-oy@^DmPTrS*@Gp)tjsK| z%&g38U}||=J4**AQ)g2<7n&E|AlQFHX@o`8KmY=yheZb5NEe=QI7|0`RbX}#8~}g;{HPHlbG9X|hPlo0s3M)RxGm-0 z6@cMG6<4_t+b=1N?ec5#t?hnsF%^mMJyk^51Z}Ue3eZJ8A!^5dZ1{ zhRj764&MY_7~zHeSDO59P7qfA)B*#35H$gb7;MQ(?14(6p)qp#KlF-N9Aj)^$||y| zki%71-OY5y&2`4jTk~6>_D^rkpMl!5fx6d$hIm2$DL39L*DvL->R=F%MaG@DLGzuI z;QKoFcj$niQYgUW#Ux&9{#U|djW_~g_P*KoY*Ct*?XM%AVtDO zv@c#}=t2hVznt*mb^s7!A?k7@>VsHAiDANtL*1Ew##wd-Vu}}w{GX4{fAIoQge2W8 z(aH~jE!yy}S^OYu@v;#_kpD@7T<|q}6Pz-daz4b3nzEHugq=Fk7NU|$)ll>;^{)qQ zhVeHbzNG0-?#fCYO>rKUL{7>3*Ydzjg)b`_hxFm^q@i}>8$zzL98ZBSn$v)c)f`RP zE^NStv_j%jscIWk{_*<{EQ<8fhTFK;AR|KNQ>_~ibs?==leFU@#FxJR9X>)3zZuTr zb*Fy;dq=_7~hi6A>vcRphUrgin>{^5w7QU;qd}|BK@Ps{TUx zABuBhLuvb|s|Q&J=wGVRj$xjIA06l-$Se>P({n&j98tTS;atxB!8)&YT8l0(UP+23 z?_WegoC-FHeh-KLH%NlMIrY;NK%(M*I_{Kw1cP|&f0U6kB1KFJNEu^gP-f#-RZ&%U zv(-#;U8oP#opoKA@m`sU(8mq>-+}eNA_ss3O~Bunj5i8r=}GgK6Gr^!;QxvoN9>*$ zqP`e%=_+#Bar&V@?DFUAV_0H}?6S%@x??!56R%B`IdvyEOea)Lr`$~E>P)rky*2Cp z6EOe6W@X0pe?-nph>&teZhVM^`R~ZdqK;gD7fB`=ORgD9>5*t2l2VkMu~+mR>3@qH zi_n5^p#@(<$kZ7u+ zmp%WdBmWr0pe|y#|I+~g&>D>_{dXNvRAQJ?;+RrmP*vgoKSvCNI>jzK!45HO0s!Cx z02#!|0qCJl(ZY888VD@gRPc*x(Y?9pf(kPtQi7$GYm(FDdT4byB#EA_K%5h+P= z7o;f-hm|b$Usjx|Gj$w_E~<*E zrkX0Mnr^0=*Q)B%-qH}Nvg{m=s%o9;+@-B*qW7AMs;;`}+_kFaYai{Iz_lyyHM|$j zGgGb*s^PS$VZG}LwPlK>)%U{U6zbyQqT)K+;_@=>@4Lm{i~Fn0i_1&737>wU=kJuA6K!#P@5kmU9&*=mW-$mw`r$A;}T$Wl~a!_SQ*HL;Ptf=a( zn_#-arK^c+x55>vJrnW0c)yW$pcx{FWwG0y=od4Q?gA%-kX}{x%Grve$VCklcM&lx5kA@S?8Q+K~|9%GMnD(^fA8ZCn276lbZj=}Dys2*KF)_f(4K z$$x2XWW~@uZB+ImoVGF{79xCmUMrkCe%uJcDpn~RGD6#?AwSUyLP${xtKFV=w&A#% z)GB?EAq}}hI7c;HszFvAKWIS6579L1WeIr++xK6Uh9xc0od&sS5rqf2sfwIrglTA0 z2j3%5)DCmg&~#06BT(eMmZoLsQnRL^foQ=1$vggrEu3sf7YGSO6A=)FL~%D5vhKj) z=i&K};^kr+qm$<0LHv@3Z49w3o-?X2Exz&aduo~h1u0sZKy)cdiabbyi$ny;=WIsf zHHaV+`nQf4AR8gG1c6;tSZOf=WTdEyK0_>8<_dvAUe}iVe-X&s(tc*kfsI=W_{;0wTIFM;T?p1@_ zkP2NGLV)CZ+5V6!FMj-mpd_^ihV;?oxx5hKm5=~{)&Y_c{ZKS<{t}Y~Su>#kkC!!5 ziW@#VUYw>I93QI$5eHGJ$O#!@yDqgCLcG=?7y=C&4mWfNth%*Cq{_N9tjkIArj1HD zW*{K0-A=KVf)K2S8USDs79RKkO(@1mg@;JXZt_H)dQzT_X_5CY`18$#gTA$qCOoFo4`G5PNn;{T5lMUXrTLk)7b?#3fT_?MN7 zWBxrgw)szz{_WrC|H#?@JA3~>wY06vAdvf?6(H1t1P?sJ6RJtPqak=j|Dq#0DkRbC z_y(CV9C1Jp&2DZ0#68&}Qry%O5R}l+K;Q$3=y)xuWM?HMT8g~Hm!)G;ONs%)8=fL> zTFD9`g$E(8X7WYU?E4QidDB{943LnMf}9$Ka|9_tF6o*zDrLzXSAxVRo^dH8fV8Y3 zQ@3WIshu_ouZ7qjvO-K7g>g)4y#iM4900!$KOBP+a;w|NR{#2%1d?nE|F!nZgMkvn z7g;Z8ArX~=py~x9BmodN{Ob#d{$G9QJUjoO1p(B~zw6=^g#SVdAsf<1Lks~K_1_i+ zq=on|f%^-_08B_K7Z2h5uP+`GBI9p*7q9e!NQh}(2!Emaw}nXZVy?dzll&X|k_$p0 z3jMMQlkJk{^po1KueC!fSoBH(e#ijeIBRu4Gu;dBN()Go4v2O_H)6z43gwolH2r|z zg*O$?l83FVWWAea6s{AFZP-IxsMsn5;<1NIe10dO$C7%vTL$OswM1-;Hv*RN)gIUO6&sTrJX=rJgS=l+cIM`TN*jR6tmNx0Asp;rwS=d?FSvgqQF4h)i zSE%Xf>1k=G**Q4gJz(!mz^w*FeLXpb`iK*4LYC5jN$^`tvBtaSod4lrRtL%(9vC-m z((iZw@fp_7JZi#mbIrkFlhj~8%4a>-Dc2B~Sh$b-$=|0wp0@(&lO*__{b)F!A%>b#LLy*t9Xd$ax&JK`xH+X(f?Et1PbpEDTWhPH4S>Ze(m+PcuoZMAxK zW`D;Gmr8D+CxR2Ren#e<5)@+>~o=$-+eNZDxYCq;O<*eqDVV8Kl&YDUuEDd6TAbg7GP8 zCG}`tALjIvJ~ZSY`xuk0 zXk)C@%^W4qqsnO9X{3AVwSrwM^oQ)yS%~7>@?n)Cfl`?NXp(f(DTxb(*cbhxfT8vU z8o)(#+NP}<7&J1yVt*}}zz}2WT~hcZhvZ0IzMF!jMBb&*+U+T#Cim)6EX`A@Y6-?r z;7%zk-U}PpwDT~&nk(nQ_S$Sg%Zgn<^PC%`O!*O3vk_mA_~lEd;FCr0Ymt?v?6vGa z#3OC8V$h%F#JuD)WSau&te`K!-As@;Zyje|ZG|yFRN#PjQDyMNHW)f@c4b8=m!$T8 zrD1TnRk}ycp`xDXITig{sf58csk`KM2UhAzTKb!iwJqjv|4w}#ECboAO#YJj=hHr1&q(Ar~-1HuC#8kFGLu(`ln36h+!l-M` z-jC)RB5b1eyPh4miV136(DQ3S(`46DO5oNA`NjqLHr|Qd9PGc%0;Cd4MpE>a#B}6x zXIqrCeK-Q}%J-SnXXTn?1A9{7kRnm4=8BfCy;;`9=b4(h-mbuR3F;6UygIeWU=xen z65hmzX1=a?^R^BKlfa}yZ!eWIkacx#2~!6xn0KdiYDYqvgSh)==ykDJIyxTr^?lw9 z1_o*Wif1GAo8;0~XaNwu)#)jLfT~d;{G@QZ28*kufK`Y|u7(Yt(pa!ZBqFX{DO38R zr9#|UEvu{Ga|GMn+Wr*M(C6V$0vN9va@PYZS=vB zA)sSP4x6l=?u^ogOE&Nh6BS&d{%}BJ;#Do43Tsw73^WN1=L+tI&G+`fwkpJ~y%JmR z#yhIN?LM5WEo(-D#_px9fcGOYgi@0TFo9|Zy}Ia_k?;=haSeXLXnP$7%d950BqgU2 zXBc`=A~qzE(X!PY`3hH-EN0N2imH}dRbghyXOc{RWQLz0u=ev@(`_MHdtjK5ftb)0 z%c5X-G}_zMe#`F(+9VF#(I^-$iUk9i>LC$KgRxdfJg!^kNLt?m(xhDUqV%$rLfnzh zuweqlZ`vINOT24LoT~Nqcpo(PWa4FWIeq2jWDG6G4?FgKXQ~Z{Xq7T;&y#SV+2h!kInKkSHMOv zJd>;yWo`xjdx>bbLay|(1*$5Tj;qeC7f0vr!*Z~yBJ9P|k4c2yn6~iOt8NQX>V)aur&i@+@s#A@zR#`jX9Ap#@O{e zH#6^>-;iMJ%;F<2{}@AWw0wW~{pO6M%_7t>_^GlgH_0VDeLf?W4i9(cr)~_Ztin|q zJ@BxnU@20lDHgxTuuMy)!}_?kQx7ffslV4R9F*Wf@)&??NZKP~7k-!l5baZ&Glv-% zV)zmRdOa;99Kl932@Qr}nTbL9DM76^N*EY~)yJ}tm!lJsw1@tYSPLYe9?>OO zNlY_&9r}JceEX(FyXSu;AUjcQxd6%Q~^gAcnO2yCRKEdd!;MRl~MJ&n$(3o5xRBdBkYmJNei=FN+5 z^`;d+KIywooJ1yFgmmTm?<6hG8Uz!oH9n)HiKnmMo0!uRJ&%wpu=qVHZp(IbLvNbD zLL&%R+3wz{KXe(gXHzRTqje>S&#(Fz`{*SsIR#fslD%Q>4L7P9j_UMF(PP=M>sGmk z(pGqP`Z0{HU6DOLlfKRo@k@;eEcmq@=q|bIJ1*gzM*PJu+mM)B5TMc4IU8Zx{@xkt zw1XJPzQJ_X&z~oceD*Xvt>}o#G34sxsr%;bI_jiVb@8E-1dHoVzDiV`@9TZTvPD(g zrmZM{q%AwEcl1zYoTZH5v6u776?&%@=*-)?C=P6EB*L;Sw_ESrJ0|{x6PaYtGmI-#>2Vo;g0zT zW~JQS9~eXO_htgOP9jUjtsK+uU2vMW&;YVLW(bV5UvX~ohheE$O;FZIWO}EH*^{xt z5T{TQZgiLX{Iq=lK_Y#bR4T1MhnqCiZw>{H{YQ@g6_-x~!XyPjhwiwu&i0ii50V^# z9v{@zX*V!UR?K$fpF-d8oP|~0NRB`kY;iWw}OYkfH zz{jxf7ZdjvzFn50x6EDXurzI0phu)3h@-S6m~M;{O!NKJS(~lZ19bGhZ?jUo(mIx5 za3$KhuM^Ildv%_C@n#rA?np7TS9?t~jsP?xMe2m^7{iV(zZDn9)H-_$7});=x6R^S z-3iC;fC3OeLdPP4hB$jRxJqdP7$poQmQ%wj-SO8d>Z*o;#?l_<6Qgr0oE3je??Y5W z3g4)j?Bl?VfnAI!>0ijqQJpR8sT6JmR9^JdIWkv`-gB&4X58sfWhuL!gXxX=+a+C6GP z0MHh(;y^=3H3=pcC*1+Sa+2O`WFLu8p>g%iJlq&2H{FzaX0=BW544YUoESs&w0bA_ z8V@Z@@tm59IhvKwoij!hJcJX+rkag;VoWC&utjtr4z&|$S5xM>)d zEkjJXU&eu~K%W{iT|kBaI%RX!em6?`VQ5yJF_zG?wyHp+n=CG(Ch9$)h8U!ol;{(` zl9w5*NYNJNYXHbd6x#vb$`wqa8ec!u0L%ic0xYWz8yi>S8LV9U%*iE}iMbBUFe}=) zJpMNeN@3|UmCN}%<==cJSlq1yv)u;C72V${5A>9FWr0h!Rw71KWcV5McqeC)7tFhu z11Y209s)?9ZOg&+>f0;iOP3%agyz)@WPQh}1JeWT^dN-sirb|Ww1QcoGu0zpD@*9g zs^4}z4_)QTC_jkN8+IiZuyvgFu6ta6^xnB%$YkLf6rClIC9B1Wp@vT~P|OP-=vm(C zMRmIRK>^tA#yLuPCG9qX6`-E?VzNz|p`^r9HBiCD15qy3qWtaywT+u)H~@@4TYYxj z0S>3DaeY7j$Df~x)nWY`qIopdO>9L|#GkWNUzca&BVxHvpa6$%A<)Xdbb3U@ECjFF zS3iFIy8rVhbu80GanA3wPmoVu55%}7?f%S zvpwJhM|ZZiYaFV|QNzWhFS*EQ#U;0;5sqQV>lTQE&Zaj7FL@;Y2*Mp2k>T=+ysm)z z^yj<3zT0ILarDn&(m919htFjm3&!B3RYGi#)V|3pZkwwj*thX%_3Hi<7nWV*Jca;NM#Z zp-=z))&UyQjQND*4`%0le1=-yU)emkVq{>Tp`~Z$;$UZ?qi1EkKR;PqS<2-Jd1FHB zukQ!Cdq&NI@=M#3iZf+18dmVy#PM;^JTtc3h2*yj;5kESz zC}6)9+Qrxi`xHrIpg%u6QHIa{;i#xb)#oQ6_8x=<5g&M%Q3}>}2SO^s?;xG0B@kuG7N3a0HPB`TZ!313S7O z4Y0rJ$rqbp3*Sh>=VIQ+Zi{1~Pan-lxG`BYS>=UWc0@OO^9%Q*n85pndafT>me3W- zl%A(5JT%QHO_r?`aCrB1ms;|Ej+ub|;@QGUcmzswZMAG3y#HK;yASB~ZEi82&fz6z zgl?Sp1dW0MD6UxnW0BIrP4ViZnJE7X`!{UQkHfOwt0mP*^-4)|zf!92+&R)^EeT_- za~k-?;4|~cw!Bm&^!g&t4Bm45_TnKQ`wDw8`cq(G0{LEngG#oh9@;-vL&P#+;81Zb z?fal671WwIbNX*w9`%x$1-3b9|0~mIQT4FLLLZo* z2z{~ZGI-9{W)BUY9)I%`m4D)1m{7RzzDDZ2faDSb6^OHHE#To;bpzTa_^v5Up)Ef{HN}xO0J(z{ypF&|_L{}cGW!#cr z34e&Ap^e~Y9e{!Nb8(g5cgX_lkO|!;C9hYj9v9u6^mgyY85ioe^~<`sC4zE_XX2c* z&EIhhWa~|cWe?3&Ny(#8 z1FQGl%sheO( z(;wt2>g}ZlS*xv*hcyW!7C(GnWFHPc$QhEKmVeKsLZm`_aA2sEgLz)fqe5Eli)|b~ zKS{Eyd+|emq4<7jm}(}P$28&@@eqtuMI5(RUq=(QLCpGK6g-Dcqa^Zl!+`VFp#@8E zN_*(MHdMUt*&Br;7Vh4^j)(AEJ$FjXZ;aDMAvP@O1h;nmJkVHGhL_$TUa1HV>VnBY zyb#~Qd}~fV+s>x=Yg7RMp5}1^nDhn2FBJ7=(QbMrT13Q(rDsA2 zr6Nq{0Hb&Mh%6&dL=M15UgphDe-h@0`uH8Rw&xb88Pb#M`=YyY-XmW{V@U_#FI^Rh*)Mic~F__~C zDW>Rda={Qa-{9}du_HsvCeW8E8)m9)Pneam0Lf+k;p3^qL_xW>`%MlA+{>2ccJ}lM zOfc2fe%u%{-x+8>aZzP$OiOb_wmPSXVQ4G`s7VXP_C}<Rkm> zNO7Gn%X&1ds%*$Dxon@Kr`3h$lRl|1_OiJSXs7z((EQQcNg)LFe|}>`#9>W0c+F@} z;q#%9#v{_5zvAV43BaaxcM;vJ92M#Dz4hDCt=DqA=h*t{SlxJ=d)?JJTV^upti$0Q zA(9Fu?X_C7#@oy%-247l$G}h46(G-Y&5zU1<4tIx{BVUKRH17Hs{mTt^|?u10J;O^ z;_Nzm(!$+a9AT(82Mh*-jZ9Q`G9|`U&^^WnY)|!{3}liN<`oHq%I%?}zfJfp1JTez zd$soK*E_8j94Gez2G7XFlargD4s4u~_FH2IQ7^w-Mfft%z%P(bEWVdCXjB_>O%`nK zGdsZTW>-`*R>|@i)b_*-`ye0eL^Z56BOShp^Y%2eQDj<2aWm!XSBtK+vFjLbH+7)~ zpn_M+V-@=Tu_+z$vV7Ey>FE1Ar{Ci{uDK&A`ih@QE@NIZKi|I@9tDGbWI**IqAStg zg(;VBTfMwm-*wMS5I5|t6#mpJMw2FFnWs3I%8TVXO82K~aPfLy^{#b5qJkl0U*w)O7y zO4_9NoaBK)^rZ1_9av9CQy<&XY;lDz9oY1#C;y>GTkyK}aT!GYO5ZyqweX#1M4HO_ zf~{w0JkcOSvYO!=`DMw+*syrJ6Fd{6Y(wSzKD)fYqj_jQD_GzP=>9PsGUNA{8%!W# z?_1zpfWc|8<$9vPsp?wRC|ycb98AG%mS$99g4OFGoU@IpP^sr<4NBGHPui6Hc`o5z zrz|=5Y5N1ik=t8JRrW=v^eAcOZR)t`T&x>7SfzQ7iDzPe zGTlqAhz}lM9ks#c#?oM9^tfE}3QVBJ6M)namDp|4CC|A5V?#b`jl8wqM2cpNW{z{* z<$H5;@A<}W@bfm)lYk1PYg(erCW?U3@M|Gbi?3mH%FXnS-Po#vai91q6-YI#o*6MV zF_mP~UjdV#uZTLt&`UE#~Jh`#BaH(IH>Ge_sXHK+WIZb3orF`ckTv1la!1lFV6nhwfCWhubT6>`;o3>Wh?D~+5P}iWYu^chin2D1Ar@LOS zt2!ODiNAa}k4qN)-+? zxSFvEGs{;$o^pSbSINfwoGOnw3RAQb2!O)^Y zGP1{>*CLJUa#Qon=3X=u?^!|bC#ORnZFB>L<&5X{aa4qEZp?&2?7O`*zKdOYAwOCb zdyQqz5I)exz0Hf6MNW*zGx)P6z18}aJ7VJJHh0ZEMN(Z_z4&A-MXa#H{hYlh(Eg zVGjM^`n}BoWataF)VKHG3i&A{S6uy1*`F)GV33g8Tc-M!BYwc{dc0YPZy~Ir5Q?=F z$B)RBe6XOQoK$ccddkB?Zzr&7g2Qfr`Lr88A;MGEnyl#T#* zYJ%(gs)1p1wxA~OCo4)v4dW`b+Ar%E7k*2*C5=+p?->ZBk9*}pt}!b|d07UZHNNVO zdzdHpqFl~k^b|C|27n(8z+lq}lsV(}o9!X>xE#w87B>>bA(4nJs$QMtZ@r2@vo%^b z=n9?k+x{TIvJ`GI5ZHOJSiMW1vw2C+!Ge^~YmZT$CTq{>1MM@PkQO5I+y-wy*@-6L z<2z7&lO;_|u7Pa>lstjh{B#zi29ID7;E<$24sp>3!KKnjynk5AeTkUoW)v7``5Y`R znbzsZa{Ux*IW=j*6i>z><^?$C#_p=~e;O+rLQ6#Nq-L+0m!8{yZF&euinq_24rf zDhYN;DzK)#IDU>(xrCvH$zRpZY#TxXKAmh$!qa2vWOM}B-R~u%fHgIV=y}Kw%;{h6 zCgB`^#f==H<;<8@9gE=-@Ut zvdK_hgVb?R{zUs5BJk1}X|VBx#^{`CMXP6^F&%wgh|kl2e}ko<4lQY}(@WI40l%GPtZ1R~-8M9AmI%cHp6Px#mXC)DS>s7+j}#gE zh!n>}cpN}tUu_6SnZ80#fq5>mAOfIb8CzK#OX0WK08h>j-TG;^hafkOw5>m}A)tcZ z(JSj}C?SZl6H{URPQ5JS@>bup+7M*%CF;~}Z#c=TW)qHNZ0S$cN>7WR^G%w+tsvc^ zi85Ssz^#_EcYM*I!IF#d&a_vJWSW->4q+`8gQmU9v*Rhr&%v&i=oQx=i&OTQk_o_v zT+D0#dPS}Ki1NYG4|EbeON%5VgN|4e;<|rAxaY>QkEy|7z%VDLy2R9(m9@kxo3@hL zA)j?lU5j2fcTpgZKD*^&=RnhY-=?yGv#gdf?5Vh}H((bXvLi8`Cm|PGov`+!2-`{v z9J;?6RI3Uqt+#Sw+)7S)p+o3+;H#9M56%sJu#6?PA14@u?iaPzVFD;EZ6wWY4=}}j zmj%uJZEzewcN+*fUpe%pi`82{@w8Aqnrq=pe2oIzFrm$Vt!uQ)&ngG$Fp3d?lR=F} z*H&h&uhZPplhZ7}4LCAVB1JlvU*ty3q|FgL-xi{-j@cgw@rk_!U{Iwmgy#E$vVETH zKq~MT>{{EbJ)F)6TlI@`OU6*(J3ZTROE7zt0I9%3zv!A3(N=V-O* z2YE*?7Pnnab5S898>%g;1ZoDYZ7z|`EX$4J+bOvecqh&l^f+feQc68cQT(j2CVrYF_%~4esGLjpIS+4X6){b-s@jV$U%nxlt^EW+{1c z3b@rjZSlfe6v3$of+F66r8l`C*K7pe1iUnSI971v$?sLTiwfPF*GV?KjTjvsmZwv< zU8I+9Fv>ZfmB*7ioq_0kEP?b1ULF9+=i6W}%I9O?l!>GN)J(=Yg-%&9OzrG$i;nF+ z4%(g3b&{`jR>M+0+`Og@|RZXE`mfE!|h%)HFlEy!hl_6z6XcZ`&NV0ogH}dx4*If zc(WY%>nz5nn%*xRe95CM`4brc3Io}beDvEm z)MpA+yVLDp`P()A{@ExW8m}_aXX@j7_>5krb~elkqu!Yr>K5^t_zAa<>FT1AJMt@0 zpM|Lt^r4+}>#DqBI`ES3a&amAJauvKD^SqQMdYV2(hSr=KGLwADHG7~Uhg9Xl$kZ` z{Tw33!u2>Sd4QCgvvkLstIPNq`*iP?r*dCQ`=;u>frI)@IXB~ULba+l-i*&i6VJ1c zJlg(nwcR{I$Lh`YGy3)32c_mS?Dx$iK^E_1iTOXY3RjMZ!U}OF`+i-bIVwiqrDyF)lfqjOPidI8>c> zf*ua~hNo>*d>1ML%o>=wQ~s*Y#D9F0(M@77skzS2&`rGbCD9{$*z;QB;cd(Ovs13N zyaPJo!{`~3+m5;6#CHmz8qEom{I*yPdz!o(t{(wsJbf#}%BQF)l(}>*6Xaka&q2kD zq({7xqS4_e)0A$|d++mWn4}myaz3Ggf70%}ospR+xNigjFRLY;B^QKE3 z!Ylf-$OOkX=R>{R0HA=Vt?Qy5{)$7s>elaaplb#6E9T537}}!Sd%wV<-NP)vh9{ci zHm2jlvqD3hvLZj3EUY<7a6PqV>vzq4UF2t7(I&(?2JtHK%7@tL7@m)B@hfuPLfwC$ zJ^g9XUtrzz;rO7Zrl+%;EoauWxTWa}l*-W=Jjjf)#Hp_lBl->RL&KRu_`-Ks%r=Y9 zM?wJ@6cO8Adlwr5Gmr0z=s1=bx!}^)>L;0yTQ?JjXCLJgS|Y=K#IYp@Z|^8}4E65_ z#bWP17mHZa$PD#{;4NvwL8kTSc-iyIa_P(U)S09L!B_bQyani}}ynfq@ z*XJBl=Dn#v#Vb+LrPLbVrViz*$P8>?sm#yDN6O=Q1qV)c~&p zcQv;cS4euR`k@C`Qtz}>+hG3 z3N#$5+l^B1koF^Wv(oj)b+3M{%XYQ%?lBSz4UA4CjTO1n`A=3mq&et%7Uog5Ojft! z?ZA>O0H*iTlsAVW#b))+Xmwhp>f&!Yh zU@WOZ1G_|f;a1;GTeO}Xa*Mge8y!Y=-h$PgSHl80HdNTP41H}!?t#fQQE1_h(3bu9 z4n-EfmTR!2+zT>lMcfC5EKc+gN$eesuNaL$z~CNC4zOv!el805EAygl1_jitHDP|BLgrk%##$9WtKw)eiqtmm4X5S*R;2}0OWl3QkHkveDa}gvs^X1V7StqAjngL2x!`~P}2rSw{AZ*L*9$zLoYk=go-LkLU1LdyJnNC#l|KzSzQRES$gi4o=0L#1p);`GD>L9{dc|@?-wrJhK$~tN!&bMW@#Xkh9~{=<4R2g>Aw^RE^S7CP zc=yS;rf$?^#N_t*;Lipo{_7q`B?>?k3Li?GQK)aovZ@%hRn+bC{M1jK>8!jFTa$+P z-9+}itI*M)w`T(JE|aX%fp#SGrhd&9))216S7gahpavQ z$S@KKL235RkY8bJC|C)z6l3(QOXLS(!~+PPMqHRALx;J;H;vIzT=-IW; zss6C=ssc};Y`$i=XSnN-crMCi{ARwrGJkgVWA8e4sPAn3v+fLTBh>B>ZoNm7j6T@^ zY()V5`;P%H?+_qgMu2IvtZ#%{+sm|cbTpK-RLpEF99zeKPIva#w@xiIdcModw~sAdEKg${ifb(!;)=PpKakvq52$ z7B&P4^treEh2eMk_%4b1u1hrJZ?hwKQl=-{b}zhg6O1cHMRs-PI7F?*E%K+13?e8m zRm$+!OlH8TyM$jbQN)CjHMIWdFCb7cRI20dk<8FWUVSO-bHj1@u{Z6wUsJw?6247& zPj%o8AoP!JOq061l@~Yb;Ao%NEqxPuhkOXt_7vYqPK1NUf8xjC2XKYl;_wX)|6q$4 zDZ=l6l}`a@p}It9ag7S-HP$xdeVm3551tdqA4CIyehD_>jv**;O#ieK0&t~d5G@zY zK8#v((@6hIKq?&AWT0$#~q zUr?f5PLq}t=o>4me+6qM9#r4l-cp`WVhfrk2jz?5OSa9Z83E1bPor?5;*x!A`$W78 z=Lfg9$pp->^i7k07Fk?>3ax_$T2>zq$*7_hCDh_!C>20M>dXQ^R5X+^l}gEw(fsd6;}HlCbRz^>bjF*_kGLT6 zZDz;p_5zp!FBQaq4Z}JKa1{a{4@k9+Ocix7l`?7}5@TbXYW7?Mc(|k%@$7Cwj@(PJ z4QT6tPCb;!47lnmqAGLCJ^a@GtE6zYtnjTy?io_r4xzzkUR45Wbv!Q4k-HGGChwmI zgSs6B%EKcF@wW55qis#cUP3`$HSUZczN>yBgg&8=mdr?)X&g#^LH6aizR4t}0@RtO zUte#0cLwt>-FWO(VTyOt8&>)s+Xw+K9)1~o&fPch%}5$07Mg;5#LlVTU1Q&bSY%w< zT)-uaa}w9w`Zq`)8T%FdKLG?Q`_y1NPYeKj7Ij#P2k(yorf(l&;EKy1r)MNu)Aumx zwf_FHb;t9?T}@XDZBlgu6<0C%A!^J0g)!6&-h~3@a^Rnqu7X;Hwr_o z0IJ5AFF!=|rI^AB&O6%|AG5J7AI69AFmg4dC$}EHY-?OiZ??O6Q?go_2{8ZGA*Cr= zGutLf|Mnz^%sXz!b@j(el{j99Mn)1k4KbvGPl`OL(sppjb0RJQj?5vBzRwhExXVcP z)YOFCFw~f{<}LO)K5RL=3`O^5QO;^)Bw`NF$=tB=W-BVdQX&l7S?_hi-?59kM%qX6nd?`vOsK=v6x&})Jpx4d=DZ9dw05@j>;R8$_gaDN2*~y$7PPH>zoV)+X(eb@Q zacKF_7jhS$ZkQ`IDlC;-L&690PaSa70ryomQpSTn{$!(_8FE!!8x7PEVC>Rw*Zg|Z z6u}dpHrFs~g5!^*lC@tSWzgY{b(=NV`!m5AdX)!jN5MVR_s;!-q&-0Yh+p3fl^t9T z3KVjioY{b8BQ}JoY|oTvO*OA#rj6qJA_YN!MmGbx_HK1ti)5{zC!f%40B|ZGmIom- zT~{e)`IMmeG*0&W)I?@y8wp5#e}!4p&{Y6F`xRiy&I2FyrCdk(=XhL`b)jdbl##E! zc>nBD3vg*=h%A1+Nd8-0k+|7NRe*ZH0>Z=cY*rnNsh6W8D#TA;MQkvAsbpP{3v zZ@n6tVum>CmiaIyf9!J6RZNtPW&EcN&E)720nXlT9ZF5C+FriISi#ZOW~QFC4%Wdo zB=?vxFY2+s&$t2?)I^$BGcRhP=g6FaL1c+O`*gCtqYrcSFuR$S(x?VK(SnX*u-6ta zBmg?PltF)Ysw~lgrd#HqG27_vfZyvV(*SC_>ZL~y+u(Ft@UU2R0^aHspfykS(W>9# z2ld9Ef8irw3mC&xC*jH@u((v)9vC>-QzQI$qEh;+1JH8W9&lT>)lgpu(Db+2(;2%{2R zJ=RJ+Lb@~_p*D$=H&pZXec%J_tgGx&Fr16Z!Z&rmHrg_<2 z13_rq$TX)|a8^qIzWVjlHGBHly;oYPi|~WTzgAbZ6PTD)Jq2Bj`N@Q^xf^VNu*Lvj zmo_$+7V^KYDd&ye9Ffc>PFK;j>Gw<{jqZ|9Uw)C76bO%7w07HTikKUK~0b_Fp zb;z0MWY=*!KelFrx5O!+rl6didX6mJ&t*0(n0E_;)gN2|007>4bw=iFgBEq|Lshce zKK!~;j|oy|xF&sOlswk~#9oL3ns$S!Z=cn1KDU5{i6DLYiI~$8L{&oqxK`WNzZIPd zA${DKo}qSlH>X6>&ln4`b6y0ycP-hh(B#(hGumw6N%~S!H$lYHVhVtT08eU7@XPs7 zD5Xf7dt>NeqN61+^^=YWUu;AGIy#qynbzTp*3eQi!ICGikHuY(COQM@+aj+_4&f-y z*N)3(8fiMgmj3a`xnC^{)R(mbrn75aX;4fT0N_zvzPHcnBand(hyjL%&B%9p0$I+x z-vJx~Ug-=v32}V~255fV#sm)K$_}Wp#&U9F$&g^sb?^+OkP`IKr~CK9r+Gil`(a~k zz6k5g{eBj>n_ud~qVuonD7}p9;AGtf-bm}YO87f7zfb@6R6*FH(;dVZOeLmAGPGv0 zq_i`3l*~F{=7KPg@|gn*Ny*d2apC9m&Nqu@-QkRoTeEhXbm;Gm#mJRJFILs>taLBA zmMw+l6}Ei%tA6*+l4G5hbn64oOB~?#-9)T5!Sr*oWtrHM9xLI^(FYU6`4BHv8qu|r)ZxB&Ud$pA_zhwfZ(*ABMN|7AZ7AH0|G(4G64lTXucyM8d9>Dog~n>2Yf5rh~(oUi-X;6Xwo zn+fvcJM)@I@MPLxHd-6N{r0OMO5aovuuZ~}IlP#)*M^mdA|`-ZX7I-uE0XEr_cd7*Og?U}ozb2#;f%2x8QJNHfBxi+3^~I6e;S;;~OZ?UtB6Z+~Mq zZuIo~(X{6FR-`#0e%I}apd}>#0Tgfd> z^8}l?Hvq`1t9|0+4vhuNt5L`Sb7O(pg81bxo8A*=m6ioFDZh1%AD#LuX>3*zBXU1= zNf&*nEfKAMj;&RtMCrO&@rcrmhkltS>H?1kc)HqxQ;gSB3zl`15A=jj%l^RCOp;OB zpu5e*Xq%-*Tol29j@MseSoJgg&e9ZKs2mg=%*_qrW;Q_cbsM`4$O-f+T&l z?B8zf-ul;Jb^A~9pQn~B@zTIsyEHsv9ePc$o^=a4>MzO5ho?0&eHfewy4y+T*l87Y zSVcHv9Cz$0w_0VE>rMCZC-cYTG_V!8%y?yGJTHt;{lUeEq#$B?nf#l=!0G%c)>1UC zp1oR%Nb|v+Qu8y3Y6b$i=pv>BIv+s<+;xSUUh+j!^e3nSm8u|3FD=hGJUDc z+I(5jVX9YGhUuJ#7LnJXDIVB}+W83v880(%Ux)Z(RcsGv8*ViKz8lr8H`U5&Yw5#Q zX`fXDE5RmUGWxz$n3$SL<^cfk7wh9w4;(sl=!>nhHIKUZ-{)7ahN8`n?McyriDc><0~nZTw8MhKb$m_gT=wfp&`XYLWXz7V z?Y?;)pPRc`pitwNJqGLM&wGsvJJadPFIe~?j4B&CltP(CROOJz8NVzB2q1glFOH@R zxugC@bpoiJRR}bHFxkD|OD6zNXJ=CY0Dw3F000000I7HY00sa60Ck$uraIEv)7>m8 zDkdl|GBY+SEh;NAF*Y?bG%_|cGBz+Ym@WOhBdVlmQQ^zu48MoqlM zIu=9C7bVMg{`mgPPuxP6VBkuyTmi2GCc&@+aRq_whb(CUP^d&-@zd?j zfSAX!hh5NBF+J;{ulY#3fjf$S3!}mTts5Ju{6Z=iU^Zl00|)bazFEt^w=WHTF~6QI z=?FW1F2-f!^vT$;~;{TF*!%hY^pg05Et-S-ARa(9%|xZJ6Hq zPN>kb_&QzY+n+Vrcyt6Ra4pk~Dcl{e9=LMVDcGoPvG$#p9z71&Kx)vd231$1sc%y> zc9!5csrzsGK@GD2p6Xp#Yv+5df~AK&D&h|S5KI|>%e`}_VJmiNk=pV%#zp( zG^{A_xf!f7e;4-iqn*>a=Bj~IR9hX$L90)RJ#{!DkTlw8ANdbSL=yFz0-9Gjzq;^zkdz|>$|0tDkKsF+qra0r0DxzBqn zbL!-0F8MC5lQt~5^|_a3Wx;XNhh9~7Wq4+yr^)!|rN!Le)Mmn+mv2z%P9%?y>zP;c znObqGt8$ZQ3>%uLNW0Nccq~QvgBVadB0yN+fb@dQ3DuxJb`HY#31SdokIcLEF9P$l zE;QzcLcT_O-G9_icA zt$TnF%rX8;CA9{dBJa*~M^J~_(3Z{qX=tqgWCEOGLt^Yy)61zJa{d$G$S@hu&1xd;p7(t<)XqNI6HdTpM~5OBEq5#c zgj&rE7W{^D{tJN7L1(j8QIU0_ojO>wm8q*V%b7a6gX!$ai4~k)!^FEG$ZGSjpELnC zaPU#&vp$Ov=t+Z>iV^XDNL6s-ncy!Abp?!C5ep>5#7pwT>;S1jC4u;5TB82dR@OpI z`hlXeyC9F#siE3_ux9G!|8AiX0_1Y30Gwo!3x3G&Y=VkOpzRlAyeIYkWZTA2pnEUA z;bqFtOxnN5*@PkTatcujkUXctSsNyD)C%DSHKt~qL%-AXBMrYgWD@n%v=_O-c zao$&dqJG6sE(m!s`}+a>3jl;>Wia|q`kbyecI^NV!}kPK79d|&cCs3i2GCu0SzALu z_MI20BW=~DRL$_GV*5{F>+rDw9E;N;LKyxT3VxmXQv)_I2yV@Zk27-1DB?y3fdzfA zC^^mkzLyRln+gEbR@uRRf?2IarOCgSFF?FN5aeAgcydUnE#>EBR$DV7NXDSY|M(?@ zpoiRHCHvBR5>Ek0AJ;zQHlnGIY+V=Dr0b5;ffflveePl@}9Hk&8+G#Z@^6%OQqO zkS;>q&WKa8z0B!;VcxZQ#rKa1R+nyHz0m-s{-4os1OWVQ`KsEZT!V=4Waz~y=WSBRGqn`0|5MjNdvHR(v$q>$>&NS1`WVQ zjA27thH9`;rE&S^+L%O&uu#WG=hN3}0zWx2O-6MDq-Mp=j6voXIj8cR{hDwfnP|Ym z?9~Ayw^AC9jcZxSuPx%W*q!3_xc}cI8u4jAD*QqgN&vi8Wnz++P1$o4EW_3+bdMH* z4vwa*V;wd7^ruHLV&ddcvuY>F>)nTBb+J~5tmFFUUL3We-4#4XHB98om`j9TeIZc1F<$T^d|G;2Z);93At z_>6c?+f?_?Lw)Nb7!5FE zSCz6po~%{&W>o;c)l1%^mk_X9xIMx*M5CA48vwe=C6zP19(twxveZ+2;0FLeHi2=> z0Co4Pr;dFA%3(zv9?#V}@4GIuXG1{Sj-8e z>(gpeHv9b~<-xpLOJsV}vI@be`K_qh+;>OUE~=4m+1)D~BY3X0^c02{IqzlVB@lje zk|@CZ!VK&ab789Zsl%*ETI+}hM7gMR$rSiJsVG+j0C2kb-(z3I{afGdcdv@T!6tt^ zsdl<&Ei5_3=pWahu-*&r4Ip#eok@qga-A0y#t@icK~pH|Xg?1=rJ|xD^khhl)B)bw zjd*YSx!gn#YkQa;+>htl{0H5+!LpMW(_kRX0rZ6=0nGiT1~^AJfRNO;u3~0-j#zsO z&U$W|m7%%2gDWfd@{Mju<3n@c(o}Nq$u2iP=ya?n=8zNs0KgF<68xaerGxF^w4QqQ z{%fl)K6)2H(HntcaFE-^(A7$I6Ft*U&(ST1LRci_R9eZmFISl0IvkqZG zhi8($i61MyJ`5Iy^LfXb1Fe^wFKAcT1e;e}dlNd!8ss;KwW23*x2(Ga2$Y#6U!MNf zrFp!vtp%ZM(E=9RjdTrj1U0>^*2ElM?vE-l-`91@3=&|R21ATrm)%MN$SML^0sIYT z3iA(79!yqFP6Xyrl-_J!U(Pr%IDg-l%GnG^&OgDcb zlsteYf?c+YX+-pHR=F#&ueB`Nm@TUb(f?D2Xt4WIml-tC&_uNj?uY&xx*-7o008y0dEv7-o5JHZjuDLGRF_s@!gfADZmPVhCNiW z7fnB#yti)dHWqZ)4tFX`#7SseQC^@V?MD6P2C>i^02G7q0GavU#B$&M#gPlu3!rs- z;bne0R4*<{ml|?+w^#&vdhno-QmyskF3`wzQce#C69BYk>BWXJ>*7>4-kKPI83PM9 z;Vt(d!&dXBYfb#%F;f8~pQsNMk4 zcUi5EQNi-(mM^Ph`)q>7RZ!)bzeC@`*a&%zH$MVJKLGrKSvHX0{^clN?EVs)0b3yK zf8q^})AG8V2iu_ki=W?J=_9XehTHU!l*s+)qDQC&0i0@C_jo#*#=Q3q9iY> zc7TVCF+m+O2>0gAmCNlQN`K9u-TZsPvI%4*lktt?j~A+4qMZ)b8nNgB)N;{PX}6*Q zB;S_b(?IqDIQVL6ZbT;YG^3-fW$h*OLbuLi5sdv@^JZT0sMHcZ&7fJU5{vOA`QmVzCL@8)aQFS~Eg< z^mc%>O@d|Rza|uZ|f-^>&@CUOZnB$b2&J;zG zZ^>Who)Z-pz*_r2-R5QK{rSuWKl(bN!uN4}JFF}7*QmZJDe0Sd(*kT>h346lAYCA~ zu>TGagWzI96)+j}rCHvzX9kgd*|u)ZEox=2Ua$YR$>w9y*M3cg#Xvr^c0se-FXO6+ zkcfS(YEr->n*?k$4DPPg*m(S4m9$Xwc;W$CzOzbt@eN#BN#jv@^_H z;wO?vb4|#>;!#nE8fsw&TD)65l=bO2Nq*!8chASWqV3@0MGbtKTOl~S&j6%WRkGg% z>jpuk(EgVI6=MR^JYiFONofvqH_lQb*WRH?>w4rO%todv@F2JL(S;1~_Ak_Ok;$IW zZh$=G)rX*eWS5FfuhMGcnoS@tE$Ku5W@w7nWom2tA53KGh0Lmqd;c%HrFu+^^5auNSco-g!yO0c63AeXv$!D6G z$LdIoi;9>c>x9eE!SchCkMDo=SsAuEIWGaUa{t7)v;HkwPN^n2e_$u89Sy9m8zY%= zp|J%e({+nw`?rfmVi9)+x=70VmYW$gxLF(+^XTO4K9Mt@leJGpJ>F}Ks)A)eCfRG1 z?r(M+@pvc_LXm(!c24c`3}nFoQ2ul;s;}~&Gi`4l=M!?2S(XF#2HMD~9?AMAusQZ# zOFl@2D)s)C4N?-=HyMJqH%}3Z9bE#=gTN%`%u&@UX9oa2x>e<23n)igXS_ch{%i7$ z$KQ6Hp`g^oS64ty!b#r-APIPL6F`_q0O+G{E^S8}M2>mVst!(T*9ia4ju%@ypt=z% z;+=yksj2l(J`qaGH71+&C!0T{-H@BVnOpzFi<#3Km_TB9{Zgj7vdMRqPQ%g$i`)IN zY1i0tq4iroLww&CN2NtzR|4!zkBTcExTBmU(*SY=`tf?*vyjHlMTAR(V7u*PI@Kbi zE>O3QuyWJ_u-r6*RfQG!i_;HxFs{$sh0__uj1KvTVZ4wpOgsg2Dx|;r6({+ z=7m}u<#wC^0G`TK^(FWS_V>fO9>N13{~hUSb=cMiRrEo#glz)GsW*;<%}IdB41kWh z^UN_Z?Kxt?y()LDHX-er`{uFOhRm00C;pn}W{22jx)wXjoCBln)OZ@Arg$r!#dlI} z?OCp4t8CzJ(d|T}<8|EEL1l>;+6tyKZVZZ(-8GWkaoYSl^R_=Pha(u+0D&C3Xsg3g z1KAE+I;Pfc#;CJv0pYhR>NlycWSQz0}&zE zjp3L9f#m}B`BXhVlODbHyH%I~zRD%dHSmDvi<)@j<8MJ#7h6#2npBq*B&+~2oEsBK zfS)S_5CsEJ`@=``TYheJlz)Uq;9Wd~nR&}w3 zs5DI0C1Gi%W3L%Y63~9G2cSg)fE|U84Yx^F&eNi3TMLxNL_0E4wsI?3yz@~Iy`~$< zv+=8F9Fe2fQ)WpfOTH>sH=imvRoiHIQbL)eZl;>F0$`rwb_9$FpaR>YIjN^6G2bhF z8W5C`unV1N(GbbmE85rwV-J?&k^9{PsS`CBQZNAEO(Nf!+a$hP9KP;v32m+%)RT$n zAfU8uXftoecry~!@G&Ay>wQqD^a(nE5xRc!F2DclJXZwMyzCnq0k#VPNj_-SY+e*A z3IN{PW$sAvKz)BwNAbqT--1e4+QNC-DM?rmt{H$ED+4gM2C!fN?ECLEWA4>Qb4u#+ zE<2UIVy=?ZQ@fJliUkGZgtbM|=<<8j6+otz1h0hiEyqdo<8n(sOVARrz|~QDL8}{7 zE0Pr}bFOxT=FM^!>Q5c3uKNoy^(o3VW;cbqXSKT(<`~2o+LvfwTM__(;hsKg@U)Jc zLiLr}to7a$aJZ5LBbz)*1dGI|SQliuR0r-~cvgZ5ijL5a*n#UBQEkzFr6zAY{#%_=rws!!MI+n}0QoUW1E#qLkWK-R zuX`a!<za9v}5yWc66wulNEx2}-bhHBLevj^f z6F>j}jIh6cr&04i%H36D+l)rCMX#Emp=?rjo`m`D)#-XRFE5Eb;Jd!e$t-kD@8$}8 zElJqoyxUozy~}lop^1T#gHSNl%m4sBx}C(*9CH{|o*#Oxm%=;!002CoM#+9(Lf9OD zAf*oguLV-G0?CgV_otJq>81V*#Qme3U8~hUn_6oIO@MHEzn0R?dGs~iIR+$mHf9Gv zCp_Y?@W&h*@Ixc*ylSHzNl8-P%qh`7gDX1(nSKr^HwDgCr0Y{y8-fMb_)v3B>t?%%tVDuYurwMFF@}xOZWr*PWvV z*Of|@DfAPc_WjDgZ1BVFO4UIJ~|ptV6y*hV5_}Q%*yiMtr)S{Rc~fwfcRD zK?mH7M)2{Dm6ibklq&TZ04jX4{aPR`yqeDSmQJrI@|u)qmy=>{aoB`>a*p2z8E*ZP zobmbX*kuO-Tr!ct)a5zANB;hs!1dVURZN!dd!VB9^7oluK0x#DRCK~(o#T>{2TEc2 zXXr+D1^^@qbuY~SN4A45jh9y)5~Qn*Y8Oyjoz%7+EA0EPW5QKDo$FoU`rlsEbB2l9 zGj^s&Z2$lS4plI7Ce2&nq~8m0HE3wrqC``QWZck2*awrHnBjCdX|+RQ1D_=U6gpG% zW_ceiWNh03Ix;yi0MdquQKs#p{u++h$Ywp!$$p==PGtV~N)ZXS+B7nb;12`r@vtIu zLsO0~e!4)$*yGV`(TDY38`h@CS7zNkdpUpP{n{`!B?mJu4;*sq$5h}B8aU+5N(g_@ zq}-c!@9j@RZyjxWLzw_ImR}}uihUB`41f2^leOcfsQ1C0E2Hp~SWQ`fXV~01ctn~AvUXVGEXytAm1@#CmdoL@sIW-$>pTUhsfTk4ys+ZScKS zgz{E@!`fgo)tcXeJHEjAe*IrJs2o{bbxhFXS|H~=J2ke>E`#BGysl9#d9Tg}fIQ%b z1|CTibpqN4#;DMI-)IH~ZAKwH>Gj1_xRCH1#om!4Pm-DI`FGjX_Q5_k@jm&>a);Xk zTk~G(Od{DNn0i(goboet>rk2psLXjw%^(=BqkFW)LY7rem4?!4?e}&#c7uzXm0)0? z4op0^xn=x1ix=3e(T*gebR_|Cz#JL+y#4a$8i28?sw%SZBE|a$4!s(0^8GV&@bGn; ze~yG#4-99A`-cxNzm6U4o5B*MHkhlHL3rq#q3)mNt_y?ii(jG$p2JtUbf$l%aBzNT zzcwZiT+6NUA*aGS#YdF1R!)M6@k&TwAxwHi)#MZZ1 zPK9m7rDj%afyin=_=B4HvIVBH332xB`a^h~y_bBRC&avn&44AQsr^LE?-cH(N#Sv zoUP-6`Et2jE|>0Ti;Ih_FL}0-lJ?iXzj|LXH6`Qu`I)Asrlw>(KQ985lsud1t3|Yw z0+c+X0@L3=QP!7~l$5~Y;v)O>hszMTuj3+f2Z|z`?AN(P=s0N_}+H^|G4 zDZCgcp_U6vr=|ehZcG74@Ju^_0swwx+>$T@ArCzeb1dZ?I|8@04{bNKArfZtpeP&W{Fe9}xH&p-2o>YpIjfIts zg^h)slvcso#@x=q#L>jY3G~Vv0_I;=kcg-{1ON}NVU;EA_8p5+0{}Dt_(TbM6K^U7 z%1_9lbxTh8@LK9-2~AE2?Z!2VVD0&@jFiI|8vvjIUs{By@7q!qBRpofG*J%OJm&K6 zevrb2DXsD#bX-vz*%Z_iSlWz$sNhjP!T?~s2z?+6#8Q6E3`59*aKTwHp+g_pk8}q_ zy25NfM7BOse_6J@ym)!uy~6KNy!*5@VO zDR?X*uz1F3BJi*5LqG+|4q#UQrbP<)f~N^c#$riTVhvUj4v$kRoHHn4a*nf$tEkGU zfiGuW4HuIc7v~uluaC)r+P}O${tDEd4b;5}G{6n|PrCJ5xp_^0r%nn1WK-}YZh&&h z@pIRCa-jl(N+AK`SCx<=#F2yIzDpIDT9lio)qO6hvmUHs7_376+XQS==-1Hz+2*MQ z|DR;~G127zo`gR4(E&nWUG~}&_S#d5D^vD5Fu?uQa327+sgN>5w*!ZyBS)_zKR8J` ziS;MQ4qwWm{+AJ6%?esl6W}_$o%A<7cn08h<`b!KMRS_qz8}X@ zw+kDvz@^ZHG@9B5)qni{1B)WP^pW2@Yv3NC^J$h12)f|XopJi{Fv4ry{|+A^u-y!1 zaeFfSNWG$94Y9}y$l{5eqTj@4v-W}Vh$EvUq>KC&mGNluo&5gJoD={8(Eg(Mzp}qj z{)ghcxG=f_+Ug;;L5A0?v~z^_prR8^6qyx_Vg^nyiX&^cGabu$K3L}0PHWNUCn!sU z^8a}h*r=q&F~YETf1M;K*;*e9p)*Z)op2RUx;nJPtG?`R0`Qu_TS7)MK@Aa|n zKMwQHZB}NS|A*(ix(GQ>)W(N6=>O$8*|bsX@1iKA;wV4HQM)CYg{BszWbPH^BK~il z^EvECa@dcMu$_=7+R#Mv(A46FT&scdgU0`B`ftyXbf5$$u;++7Q2r0kX=f!A1$$E! zgWScxISPz}73w7Z_J0}x0NP`aW&W-sO3I9XlsW$>GpeZy{GUArO#Q^A_w z0{{xJkps}e9AZRl1T^7Uw<%$Acwlq7a07mzu_N=KkUPZ)(+K>EKek=l9(4_@}50VM$NW$k0_!gUyt>dzJ%VMWMD=;NWukDrhNF(%@&gQyBH zj5gB0Pe}FWCE&`0W#nNPg_eOk0dU|yq@1xBYzQGN05C*WMg#>WD35@)W0VJ2w+NM` zd48m;jPSq{1q`slX85Cl@(EQ&K)r+kL&96>{$s+l06^Lf0sa%AZs%}<>W3^)iA}?u+=6L<$O9RMnPn)c(|&EZ}%+Bs#CK%Y6jjPJ^k=Gl^dM)7HAl|6wJE^_LZw+Dsj%l9QT} zn#o61wT~_)A8*t&roCjqR28{7Y&EqywYe*6wM4HqCpBFSlertUk2v1iGl6T@UTe6o zoM-+xgQ*77CID164mu%B>E- z)bhgODu&`>hLWn%hhm0MhJ!}C;_~v6s>4@mW7$EE{Xrv( zX8~xipk%+XsIk%JpwWJ)&YJLh@qR1aU`NG3)yY94bB!~ZlA7~Ug6@U}cpldJUoy3C z0;{a~+R7dVzzimCc}8ss8^GPFZ3w`1Js0$X2JfQs%~HW5EiOwdE;*>Oq3urpwV@cI-x1=ljff)qj!K0Fvt_)PxvSOW1SGM8=j|$8xPTGpGM@w6_))`F;>F=n@YSk?*%6h=U zsq%4Uq$_K2ENxh~@ukhnUWFHR<7h{Lg{xR{7ED{b611%arc)iI%ciH4Bf$hC>y|&M z9w+}bb3+Tpo@v9fSK)M(-{Qc+x97DYcoHTI!K~txBfvehtr`jvEx?3SnW|$R~a(kCxl~k!<9OC)$xS_gnSW9vR{{wSGN@oQ67;pM{^kBp+gWE;-M*WkQD)e z)P{uNscJ`fK%nkv9(byJ92q*sZgoo#2s{f$aNP0NZDHj?yCD!!J|X~OU@z_=1+P1> zc=@>gW4L)(Mrh>uxL~{FV;O;Ui|hDCgbvSWM3@#7peRiT3Ph8ZqRIycxQK+{c+P4p zL6Z^G09k38qOV|$mN|o=kl#I|Wl>f$D+FH_IL#(Q1%`rY zSy!?aID$O{59sjkIzk1+zyU(I-@$Tu%+L&ncyKWMAWt2rvPB+XE)>>=3?Y>5ftVD=_(AC4~Q|F7u%|5VbpECWOCe`bJC8zLO=0!N@O`3{7S#PB*tv^U^D zuQM4uVpyVpAkc1J0N6Y^qS8FHRA7{VKw$WQJvu>4I>k|0nT{$y@pb8#(voHb^M<3! zpH{X2OW}pjubFxkH7oo9ls~N%&IoonY4ELK1ZR*kxJmb{VJU0ggfiGaag9pB4y0uX z9=atXsCL>gq86-w@Cq?)7|uDZg#@hH*a5yDD(r*4FERkw&srRSru#^{(*qJ^0%9D{44KfC!+0bsO+Mgt z$eYqJ4~22O4@4gAEZGu{XeR!W;@f3+O|R4beo#z%2fnYsd>|>U`>h^F@w~tO-Zj zWow7gU34Z5AcZCi>4w0H@%6{Faa~7I`1KosS3LjCzYQ=1KnwtJD5T`%sXS3{qETbe zV$tI;;xQAz@CATX2wzmdml7rL*Ue_ix)nD>!1`q#ls{;ME{BMKY zF7!$PfY%N3tC*-jB!41M6AKH7ot>SPYwKkBh=HA*ll5?advpG1=jL|v60OLfD@BFJ z>oDT2P!tqPOg+x90iHV%Fk9Jq22!FVnyI3>BO(U@RVJR+4+O{+zEu3a0@*uqTG&(& zxi9vRKwdtu_~ZJRsPSU#ZC2FMIhEzb$qxbPwk2^cTpd%wYd(r&F9_kmGpKA+v0Wop`iB8;_05s-N z5s`eu>qt8h(HXj=r^U4qzoIuA*RyEizk0B0qxjd}w2rkMfS`0Rp3py_s~eNg_>d!5 z6?5L{;1>4tdpwyDIMub(q3%_-QBi!cH_AQkn&o=%JVbSzeMtlW_kNVV#B`D+L;kn% zPXT9ez-=`#u75i$OVCy}8(9Mb5FWp#yFIoOQ|)n|KLwX!Aw<9$F~M;SH+(*vaN986 zx7d7Jb(e)R;`Q61=-%4*vpBtRV4v1FipKh?p*+!|=nz-L(AP#Mx*!pRDa4i)HLV=R zYJNsUCf#l9Wf`y7TDXcwB~N;LC~GYTnV7CfbV04YaZDB&^d-jTYT2q{_ko`>`_B#p zTU6bMxb{jfsyy6+Pn_Q!A|ym^Y>QXEOHhq5Z=WuCLvw!f8{AmYhCmYeB>~D;43dD0 zJMk^iW0Ek7MDPx!@>@3iW+&BjV@wsl;sf{!{yD{n(bR)nLmZrx=1;^1TA?FIX$!2R zCFT)_5Lqi-;*$C%jGYy~*U>;7M}}*eca?FwSv{2LYPrx23Zp_y3Hp6aH>oSR*AIjr zMv}Vl+BJZjWi)4E6*xWo{T%Fl?>zr(udQMqw6&}aC^!o6-%NisqyCJW&Y%5elA1xP z><3{cu`uGZCaR0kTkF~^a*m(P5x({lU8Fx@x0CIz;J^IL7!AaMw;_k5AdhYce_ubx zKtM3&T;!C0hH+=El}U z3`neiz@arJg`^W6PuX1RS#NN~0|YeOlp&W>XQY!AI0I!|e23#nz||5#NBd?`F2Tp@9XqfMBf8)H8voSpq( zN!L8;F#&Io*Y+!%O=*~8h`#}YarM1w%Rx}0F7N!3LgVjBvbBmZz&Ghv+NLVH3H<&g zu)BBaV|%1?Dg2HQHxXL>YZvm%@%~$dq0BEEef%DW0O0hT4oQ{<0lAb8SwUCpHnSlI z;+=|r5qtD#L3cG7NRfm+k@QNGouT8C<1f2 zJ{!ocN;_pz{Wy!i`>GxUyAhT4k3I(iSofDbj?f?%c*o|??Yu6IGm#uq9aHM+5gImf zYZ2!6KTEPImMyDm#Rm(14u>0CiSIZ#Icqf;{8pKO zl2f6aV7)?`GUsd(Zp;djCrass#}^17omT)OfH2hmvp&qg`TCKlJCA(XR?Qc;s%N<> z3qmqt(A&e^N5JKq)KGnc7i?}BRpZ@e_Sa?s&AggotQ2ib)Dw41N3YAYhRJ3J8DPV> zbWD>ch1M)~{hQ9nSdKz6wUVR26G1cyadL+DDTArmo97V5T9eN6z1i+`N9rxSguwzK zJ;T5Pv1XN?uDLhZ5?yAV?_g!P>lu~0cyn=Ws-^s^QX%xF%hF}(X@5b~;m}Z)sw*h& zp28mlT8^v@5el3~W5p0`VW2ABh5KDj)sxuKl7|aFr`OQOl&}jW4^TA0OS;Jk$y1|2Ui%cj%RXuF!!NH&GozMS422$O4d zn&>YBrd31(g>AJcqG|8Uo!Tgb)bprW0*7(SWQ*G#Vo?$F7MdqDr{p=$6yWN{vm}Ky z%q>OL?RI-)7ui%5e^%|IG=Tt3=`oO=7k+37E*Er<>Fq*Oy%))^w?26yMKPf`^vt{n zF4wv%eZR1q(<5_q4xbqIxI4{;z_Cy3ePp6kzvwO2jYV;=-Nu@WV3PgV?-7qu#IbUq zQX;eg0UnkXMo45^R&dObekzZUFRA6>jH6(Bg!5`b3{(FoL4R4s!AP|lKK{J~GI-fi=8EpyoJPm9o5=>@~pQ;L0Cq)9Fs^|YycY7<)a&3B1$F*>Hy;z(1R61)f4 zrv2KQPSygMclM)W8VrT2cQ65(#Uli)Hkc*-;+fg-yIVpwx&sS)&VnvSSC7B2?oBxR zrv|Hhu@j=BAB8XHEI1B_*QVD?hFg-$sKS`8AeYW&tY+(I<5qLzf|-Zxf#-Qn+G``p z3FbRbEsOI=)SvoH-6YH!!Wz^&u4APbxZE&(ky5VmK+gv_U#%A-P0T>0PAfCc2eLLv zQ#FYXzB3bpMbuLJ^vOrmT+>ClLnV)K%L+w7Z1n9tmlBQJ)Ahk+8cue7e>yXS#r=`r z*&lEgUmbzWX3jh#;CZzfpQ7IFC+1e4P=;W0xJMu=x|ZvAM%2jNlzY}U+f>v&T1C`^ zvF1q1irr?YWm|e*i53fIo9{?|(Zu(MpbyAco#~Ah(IL{J7|6ioa?f!pWSnuS^--dL z8q^O$%-N_tj&U?2G6gzOq6=E^o4-@7V+HQvC4OCQxWz_WPgen=WD{p<|%4X@SM&-z~22kDo40s9OwiBWw#j{xDinX0o{IcHGM=^MAsd;Z{kC z%`yMn)mPi<)N_)4YXkL2+2Vyu)g-H4l~-x3<(=xQDo)g5+uSH1`2knh&$p|*wo1XF z;_J;O6H0BuTo%*act7%2Pt=p!M`ht1UdE~HV2JzCBU-HuF>;l9t+_8Jl!s$qUlI#Z$|!n-$D;D z3)5N*gM7(}B&CvpAl~@|01-Ao&zq4nyEP%|G@L6npVZN6taegDSJI*RC{*v

Am_rB54*Ls^t&Mc6=W5yD5O@R@XG=a>xo5jk^(R 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 literal 0 HcmV?d00001 diff --git a/modular_skyrat/modules/sec_haul/code/guns/guns.dm b/modular_skyrat/modules/sec_haul/code/guns/guns.dm index 4c0c07501cc..72d42b45c64 100644 --- a/modular_skyrat/modules/sec_haul/code/guns/guns.dm +++ b/modular_skyrat/modules/sec_haul/code/guns/guns.dm @@ -693,7 +693,7 @@ /obj/item/gun/ballistic/shotgun/m23 name = "\improper Model 23-37" - desc = "A common outdated police shotgun sporting a six-round tube." + desc = "An outdated police shotgun sporting an eight-round tube." icon_state = "riotshotgun" inhand_icon_state = "shotgun" mag_type = /obj/item/ammo_box/magazine/internal/shot/m23 @@ -704,11 +704,11 @@ name = "m23 shotgun internal magazine" caliber = CALIBER_SHOTGUN ammo_type = /obj/item/ammo_casing/shotgun/beanbag - max_ammo = 6 + max_ammo = 8 /obj/item/gun/ballistic/shotgun/automatic/as2 name = "\improper M2 Auto-Shotgun" - desc = "An automatic shotgun with a four round internal tube." + desc = "A semi-automatic shotgun with a four-round internal tube." icon = 'modular_skyrat/modules/aesthetics/guns/icons/guns.dmi' icon_state = "as2" worn_icon = 'modular_skyrat/modules/aesthetics/guns/icons/guns_back.dmi' @@ -730,12 +730,12 @@ /obj/item/ammo_box/magazine/internal/shot/as2 name = "shotgun internal magazine" caliber = CALIBER_SHOTGUN - ammo_type = /obj/item/ammo_casing/shotgun/beanbag + ammo_type = /obj/item/ammo_casing/shotgun max_ammo = 4 /obj/item/gun/ballistic/shotgun/sas14 name = "\improper SAS-14" - desc = "A pump action shotgun with a five round box magazine." + desc = "A semi-automatic shotgun with a five-round box magazine." icon = 'modular_skyrat/modules/sec_haul/icons/guns/sas14.dmi' icon_state = "sas14" inhand_icon_state = "shotgun" @@ -752,7 +752,7 @@ weapon_weight = WEAPON_MEDIUM burst_size = 1 fire_select_modes = list(SELECT_SEMI_AUTOMATIC) - semi_auto = FALSE + semi_auto = TRUE internal_magazine = FALSE armadyne = TRUE @@ -764,3 +764,20 @@ caliber = CALIBER_14GAUGE ammo_type = /obj/item/ammo_casing/s14gauge max_ammo = 5 + +//New SAS14 mags beyond here + +/obj/item/ammo_box/magazine/sas14/empty + start_empty = TRUE + +/obj/item/ammo_box/magazine/sas14/beanbag + ammo_type = /obj/item/ammo_casing/s14gauge/beanbag + +/obj/item/ammo_box/magazine/sas14/buckshot + ammo_type = /obj/item/ammo_casing/s14gauge/buckshot + +/obj/item/ammo_box/magazine/sas14/rubbershot + ammo_type = /obj/item/ammo_casing/s14gauge/rubbershot + +/obj/item/ammo_box/magazine/sas14/stunslug + ammo_type = /obj/item/ammo_casing/s14gauge/stunslug diff --git a/modular_skyrat/modules/ticket_counter/code/counter.dm b/modular_skyrat/modules/ticket_counter/code/counter.dm index e8a6ca87cbc..a669b3b278d 100644 --- a/modular_skyrat/modules/ticket_counter/code/counter.dm +++ b/modular_skyrat/modules/ticket_counter/code/counter.dm @@ -10,13 +10,15 @@ GLOBAL_LIST_INIT(ticket_counter, list()) /datum/admin_help_tickets/stat_entry() var/list/L = ..() L[++L.len] = list(null, null, null, null) - L[++L.len] = list("Ticket statistics", null, null, null) - L[++L.len] = list("Admin:", "Tickets handled:", null, null) + L[++L.len] = list("Ticket/OPFOR statistics", null, null, null) + L[++L.len] = list("Admin:", "Tickets/OPFOR handled:", null, null) for(var/ckey in GLOB.ticket_counter) //assumption, that there's no keys with empty values L[++L.len] = list("[ckey]", "[GLOB.ticket_counter[ckey]]", null, null) + L[++L.len] = list("OPFOR:", "UNSUB: [LAZYLEN(SSopposing_force.unsubmitted_applications)] | SUB: [LAZYLEN(SSopposing_force.submitted_applications)] | APPR: [LAZYLEN(SSopposing_force.approved_applications)]", null, null) + return L /datum/admin_help diff --git a/tgstation.dme b/tgstation.dme index 84bed840408..8745fdee767 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -272,6 +272,7 @@ #include "code\__DEFINES\~skyrat_defines\mining_traits.dm" #include "code\__DEFINES\~skyrat_defines\mobs.dm" #include "code\__DEFINES\~skyrat_defines\obj_flags.dm" +#include "code\__DEFINES\~skyrat_defines\opposing_force_defines.dm" #include "code\__DEFINES\~skyrat_defines\pollution.dm" #include "code\__DEFINES\~skyrat_defines\projectiles.dm" #include "code\__DEFINES\~skyrat_defines\reskin_defines.dm" @@ -4260,6 +4261,7 @@ #include "modular_skyrat\master_files\code\datums\traits\negative.dm" #include "modular_skyrat\master_files\code\datums\traits\neutral.dm" #include "modular_skyrat\master_files\code\game\effects\spawners\random\structure.dm" +#include "modular_skyrat\master_files\code\game\gamemodes\objective.dm" #include "modular_skyrat\master_files\code\game\machinery\doors\firedoor.dm" #include "modular_skyrat\master_files\code\game\objects\items.dm" #include "modular_skyrat\master_files\code\game\objects\items\airlock_painter.dm" @@ -5121,6 +5123,13 @@ #include "modular_skyrat\modules\novaya_ert\code\uniform.dm" #include "modular_skyrat\modules\officestuff\code\officestuff.dm" #include "modular_skyrat\modules\oneclickantag\code\oneclickantag.dm" +#include "modular_skyrat\modules\opposing_force\code\admin_procs.dm" +#include "modular_skyrat\modules\opposing_force\code\items.dm" +#include "modular_skyrat\modules\opposing_force\code\mind.dm" +#include "modular_skyrat\modules\opposing_force\code\opposing_force_datum.dm" +#include "modular_skyrat\modules\opposing_force\code\opposing_force_equipment.dm" +#include "modular_skyrat\modules\opposing_force\code\opposing_force_subsystem.dm" +#include "modular_skyrat\modules\opposing_force\code\roundend.dm" #include "modular_skyrat\modules\organs\code\lungs.dm" #include "modular_skyrat\modules\oversized\code\door.dm" #include "modular_skyrat\modules\oversized\code\oversized_quirk.dm" diff --git a/tgui/packages/tgui-panel/styles/goon/chat-dark.scss b/tgui/packages/tgui-panel/styles/goon/chat-dark.scss index 761cb45491a..845a49ea33c 100644 --- a/tgui/packages/tgui-panel/styles/goon/chat-dark.scss +++ b/tgui/packages/tgui-panel/styles/goon/chat-dark.scss @@ -997,3 +997,8 @@ em { color: #ff0000; font-weight: bold; } + +.pink { + color: #ff00ff; + font-weight: bold; +} diff --git a/tgui/packages/tgui-panel/styles/goon/chat-light.scss b/tgui/packages/tgui-panel/styles/goon/chat-light.scss index 31986f469aa..f9291341392 100644 --- a/tgui/packages/tgui-panel/styles/goon/chat-light.scss +++ b/tgui/packages/tgui-panel/styles/goon/chat-light.scss @@ -953,3 +953,8 @@ h1.alert, h2.alert { color: #ff0000; font-weight: bold; } + +.pink { + color: #ff00ff; + font-weight: bold; +} diff --git a/tgui/packages/tgui/interfaces/OpposingForcePanel.js b/tgui/packages/tgui/interfaces/OpposingForcePanel.js new file mode 100644 index 00000000000..998297bd1a8 --- /dev/null +++ b/tgui/packages/tgui/interfaces/OpposingForcePanel.js @@ -0,0 +1,777 @@ +import { round } from 'common/math'; +import { useBackend, useLocalState } from '../backend'; +import { Section, Stack, TextArea, Button, Tabs, Input, Slider, NoticeBox, LabeledList, Box, Collapsible, NumberInput } from '../components'; +import { Window } from '../layouts'; + +export const OpposingForcePanel = (props, context) => { + const [tab, setTab] = useLocalState(context, 'tab', 1); + const { act, data } = useBackend(context); + const { + admin_mode, + creator_ckey, + owner_antag, + } = data; + return ( + + + + + + {admin_mode ? ( + <> + setTab(1)}> + Admin Control + + setTab(2)}> + Admin Chat + + + ) : ( + <> + setTab(1)}> + Summary + + setTab(2)}> + Equipment + + setTab(3)}> + Admin Chat + + + )} + + + + {admin_mode ? ( + <> + {tab === 1 && ( + + )} + {tab === 2 && ( + + )} + + ) : ( + <> + {tab === 1 && ( + + )} + {tab === 2 && ( + + )} + {tab === 3 && ( + + )} + + )} + + + ); +}; + +export const OpposingForceTab = (props, context) => { + const { act, data } = useBackend(context); + const { + creator_ckey, + objectives = [], + can_submit, + status, + can_request_update, + request_updates_muted, + can_edit, + backstory, + handling_admin, + blocked, + approved, + denied, + } = data; + return ( + + +

+ + +
+ + +
+