diff --git a/code/__DEFINES/nsv13.dm b/code/__DEFINES/nsv13.dm index 9e881f19f94..28d8215034a 100644 --- a/code/__DEFINES/nsv13.dm +++ b/code/__DEFINES/nsv13.dm @@ -88,4 +88,13 @@ GLOBAL_DATUM_INIT(conquest_role_handler, /datum/conquest_role_handler, new) #define NEVER_DELETE_OCCUPIED (1<<2) // Even if the overmap takes enough damage to be destroyed, never delete it if it's occupied. I don't know when we'd use this it just seems useful #define DELETE_UNOCCUPIED_ON_DEPARTURE (1<<3) // When a fighter/dropship leaves the map level for the overmap level, look for remaining occupants. If none exist, delete #define FIGHTERS_ARE_OCCUPANTS (1<<4) // Docked overmaps count as occupants when deciding whether to delete something -//NSV13 change end + +// Squads +//These names ought to be self explanatory for any XO when he assigns them. +#define DC_SQUAD "Damage Control Team" +#define MEDICAL_SQUAD "Medical Team" +#define SECURITY_SQUAD "Security Support" +#define COMBAT_AIR_PATROL "Combat Air Patrol" +#define MUNITIONS_SUPPORT "Munitions Support" +#define CIC_OPS "CIC Ops" +#define SQUAD_TYPES list(DC_SQUAD, MEDICAL_SQUAD, SECURITY_SQUAD, COMBAT_AIR_PATROL, MUNITIONS_SUPPORT, CIC_OPS) diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm index 93b2993b2c1..53303de7db9 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -19,6 +19,7 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) #define REQ_SCREEN_VIEW_MSGS 8 #define REQ_SCREEN_AUTHENTICATE 9 #define REQ_SCREEN_ANNOUNCE 10 +#define REQ_SCREEN_WRITE_SQUAD 11 //NSV13 #define REQ_EMERGENCY_SECURITY 1 #define REQ_EMERGENCY_ENGINEERING 2 @@ -68,6 +69,7 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) var/emergency //If an emergency has been called by this device. Acts as both a cooldown and lets the responder know where it the emergency was triggered from var/receive_ore_updates = FALSE //If ore redemption machines will send an update when it receives new ores. var/auth_id = "Unknown" //Will contain the name and and job of the person who verified it + var/static/list/departments_with_squads = list("bridge", "cic", "medbay", "medical", "engineering", "security", "munitions", "hangar") max_integrity = 300 armor = list("melee" = 70, "bullet" = 30, "laser" = 30, "energy" = 30, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90, "stamina" = 0) @@ -147,6 +149,8 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) dat += "Request Assistance
" dat += "Request Supplies
" + if(lowertext(department) in departments_with_squads) //NSV13 - squad messaging + dat += "Page Squad Members
" dat += "Relay Anonymous Information

" if(!emergency) @@ -219,6 +223,16 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) dat += "Announce Message
" dat += "
<< Back
" + //NSV13 - squad messaging + if(REQ_SCREEN_WRITE_SQUAD) + dat += "Message Squads

" + dat += "Message: [message]

" + dat += "
You may authenticate your message now by scanning your ID or your stamp

" + dat += "Validated by: [msgVerified ? msgVerified : "Not Validated"]
" + dat += "Stamped by: [msgStamped ? msgStamped : "Not Stamped"]

" + dat += "Send Message
" + dat += "
<< Discard Message
" + if(!dat) CRASH("No UI for src. Screen var is: [screen]") var/datum/browser/popup = new(user, "req_console", "[department] Requests Console", 450, 440) @@ -285,21 +299,29 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) if(href_list["emergency"]) if(!emergency) var/radio_freq + var/squad_type //NSV13 - squad alerts switch(text2num(href_list["emergency"])) if(REQ_EMERGENCY_SECURITY) //Security radio_freq = FREQ_SECURITY emergency = "Security" + squad_type = SECURITY_SQUAD //NSV13 - squad alerts if(REQ_EMERGENCY_ENGINEERING) //Engineering radio_freq = FREQ_ENGINEERING emergency = "Engineering" + squad_type = DC_SQUAD //NSV13 - squad alerts if(REQ_EMERGENCY_MEDICAL) //Medical radio_freq = FREQ_MEDICAL emergency = "Medical" + squad_type = MEDICAL_SQUAD //NSV13 - squad alerts if(radio_freq) Radio.set_frequency(radio_freq) Radio.talk_into(src,"[emergency] emergency in [department]!!",radio_freq) update_icon() addtimer(CALLBACK(src, .proc/clear_emergency), 5 MINUTES) + if(squad_type) //NSV13 - squad alerts + var/list/squads = GLOB.squad_manager.role_squad_map[squad_type] + for(var/datum/squad/S as() in squads) + S.broadcast(null, "[emergency] emergency in [department]!!") if(href_list["send"] && message && to_department && priority) @@ -317,6 +339,8 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) radio_freq = FREQ_SECURITY if("cargobay" || "mining") radio_freq = FREQ_SUPPLY + if("munitions") //NSV13 - added munitions + radio_freq = FREQ_MUNITIONS var/datum/signal/subspace/messaging/rc/signal = new(src, list( "sender" = department, @@ -351,6 +375,38 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) if(href_list["setSilent"]) silent = text2num(href_list["setSilent"]) ? TRUE : FALSE + //NSV13 - squad messaging + if(href_list["writeSquad"]) + var/new_message = stripped_input(usr, "Write your message:", "Awaiting Input", "", MAX_MESSAGE_LEN) + if(new_message) + message = new_message + screen = REQ_SCREEN_WRITE_SQUAD + + if(href_list["sendSquadMessage"] && message) + var/squad_type + switch(lowertext(department)) + if("bridge", "cic") + squad_type = CIC_OPS + if("munitions") + squad_type = MUNITIONS_SUPPORT + if("security") + squad_type = SECURITY_SQUAD + if("medical", "medbay") + squad_type = MEDICAL_SQUAD + if("engineering") + squad_type = DC_SQUAD + if("hangar") + squad_type = COMBAT_AIR_PATROL + + if(!squad_type) + screen = REQ_SCREEN_ERR + else + var/list/squads = GLOB.squad_manager.role_squad_map[squad_type] + for(var/datum/squad/S as() in squads) + S.broadcast(department, message) + screen = REQ_SCREEN_SENT + //NSV13 end + updateUsrDialog() /obj/machinery/requests_console/say_mod(input, list/message_mods = list()) diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 343c8664b3f..ba9b136b1ca 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -498,7 +498,9 @@ GLOBAL_LIST_INIT(cardboard_recipes, list ( \ new /datum/stack_recipe("light bulbs box", /obj/item/storage/box/lights/bulbs), \ new /datum/stack_recipe("mixed lights box", /obj/item/storage/box/lights/mixed), \ new /datum/stack_recipe("mouse traps box", /obj/item/storage/box/mousetraps), \ - new /datum/stack_recipe("candle box", /obj/item/storage/fancy/candle_box) + new /datum/stack_recipe("candle box", /obj/item/storage/fancy/candle_box), \ + null, // NSV13 - added squad kit box + new /datum/stack_recipe("squad kit box", /obj/item/storage/box/squad_kit) )), null, \ diff --git a/code/game/say.dm b/code/game/say.dm index df29611267f..391933392df 100644 --- a/code/game/say.dm +++ b/code/game/say.dm @@ -217,8 +217,6 @@ INITIALIZE_IMMEDIATE(/atom/movable/virtualspeaker) if(ishuman(M)) // Humans use their job as seen on the crew manifest. This is so the AI // can know their job even if they don't carry an ID. - var/mob/living/carbon/human/H = M - squad_rank = H.squad_rank var/datum/data/record/findjob = find_record("name", name, GLOB.data_core.general) if(findjob) job = findjob.fields["rank"] diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 5f9ac35793e..b4ea3556acf 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -7,6 +7,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/default_slot = 1 //Holder so it doesn't default to slot 1, rather the last one used var/max_save_slots = 3 + var/bad_savefile = FALSE //NSV13 - fixing some savefile stupidity + //non-preference stuff var/muted = 0 var/last_ip @@ -133,7 +135,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/action_buttons_screen_locs = list() //Nsv13 squads - we CM now - var/squad_specialisation = "Midshipman" + var/preferred_squad = "Able" //Nsv13 - Syndicate role select var/preferred_syndie_role = CONQUEST_ROLE_GRUNT @@ -251,7 +253,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "Preferred Syndicate Role: [preferred_syndie_role]
" //Nsv13 dat += "Squad Preferences:
" - dat += "Squad Specialisation: [squad_specialisation]
" //Nsv13 squads - we CM now. + dat += "Preferred GQ Squad: [preferred_squad]
" //Nsv13 squads - we CM now. dat += "" dat += "

Body

" @@ -1665,9 +1667,9 @@ GLOBAL_LIST_EMPTY(preferences_datums) //Nsv13 squads - we CM now if("squad") - var/new_spec = input(user, "Choose your preferred squad specialisation:", "Squad Setup") as null|anything in GLOB.squad_manager.specialisations + var/datum/squad/new_spec = input(user, "Choose your preferred squad:", "Squad Setup") as null|anything in GLOB.squad_manager.squads if(new_spec) - squad_specialisation = new_spec + preferred_squad = new_spec.name if("syndiecrew") var/client/C = (istype(user, /client)) ? user : user.client C.select_syndie_role() diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index b6a9be24e8e..1864a9ec1d5 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -5,7 +5,7 @@ // You do not need to raise this if you are adding new values that have sane defaults. // Only raise this value when changing the meaning/format/name/layout of an existing value // where you would want the updater procs below to run -#define SAVEFILE_VERSION_MAX 36 +#define SAVEFILE_VERSION_MAX 38 /* SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn @@ -64,7 +64,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if(n_gear) purchased_gear += n_gear if(current_version < 34) - squad_specialisation = "Midshipman" + preferred_squad = "Able" preferred_pilot_role = PILOT_COMBAT if(current_version < 35) chat_on_map = TRUE @@ -73,6 +73,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car see_rc_emotes = TRUE S.dir.Remove("overhead_chat") see_balloon_alerts = BALLOON_ALERT_ALWAYS + if(current_version < 37) + preferred_squad = "Able" + if(current_version < 38) //NSV13 - added some keybinds + key_bindings = deepCopyList(GLOB.keybinding_list_by_key) + WRITE_FILE(S["key_bindings"], key_bindings) return /datum/preferences/proc/update_character(current_version, savefile/S) @@ -145,9 +150,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if(current_version < 27) if (!(underwear in GLOB.underwear_list)) underwear = "Nude" - if(current_version < 36) //NSV13 - added some keybinds - key_bindings = deepCopyList(GLOB.keybinding_list_by_key) - WRITE_FILE(S["key_bindings"], key_bindings) /datum/preferences/proc/load_path(ckey,filename="preferences.sav") if(!ckey) @@ -189,10 +191,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car READ_FILE(S["crew_objectives"], crew_objectives) - //Nsv13 squads - we CM now - READ_FILE(S["squad_specialisation"], squad_specialisation) READ_FILE(S["preferred_syndie_role"], preferred_syndie_role) READ_FILE(S["preferred_pilot_role"], preferred_pilot_role) + //NSV13 end READ_FILE(S["default_slot"], default_slot) READ_FILE(S["chat_toggles"], chat_toggles) @@ -268,12 +269,22 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if(!equipped_gear) equipped_gear = list() + //Nsv13 squads - we CM now + try + READ_FILE(S["preferred_squad"], preferred_squad) + catch + bad_savefile = TRUE return TRUE /datum/preferences/proc/save_preferences() if(!path) return FALSE var/savefile/S = new /savefile(path) + if(bad_savefile) // NSV13 - back it up so we can restore it later, and give them a clean one in the meantime + fcopy(S, path + ".bad") + S = null + fdel(path) + S = new /savefile(path) if(!S) return FALSE S.cd = "/" @@ -326,7 +337,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["purchased_gear"], purchased_gear) WRITE_FILE(S["equipped_gear"], equipped_gear) //Nsv13 squads - we CM now - WRITE_FILE(S["squad_specialisation"], squad_specialisation) + WRITE_FILE(S["preferred_squad"], preferred_squad) WRITE_FILE(S["preferred_syndie_role"], preferred_syndie_role) WRITE_FILE(S["preferred_pilot_role"], preferred_pilot_role) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 41ec5a080b5..b81900c1ad0 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -168,7 +168,7 @@ builtInCamera.network = list("ss13") //Nsv13 for(var/stype in subtypesof(/datum/component/simple_teamchat/radio_dependent/squad)) - AddComponent(stype) + AddComponent(stype, override = TRUE) //Nsv13 end diff --git a/nsv13.dme b/nsv13.dme index 72747f6539f..45d64baf2c4 100644 --- a/nsv13.dme +++ b/nsv13.dme @@ -3546,10 +3546,6 @@ #include "nsv13\code\game\general_quarters\damage.dm" #include "nsv13\code\game\general_quarters\dropship.dm" #include "nsv13\code\game\general_quarters\dropship_types.dm" -#include "nsv13\code\game\general_quarters\squad2.dm" -#include "nsv13\code\game\general_quarters\squad_items.dm" -#include "nsv13\code\game\general_quarters\squad_management.dm" -#include "nsv13\code\game\general_quarters\squad_vendor.dm" #include "nsv13\code\game\machinery\boarding_harpoon.dm" #include "nsv13\code\game\machinery\custom_airlocks.dm" #include "nsv13\code\game\machinery\custom_machines.dm" @@ -3768,6 +3764,16 @@ #include "nsv13\code\modules\security_levels\security_levels.dm" #include "nsv13\code\modules\ship_missions\hail_computer.dm" #include "nsv13\code\modules\shuttle\computer.dm" +#include "nsv13\code\modules\squads\squad_computers.dm" +#include "nsv13\code\modules\squads\squad_datum.dm" +#include "nsv13\code\modules\squads\squad_helmets.dm" +#include "nsv13\code\modules\squads\squad_hud.dm" +#include "nsv13\code\modules\squads\squad_human.dm" +#include "nsv13\code\modules\squads\squad_items.dm" +#include "nsv13\code\modules\squads\squad_jobs.dm" +#include "nsv13\code\modules\squads\squad_lead_finder.dm" +#include "nsv13\code\modules\squads\squad_manager.dm" +#include "nsv13\code\modules\squads\squad_vendor.dm" #include "nsv13\code\modules\turbolift\lazylift.dm" #include "nsv13\code\modules\turbolift\turbolift.dm" #include "nsv13\code\modules\uplink\uplink_items.dm" diff --git a/nsv13/code/controllers/subsystem/ranks.dm b/nsv13/code/controllers/subsystem/ranks.dm index 8b40d48e41d..9fde19fe220 100644 --- a/nsv13/code/controllers/subsystem/ranks.dm +++ b/nsv13/code/controllers/subsystem/ranks.dm @@ -112,10 +112,7 @@ Checks two text ranks, see which one outranks the other. Used for squad rank ass if (istype(speaker, /mob/living/carbon/human)) var/mob/living/carbon/human/speakerMob = speaker //Squads can override our ranks to be beyond our station. - if(speakerMob.squad_rank) - rank = "[speakerMob.squad_rank] " - else - job = speakerMob.get_assignment("", "") + job = speakerMob.get_assignment("", "") //Or it's radiocode jank shitcode. else if (istype(speaker, /atom/movable/virtualspeaker)) var/atom/movable/virtualspeaker/VS = speaker diff --git a/nsv13/code/game/general_quarters/squad.dm b/nsv13/code/game/general_quarters/squad.dm deleted file mode 100644 index 6802a0f1615..00000000000 --- a/nsv13/code/game/general_quarters/squad.dm +++ /dev/null @@ -1,245 +0,0 @@ -GLOBAL_LIST_INIT(squad_styling, list(list("Apples Squad","#C73232", 5), list("Butter Squad" , "#CFB52B", 5), list("Charlie Squad" , "#AE4CCD", 5), list("Duff Squad" , "#5998FF", INFINITY))) -GLOBAL_DATUM_INIT(squad_manager, /datum/squad_manager, new) -//"Enum" that lets you define squads. Format: Name, colour theming. - -#define RADIO_SQUAD "squadcomm" -#define FREQ_SQUAD 1452 - -//These names ought to be self explanatory for any XO when he assigns them. -#define DC_SQUAD "Damage Control Team" -#define MEDICAL_SQUAD "Medical Team" -#define SECURITY_SQUAD "Security Fireteam" -#define COMBAT_AIR_PATROL "Combat Air Patrol" -#define MUNITIONS_SUPPORT "Munitions Support" -#define CIC_OPS "CIC Ops" -#define SQUAD_TYPES list(DC_SQUAD, MEDICAL_SQUAD, SECURITY_SQUAD, COMBAT_AIR_PATROL, MUNITIONS_SUPPORT, CIC_OPS) - -/datum/squad_manager - var/name = "Squad Manager" - var/list/squads = list() - -/datum/squad_manager/New() - . = ..() - for(var/I = 1; I <= GLOB.squad_styling.len; I++){ - var/datum/squad/S = new /datum/squad() - S.name = "[GLOB.squad_styling[I][1]]" - S.colour = GLOB.squad_styling[I][2] - S.max_members = GLOB.squad_styling[I][3] - squads += S - S.generate_channel() - } - addtimer(CALLBACK(src, .proc/check_squad_assignments), 5 MINUTES) //Kick off a timer to check if we're on nightmare world lowpop and need to finagle some people into jobs. Ensure people have a chance to join. - -///Method which runs just slightly after roundstart, and ensures that the ship has at least its BASIC roles filled -/datum/squad_manager/proc/check_squad_assignments() - for(var/rank in list("Bridge Staff", "Munitions Technician")) - var/datum/job/job = SSjob.GetJob(rank) - if(!job) - message_admins("No [rank] in SSjob]") - continue - if(!job.current_positions) //Unstaffed crucial job! I count MT and BS as ESSENTIAL for ship operation, so if you have none, the game needs to step in and fix your problem for you. This is so that the ship can always keep moving, even if all the crew try and go meme roles like clown (fight me) - var/list/possible = list() - for(var/datum/squad/S in squads) - if(S.members.len && S.squad_type == DC_SQUAD) //Unassigned DC squads with members are preferred. Otherwise, set up any random squad for when people join it. - possible += S - if(!possible.len) //Second run: If no squads are populated, we'll want to set up a squad for later. - for(var/datum/squad/S in squads) - if(S.squad_type == DC_SQUAD) //If we just re-assigned a squad, don't re-re-assign it because that would be stupid. - possible += S - var/datum/squad/victim = pick(possible) - var/required = DC_SQUAD //Foo. - required = (rank == "Bridge Staff") ? CIC_OPS : MUNITIONS_SUPPORT - victim.retask(required) - minor_announce("[victim] has been retasked as a [required] due to staffing issues", "WhiteRapids Bureaucratic Corps") - -/datum/squad/New() - . = ..() - radio_connection = SSradio.add_object(src, FREQ_SQUAD , RADIO_SQUAD) - -/datum/squad_manager/proc/get_squad(name) - for(var/datum/squad/S in squads){ - if(S.name == name){ - return S - } - } - -/datum/squad_manager/proc/get_joinable_squad() - for(var/datum/squad/S in squads){ - if(S.members.len && S.members.len >= S.max_members){ - continue - } - else{ - return S - } - } - -/datum/squad - var/name = "Squad" - var/orders = "No standing orders" - var/squad_type = DC_SQUAD - var/list/members = list() - var/max_members = 5 - var/mob/living/carbon/human/leader = null - var/colour = null - var/blurb = "
During General Quarters you must find a squad vendor, gear up, then report to your squad leader for orders.
\ - As a damage control party member you are responsible for repairing the ship and ensuring that breaches are sealed, debris is cleared from the halls, and injured people are taken to the medical bay.
\ - Although your assigned duty is damage control, you must listen to your squad leader, as they may receive orders to redirect your squad to another essential duty
\ - Squad vendors open up during General Quarters, and allow you to acquire a kit containing tarpaulins for closing breaches, basic tools, metal foam and a distinctive uniform to tell your squad members apart.
" - var/datum/radio_frequency/radio_connection - var/static/list/blacklist = list(/datum/job/captain, /datum/job/hop, /datum/job/chief_engineer, /datum/job/cargo_tech,/datum/job/mining, /datum/job/qm, /datum/job/ai, /datum/job/cyborg, /datum/job/munitions_tech, /datum/job/pilot, /datum/job/master_at_arms, /datum/job/rd, /datum/job/air_traffic_controller, /datum/job/warden, /datum/job/hos, /datum/job/officer, /datum/job/chief_engineer, /datum/job/bridge) - var/list/access = list() - var/datum/component/simple_teamchat/radio_dependent/squad/squad_channel = null - var/squad_channel_type - -/datum/squad/proc/generate_channel() - var/stripped = replacetext(name, " Squad", "") - squad_channel_type = text2path("/datum/component/simple_teamchat/radio_dependent/squad/[stripped]") //This is OOP sin. - squad_channel = AddComponent(squad_channel_type) - squad_channel.squad = src - -/datum/squad/proc/get_squad_channel() - return squad_channel_type - -/datum/squad/proc/broadcast(mob/living/carbon/human/sender, message, list/sounds) - squad_channel.send_message(sender, message, sounds) - //msg = "\[[name][isLead ? " [isLead]\]" : "\]"] [display_name] says, \"[msg]\"" - -/mob/living/carbon/human - var/datum/squad/squad = null - -/datum/squad/proc/set_leader(mob/living/carbon/human/H) - leader = H - to_chat(H, "You are the squad leader of [name]!. You have authority over the members of this squadron, and may direct them as you see fit. In general, you should use your squad members to help you repair damaged areas during general quarters") - broadcast(src,"[leader.name] has been assigned to your squad as leader.", list('nsv13/sound/effects/notice2.ogg')) //Change order of this when done testing. - for(var/mob/M in members) - if(M == H) - return - src += H - -/datum/squad/proc/unset_leader(mob/living/carbon/human/H) - if(!leader || (H && H != leader)) - return - if(!H && leader) - H = leader - to_chat(H, "You have been demoted from your position as [name] Lead.") - broadcast(src,"[H] has been demoted from squad lead.", list('nsv13/sound/effects/notice2.ogg')) - leader = null - -/datum/squad/proc/set_orders(orders) - broadcast(src,"New standing orders received: [orders].", list('nsv13/sound/effects/notice2.ogg')) - src.orders = orders - -/datum/squad/proc/retask(task) - if(squad_type == task) - return - squad_type = task - broadcast(src, "ATTENTION: Your squad has been re-assigned as a [squad_type]. Report to squad vendors to obtain your new equipment.", list('nsv13/sound/effects/notice2.ogg')) - switch(squad_type) - if(DC_SQUAD) - blurb = "
During General Quarters you must find a squad vendor, gear up, then report to your squad leader for orders.
\ - As a damage control party member you are responsible for repairing the ship and ensuring that breaches are sealed, debris is cleared from the halls, and injured people are taken to the medical bay.
\ - Although your assigned duty is damage control, you must listen to your squad leader, as they may receive orders to redirect your squad to another essential duty
\ - Squad vendors open up during General Quarters, and allow you to acquire a kit containing tarpaulins for closing breaches, basic tools, metal foam and a distinctive uniform to tell your squad members apart.
" - if(MEDICAL_SQUAD) - blurb = "
During General Quarters you must find a squad vendor, gear up, then report to your squad leader for orders.
\ - As a medical team member you are responsible for providing basic field first-aid to injured crewmen. Once the patient is out of critical condition, bring them to the medical bay.
\ - Although your assigned duty is medical aid, you must listen to your squad leader, as they may receive orders to redirect your squad to another essential duty
\ - Squad vendors open up during General Quarters, and allow you to acquire a kit containing tarpaulins for closing breaches, basic tools, metal foam and a distinctive uniform to tell your squad members apart.
" - if(SECURITY_SQUAD) - blurb = "
During General Quarters you must find a squad vendor, gear up, then report to your squad leader for orders.
\ - As a security fireteam member you are responsible for assisting security in repelling boarders, or by partaking in boarding action.
\ - You must listen to your squad leader, as they may receive orders to redirect your squad to another essential duty.
\ - Squad vendors open up during General Quarters, and allow you to acquire a kit containing tarpaulins for closing breaches, basic tools, metal foam and a distinctive uniform to tell your squad members apart.
" - if(COMBAT_AIR_PATROL) - blurb = "
During General Quarters you must find a squad vendor, gear up, then report to your squad leader for orders.
\ - As a member of theauxiliary combat air patrol you are responsible for manning any available fighters. If all the fighters are manned by pilots, report to the XO for re-assignment.
\ - You must listen to your squad leader, as they may receive orders to redirect your squad to another essential duty.
\ - Squad vendors open up during General Quarters.
" - access = list(ACCESS_FIGHTER, ACCESS_MUNITIONS) //They'll need to access the fighter bay, which is usually through munitions. - if(MUNITIONS_SUPPORT) - blurb = "
During General Quarters you must find a squad vendor, gear up, then report to your squad leader for orders.
\ - As a member of themunitions support crew you are responsible aiding the munitions technicians with firing the guns. If there are no munitions techs, then your squad must assume command of the weapons bay and ensure the guns are firing.
\ - You must listen to your squad leader, as they may receive orders to redirect your squad to another essential duty.
\ - Squad vendors open up during General Quarters.
" - access = list(ACCESS_MUNITIONS, ACCESS_MUNITIONS_STORAGE) //Puce gang forever - if(CIC_OPS) //This is a dangerous squad to hand out, but very useful on lowpop. - blurb = "
During General Quarters you must find a squad vendor, gear up, then report to your squad leader for orders.
\ - As a CIC operations specialist you are responsible for manning the ship control consoles and ensuring that the ship is able to fight back against any threats. If all the bridge stations are manned by bridge crew, report to the XO for re-assignment.
\ - You must listen to your squad leader, as they may receive orders to redirect your squad to another essential duty.
\ - Squad vendors open up during General Quarters..
" - access = list(ACCESS_HEADS, ACCESS_RC_ANNOUNCE) //Should cover those lowpop no bridge crew rounds nicely. - -//Add a member to our squad. -/datum/squad/proc/operator+=(mob/living/carbon/human/H) - to_chat(H, "You have been assigned to [name]![blurb]") - members += H - var/datum/squad/oldSquad = H.squad - H.squad = src - if(!oldSquad) - var/obj/item/storage/backpack/bag = H.get_item_by_slot(ITEM_SLOT_BACK) - new /obj/item/squad_pager(bag, src) - new /obj/item/clothing/neck/squad(bag, src) - -//Remove a member from our squad. -/datum/squad/proc/operator-=(mob/living/carbon/human/H) - if(H == leader) - unset_leader(H) - members -= H - H.squad = null - -//Begin job overrides. - -/datum/job/after_spawn(mob/living/H, mob/M, latejoin = FALSE) - . = ..() - addtimer(CALLBACK(src, .proc/register_squad, H), 5 SECONDS) - -/datum/job/proc/register_squad(mob/living/H) - if(!ishuman(H)) - return //No - var/datum/squad/squad = (H.client && H.client?.prefs?.preferred_squad) ? GLOB.squad_manager.get_squad(H.client.prefs.preferred_squad) : GLOB.squad_manager.get_joinable_squad() - if(squad.members.len >= squad.max_members) //Too many people! Make a new squad and pop us in it. - squad = GLOB.squad_manager.get_joinable_squad() - for(var/path in squad.blacklist) - if(type == path) - return - if(H.client?.prefs?.be_leader) - if(!squad.leader) - squad.set_leader(H) - return - else - for(var/datum/squad/S in GLOB.squad_manager.squads) - if(!S.leader) - S.set_leader(H) - return - squad += H - -//Show relevent squad info on status panel. - -/mob/living/carbon/human/proc/get_stat_tab_squad() - var/list/tab_data = list() - - if(!squad) - tab_data["Assigned Squad"] = list( - text = "None", - type = STAT_TEXT - ) - return tab_data - - tab_data["Assigned Squad"] = list( - text = "[squad.name || "Unassigned"]", - type = STAT_TEXT - ) - tab_data["Squad Leader"] = list( - text = "[squad.leader || "None"]", - type = STAT_TEXT - ) - tab_data["Squad Type"] = list( - text = "[squad.squad_type || "Standard"]", - type = STAT_TEXT - ) - tab_data["Standing Orders"] = list( - text = "[squad.orders || "None"]", - type = STAT_TEXT - ) - - return tab_data diff --git a/nsv13/code/game/general_quarters/squad2.dm b/nsv13/code/game/general_quarters/squad2.dm deleted file mode 100644 index 5719082148e..00000000000 --- a/nsv13/code/game/general_quarters/squad2.dm +++ /dev/null @@ -1,426 +0,0 @@ -#define SQUAD_LEAD "Squad Leader" -#define SQUAD_SERGEANT "Squad Sergeant" -#define SQUAD_MARINE "Marine" -#define SQUAD_MEDIC "Squad Medic" -#define SQUAD_ENGI "Squad Engineer" -#define ALL_SQUAD_ROLES list(SQUAD_LEAD, SQUAD_MEDIC, SQUAD_ENGI, SQUAD_MARINE) - -#define ABLE_SQUAD "Able" -#define BAKER_SQUAD "Baker" -#define CHARLIE_SQUAD "Charlie" -#define DUFF_SQUAD "Duff" - -/** - -Squads, revision 2! - -Partial code used from TerraGov marine corps - -*/ - -GLOBAL_DATUM_INIT(squad_manager, /datum/squad_manager, new) - -/datum/squad_manager - var/name = "Squad Manager" - var/list/squads = list() - var/list/specialisations = ALL_SQUAD_ROLES - -/datum/squad_manager/proc/get_joinable_squad(datum/job/J) - var/list/joinable = list() - for(var/datum/squad/squad in squads) - if(!squad.hidden) - if(squad.disallowed_jobs) - if(LAZYFIND(squad.disallowed_jobs, J.type)) - continue - if(squad.allowed_jobs) - if(!(LAZYFIND(squad.allowed_jobs, J.type))) - continue - joinable += squad - return (joinable?.len) ? pick(joinable) : null - -/datum/squad_manager/New() - . = ..() - for(var/_type in subtypesof(/datum/squad)) - squads += new _type() - -/mob/living/carbon/human - var/datum/squad/squad = null - var/squad_role = null - var/squad_rank = null - -/datum/squad - var/name = "" - var/desc = "nope" - var/id = null - var/tracking_id = null // for use with SSdirection - var/colour = null //colour for helmets, etc. - var/list/access = list() //Which special access do we grant them during GQ - var/access_enabled = FALSE //Is this squad's access enabled or not? - var/hidden = FALSE //Can you join this squad by default? - - //Positions... - - var/mob/living/carbon/human/leader - - var/list/engineers = list() - var/max_engineers = 1 - - var/list/medics = list() - var/max_medics = 2 - - var/list/sergeants = list() - var/max_sergeants = 2 - - var/list/grunts = list() - - var/primary_objective = null //Text strings - var/secondary_objective = null - var/list/disallowed_jobs = list(/datum/job/captain, /datum/job/hop, /datum/job/ai, /datum/job/cyborg, /datum/job/munitions_tech, /datum/job/master_at_arms, /datum/job/pilot, /datum/job/air_traffic_controller, /datum/job/warden, /datum/job/hos, /datum/job/bridge, /datum/job/officer, /datum/job/assistant, /datum/job/doctor, /datum/job/engineer, /datum/job/chief_engineer) - var/list/allowed_jobs = null //Do you want this squad to be locked to one role? - var/datum/component/simple_teamchat/radio_dependent/squad/squad_channel = null - var/squad_channel_type - var/weapons_clearance = FALSE //Are they cleared for firearms? - -/** - Checks your access. -*/ -/datum/squad/proc/GetAccess() - return (access_enabled) ? access : list() - -/datum/squad/proc/broadcast(mob/living/carbon/human/sender, message, list/sounds) - squad_channel.send_message(sender, message, sounds) - -/datum/squad/proc/generate_channel() - var/stripped = replacetext(name, " Squad", "") - squad_channel_type = text2path("/datum/component/simple_teamchat/radio_dependent/squad/[stripped]") //This is OOP sin. - squad_channel = AddComponent(squad_channel_type) - squad_channel.squad = src - -//Joining squads, registering people to squads. - -/datum/squad/New() - . = ..() - generate_channel() - -/datum/hud/human - var/atom/movable/screen/squad_lead_finder/squad_lead_finder = null - -/datum/hud/human/New(mob/living/carbon/human/owner) - . = ..() - squad_lead_finder = new /atom/movable/screen/squad_lead_finder() - squad_lead_finder.hud = src - squad_lead_finder.alpha = 0 - squad_lead_finder.invisibility = INVISIBILITY_ABSTRACT - infodisplay += squad_lead_finder - -/atom/movable/screen/squad_lead_finder - icon = 'nsv13/icons/mob/screen_squad.dmi' - icon_state = "leadfinder" - name = "Squad Lead Locator" - desc = "Allows you to track your squad leader anywhere in the world!" - screen_loc = "EAST-1:28,CENTER-4:10" - var/datum/squad/squad = null - var/mob/user = null - var/mutable_appearance/pointer - -/atom/movable/screen/squad_lead_finder/examine(mob/user) - . = ..() - if(squad && squad.leader) - . += "Your squad leader is: [squad.leader.real_name]" - -/atom/movable/screen/squad_lead_finder/proc/set_squad(datum/squad/squad, mob/living/user) - src.squad = squad - src.user = user - pointer = mutable_appearance(src.icon, "arrow") - pointer.dir = dir - add_overlay(pointer) - START_PROCESSING(SSobj, src) - -/atom/movable/screen/squad_lead_finder/Destroy() - if(pointer) - cut_overlay(pointer) - QDEL_NULL(pointer) - STOP_PROCESSING(SSobj, src) - return ..() - -/atom/movable/screen/squad_lead_finder/process() - var/mob/SL = squad?.leader - if(!SL) - return - var/turf/Q = get_turf(SL) - var/turf/A = get_turf(user) - if(Q.z != A.z) //Different Z-level. - return - var/Qdir = get_dir(user, Q) - var/finder_icon = "arrow" //Overlay showed when adjacent to or on top of the queen! - if(squad.leader == user) - finder_icon = "youaretheleader" - pointer.dir = Qdir - pointer.icon_state = finder_icon - -/datum/squad/proc/handle_hud(mob/living/carbon/human/H, add=TRUE) - var/datum/atom_hud/HUD = GLOB.huds[DATA_HUD_SQUAD] - var/datum/hud/human/hud_used = H.hud_used - - if(add) - HUD.add_hud_to(H) - - if(hud_used && hud_used.squad_lead_finder) - hud_used.squad_lead_finder.invisibility = FALSE - hud_used.squad_lead_finder.alpha = 255 - hud_used.squad_lead_finder.set_squad(src, H) - - else - HUD.remove_hud_from(H) - if(hud_used && hud_used.squad_lead_finder) - hud_used.squad_lead_finder.invisibility = INVISIBILITY_ABSTRACT - hud_used.squad_lead_finder.alpha = 0 - //hud_used?.show_hud(hud_used?.hud_version) - // H.squad_hud_set_squad() - -/datum/squad/proc/remove_member(mob/living/carbon/human/H) - handle_hud(H, FALSE) - strip_role(H) - //If we're changing into a new squad. - if(H.squad == src) - H.squad_rank = null - H.squad = null - broadcast(src,"[H.name] has been reassigned from your squad.", list('nsv13/sound/effects/notice2.ogg')) //Change order of this when done testing. - -/datum/squad/proc/apply_squad_rank(mob/living/carbon/human/H, rank) - var/Hrank = H.compose_rank(H) - Hrank = replacetext(Hrank, " ", "") - if(!check_rank_pecking_order(Hrank, rank)) - return FALSE - H.squad_rank = rank //Promotion! Congrats. - -/** - Strips a role from the target, if it finds them in any squad subsections, removes them. -*/ -/datum/squad/proc/strip_role(mob/living/carbon/human/H) - H.squad_role = null - H.squad_rank = null - if(H == leader) - leader = null - if(LAZYFIND(engineers, H)) - engineers -= H - if(LAZYFIND(medics, H)) - medics -= H - if(LAZYFIND(sergeants, H)) - sergeants -= H - if(LAZYFIND(grunts, H)) - grunts -= H - -/datum/squad/proc/set_role(mob/living/carbon/human/H, role) - switch(role) - if(SQUAD_LEAD) - if(leader) - return FALSE - strip_role(H) - leader = H - H.squad_role = SQUAD_LEAD - apply_squad_rank(H, "LT") - if(SQUAD_MEDIC) - if(medics.len >= max_medics || LAZYFIND(medics, H)) - return FALSE - strip_role(H) - medics += H - H.squad_role = SQUAD_MEDIC - apply_squad_rank(H, "SLT") - if(SQUAD_ENGI) - if(engineers.len >= max_engineers || LAZYFIND(engineers, H)) - return FALSE - strip_role(H) - engineers += H - H.squad_role = SQUAD_ENGI - apply_squad_rank(H, "SLT") - if(SQUAD_MARINE) - if(LAZYFIND(grunts, H)) - return FALSE - strip_role(H) - grunts += H - H.squad_role = SQUAD_MARINE - apply_squad_rank(H, "PFC") - // H.squad_hud_set_squad() - broadcast(src,"[H.name] has been re-assigned to [H.squad_role].", list('nsv13/sound/effects/notice2.ogg')) //Change order of this when done testing. - - -/datum/squad/proc/add_member(mob/living/carbon/human/H, give_items=FALSE) - if(!ishuman(H)) - return FALSE - //Check for our specialisations... - var/pref = H.client?.prefs?.squad_specialisation || SQUAD_MARINE - switch(pref) - if(SQUAD_LEAD) - if(!leader) - leader = H - H.squad_role = SQUAD_LEAD - apply_squad_rank(H, "LT") //Leftenant - if(SQUAD_MEDIC) - if(medics.len < max_medics) - medics += H - H.squad_role = SQUAD_MEDIC - apply_squad_rank(H, "SLT") //Second LT - if(SQUAD_ENGI) - if(engineers.len < max_engineers) - engineers += H - H.squad_role = SQUAD_ENGI - apply_squad_rank(H, "SLT") //Second LT - //They didn't get their pref :( - if(!H.squad_role) - var/my_exp = H.client?.calc_exp_type(EXP_TYPE_CREW) || 0 - if(my_exp > 1200) - if(sergeants.len < max_sergeants) - sergeants += H - H.squad_role = SQUAD_SERGEANT - apply_squad_rank(H, "SGT") //Sergeant - //They didn't make SGT. - if(!H.squad_role) - grunts += H - H.squad_role = SQUAD_MARINE - apply_squad_rank(H, "PFC") //Private first class - equip(H, give_items) - handle_hud(H, TRUE) - - var/blurb = "As a Squad Marine you are the most Junior member of any squad and are expected only to follow the orders of your superiors... \n Sergeants, Specialists and the Squad Leader all outrank you and you are expected to follow their orders." - switch(H.squad_role) - if(SQUAD_LEAD) - blurb = "As a Squad Leader you hold the rank of Lieutenant. You have authority over your squad, and are responsible for organising the squad to complete objectives set by your superiors. You answer to the XO and HoS directly, and must carry out their orders." - if(SQUAD_MEDIC) - blurb = "As a Squad Medic you are the Squad's frontline medic and are responsible for treating the wounds of your squadmates. You answer to the Squad Sergeants, failing them, the Squad Leader directly." - if(SQUAD_ENGI) - blurb = "As a Squad Engineer you are responsible for breaching enemy ships during boarding, or repairing your own ship during GQ. You answer to the Squad Sergeants, failing them, the Squad Leader directly." - if(SQUAD_SERGEANT) - blurb = "As a Squad Sergeant, you are a seasoned veteran with command experience and thus are outranked only by the squad leader. Your experience comes with the added duty of guiding and mentoring the PFCs, however in general your duties are the same as theirs. You answer to the Squad Leader directly." - - - to_chat(H, "You are a [H.squad_role] in [name] squad! \n[desc] \n[blurb]") - - broadcast(src,"[H.name] has been assigned to your squad as [H.squad_role].", list('nsv13/sound/effects/notice2.ogg')) //Change order of this when done testing. - -/datum/atom_hud/data/human/squad_hud - hud_icons = list(SQUAD_HUD) - -/* /mob/living/carbon/human/proc/squad_hud_set_squad() - var/image/holder = hud_list[SQUAD_HUD] - var/icon/I = icon(icon, icon_state, dir) - holder.pixel_y = I.Height() - world.icon_size - if(squad && squad_role) - holder.icon_state = "squad_[squad.name]_[squad_role]" - else - holder.icon_state = "hudno_id" - if(wear_id?.GetID()) - holder.icon_state = "hud[ckey(wear_id.GetJobName())]" */ - -/datum/squad/proc/equip(mob/living/carbon/human/H, give_items) - var/datum/squad/oldSquad = H.squad - H.squad = src - oldSquad?.remove_member(H) - - //If they're a new-spawn, give them their gear. - if(give_items) - var/obj/item/storage/backpack/bag = H.get_item_by_slot(ITEM_SLOT_BACK) - new /obj/item/squad_pager(bag, src) - new /obj/item/clothing/neck/squad(bag, src) - /* - switch(H.squad_role) - if(SQUAD_LEAD) - new /obj/item/clothing/head/ship/squad/leader(bag, src) - new /obj/item/clothing/suit/ship/squad(bag, src) - return TRUE - if(SQUAD_MEDIC) - new /obj/item/clothing/under/ship/marine/medic(bag, src) - if(SQUAD_ENGI) - new /obj/item/clothing/under/ship/marine/engineer(bag, src) - new /obj/item/clothing/suit/ship/squad(bag, src) - - if(prob(75)) - new /obj/item/clothing/head/ship/squad(bag, src) - return TRUE - if(prob(25)) - new /obj/item/clothing/head/ship/squad/colouronly/cap(bag, src) - return TRUE - new /obj/item/clothing/head/ship/squad/colouronly/headband(bag, src) - return TRUE - */ - -/datum/job/after_spawn(mob/living/H, mob/M, latejoin = FALSE) - . = ..() - addtimer(CALLBACK(src, .proc/register_squad, H), 5 SECONDS) - -/datum/job/proc/register_squad(mob/living/H) - if(!ishuman(H)) - return //No - var/datum/squad/squad = GLOB.squad_manager.get_joinable_squad(src) - squad?.add_member(H, give_items=TRUE) - - -/datum/squad/able - name = ABLE_SQUAD - desc = "Able squad is the ship's marine squad. Able Squad can be activated to commandeer / loot enemy vessels, though by default they are expected to help munitions with wartime ship operation." - id = ABLE_SQUAD - colour = "#e61919" - access = list(ACCESS_HANGAR, ACCESS_BRIG, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_MAINT_TUNNELS) - allowed_jobs = list(/datum/job/assistant) - disallowed_jobs = list() - -/datum/squad/baker - name = BAKER_SQUAD - desc = "Baker squad is the ship's reservist squad. They specialise in damage control and medical care, comprised mostly of engineering and medical specialists." - id = BAKER_SQUAD - colour = "#4148c8" - access = list(ACCESS_MUNITIONS, ACCESS_MEDICAL, ACCESS_MAINT_TUNNELS, ACCESS_ENGINE, ACCESS_EXTERNAL_AIRLOCKS) - max_engineers = 4 - max_medics = 4 - -//Backup squads for the XO to use. - -/datum/squad/charlie - name = CHARLIE_SQUAD - desc = "Charlie squad is the ship's secondary marine squad. They are usually activated during highly complex boarding operations when Able becomes overcrowded." - id = CHARLIE_SQUAD - colour = "#ffc32d" - access = list(ACCESS_HANGAR, ACCESS_BRIG, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_MAINT_TUNNELS) - hidden = TRUE - -/datum/squad/duff - name = DUFF_SQUAD - desc = "Duff squad is comprised of conscripts and deserters. While they're a band of rogues, they can be useful when munitions is understaffed. Give them access to weapons at your own risk." - id = DUFF_SQUAD - colour = "#c864c8" - access = list(ACCESS_MUNITIONS, ACCESS_MEDICAL, ACCESS_MAINT_TUNNELS, ACCESS_ENGINE, ACCESS_EXTERNAL_AIRLOCKS) - hidden = TRUE - -//Show relevent squad info on status panel. - -/mob/living/carbon/human/proc/get_stat_tab_squad() - var/list/tab_data = list() - - if(!squad) - tab_data["Assigned Squad"] = list( - text = "None", - type = STAT_TEXT - ) - return tab_data - - tab_data["Assigned Squad"] = list( - text = "[squad.name || "Unassigned"]", - type = STAT_TEXT - ) - tab_data["Squad Leader"] = list( - text = "[squad.leader || "None"]", - type = STAT_TEXT - ) - tab_data["Primary Objective"] = list( - text = "[squad.primary_objective || "None"]", - type = STAT_TEXT - ) - tab_data["Secondary Objective"] = list( - text = "[squad.secondary_objective || "None"]", - type = STAT_TEXT - ) - return tab_data - -/obj/machinery/computer/security/telescreen/squadcam - name = "Squad Helmet Cam Monitor" - network = list("squad_headcam") diff --git a/nsv13/code/modules/antagonists/simple_teamchat.dm b/nsv13/code/modules/antagonists/simple_teamchat.dm index 1dcbec9999d..33fbec4d4cb 100644 --- a/nsv13/code/modules/antagonists/simple_teamchat.dm +++ b/nsv13/code/modules/antagonists/simple_teamchat.dm @@ -43,10 +43,13 @@ GLOBAL_LIST_EMPTY(simple_teamchats) var/icon_icon = 'nsv13/icons/mob/actions/actions_teamchat.dmi' var/button_icon_state = null //The button's icon_state var/background_icon_state = null - var/list/sound_on_send = null //Play a sound when they're messaging this channel? - var/list/sound_on_receipt = null //Play a sound when a message is received by someone? (WARNING: MAY GET ANNOYING) - var/telepathic = TRUE //Should the user speak their message when they enter it? Or if youre mimicking radio, can it be heard "in your head" or over a comm. + var/max_message_length = MAX_MESSAGE_LEN + var/list/sound_on_send = null /// Play a sound when they're messaging this channel? + var/list/sound_on_receipt = null /// Play a sound when a message is received by someone? (WARNING: MAY GET ANNOYING) + var/list/sound_on_failure = null /// Play a sound when a message cannot be received + var/telepathic = TRUE /// Should the user speak their message when they enter it? Or if youre mimicking radio, can it be heard "in your head" or over a comm. var/text_span_style = "boldnotice" + var/last_message = "No new messages." /datum/component/simple_teamchat/proc/get_user() RETURN_TYPE(/mob/living) @@ -85,7 +88,7 @@ GLOBAL_LIST_EMPTY(simple_teamchats) qdel(chatAction) /datum/component/simple_teamchat/proc/finalise_chat() - LAZYADD(GLOB.simple_teamchats[key], src) + LAZYOR(GLOB.simple_teamchats[key], src) //For "radios". You keep /datum/component/simple_teamchat/proc/on_equip(datum/source, mob/equipper, slot) @@ -93,7 +96,11 @@ GLOBAL_LIST_EMPTY(simple_teamchats) if(slot && slot == ITEM_SLOT_BACKPACK) on_drop(source, equipper) return - chatAction.Grant(equipper) + if(has_send_permission(source, equipper)) + chatAction.Grant(equipper) + +/datum/component/simple_teamchat/proc/has_send_permission(datum/source, mob/equipper) + return TRUE /datum/component/simple_teamchat/proc/on_drop(datum/source, mob/user) chatAction.Remove(user) @@ -120,9 +127,13 @@ GLOBAL_LIST_EMPTY(simple_teamchats) /datum/component/simple_teamchat/proc/enter_message(datum/user) if(!can_message()) return FALSE - var/str = stripped_input(user,"Enter a message:", "[key]", "", MAX_MESSAGE_LEN) + var/str = input(user, "Enter a message:", "[key]", null) as text|null if(!str) return FALSE + if(length(str) > max_message_length) + to_chat(user, "Your message \"[str]\" of [length(str)] characters exceeded maximum length of [max_message_length].") + return FALSE + str = copytext(html_encode(str), 1, max_message_length) log_say("[key]: [user] transmitted: [str]") send_message(user, str) @@ -141,27 +152,36 @@ GLOBAL_LIST_EMPTY(simple_teamchats) /datum/component/simple_teamchat/proc/receive_message(atom/movable/sender, text, list/receipt_sound_override) + if(length(text) > max_message_length) + text = copytext(text, 1, max_message_length) + text = style_message(sender, text) + last_message = text + var/mob/user = get_user() if(!isliving(user)) return FALSE - text = style_message(sender, text) if(!receipt_sound_override) receipt_sound_override = sound_on_receipt if(receipt_sound_override && isatom(user)) playsound(user.loc, pick(receipt_sound_override), 100, 1) if(telepathic) to_chat(user, text) - else + else if(isliving(user)) //You can hear the sound coming out the radio... user.visible_message(text, \ text, null, 1) + return TRUE + +/datum/component/simple_teamchat/proc/show_last_message(mob/user) + user.visible_message(last_message, last_message, null, 1) //Teamchat that behaves just like a radio would. /datum/component/simple_teamchat/radio_dependent telepathic = FALSE sound_on_receipt = list('sound/effects/radio1.ogg','sound/effects/radio2.ogg') + sound_on_failure = list('nsv13/sound/effects/radiostatic.ogg') /datum/component/simple_teamchat/radio_dependent/can_message() var/obj/machinery/telecomms/relay/ourBroadcaster = null @@ -176,13 +196,41 @@ GLOBAL_LIST_EMPTY(simple_teamchats) if(ourBroadcaster && ourBroadcaster.on) return TRUE //Play a static sound to signify that it failed. - if(isatom(get_user())) - playsound(get_user().loc, 'nsv13/sound/effects/radiostatic.ogg', 100, FALSE) + if(isatom(get_user()) && length(sound_on_failure)) + playsound(get_user().loc, pick(sound_on_failure), 100, FALSE) return FALSE /datum/component/simple_teamchat/radio_dependent/squad var/datum/squad/squad = null dupe_mode = COMPONENT_DUPE_ALLOWED //For the global squad pager. + telepathic = TRUE // Not really but it *is* text-based + sound_on_receipt = list('sound/machines/twobeep.ogg') + sound_on_failure = null + max_message_length = 120 // It's a pager, the screen's not that big + var/override_send_permission = FALSE //For AI and global pagers + +/datum/component/simple_teamchat/radio_dependent/squad/Initialize(override = FALSE) + . = ..() + if(override) + override_send_permission = TRUE + +/datum/component/simple_teamchat/radio_dependent/squad/has_send_permission(datum/source, mob/equipper) + if(override_send_permission || (squad && equipper && (squad.leader == equipper))) + return TRUE + return FALSE + +/datum/component/simple_teamchat/radio_dependent/squad/proc/recursive_get_loc(atom/movable/thing) + if(!istype(thing)) + return + if(isliving(thing.loc) || isturf(thing.loc)) + return thing + return recursive_get_loc(thing.loc) + +/datum/component/simple_teamchat/radio_dependent/squad/receive_message(atom/movable/sender, text, list/receipt_sound_override) + . = ..() + if(!.) + var/atom/movable/container = recursive_get_loc(parent) + container?.balloon_alert_to_viewers("[container] buzzes.") /datum/component/simple_teamchat/radio_dependent/squad/Able name = "Able Squad" @@ -210,12 +258,9 @@ GLOBAL_LIST_EMPTY(simple_teamchats) /datum/component/simple_teamchat/radio_dependent/squad/style_message(atom/movable/sender, msg) if(isatom(sender)) - return "([key]) [sender.compose_rank(sender)][sender] ([sender == squad?.leader ? "SL" : "Midshipman"]) says, \"[msg]\"" + return "([key]) [sender.compose_rank(sender)][sender][sender == squad?.leader ? " (SL)" : ""]: [msg]" return "([key]) [sender] (Overwatch): [msg]" -//datum/component/simple_teamchat/radio_dependent/squad/style_message(atom/movable/sender, msg) - //return "([key]) [sender.compose_rank(sender)][sender == squad.leader ? " (SL) " : ""]: [msg]" - /datum/component/simple_teamchat/bloodling background_icon_state = "bg_changeling" button_icon_state = "bloodling" diff --git a/nsv13/code/modules/clothing/custom_outfits.dm b/nsv13/code/modules/clothing/custom_outfits.dm index 4ea46e2a378..5717967e3bb 100644 --- a/nsv13/code/modules/clothing/custom_outfits.dm +++ b/nsv13/code/modules/clothing/custom_outfits.dm @@ -139,10 +139,6 @@ id = /obj/item/card/id var/rank_title = "Admiral" -/datum/outfit/centcom_admiral/pre_equip(mob/living/carbon/human/H, visualsOnly) - . = ..() - H.squad_rank = rank_title - /datum/outfit/centcom_admiral/fleet name = "Admiral (Fleet)" uniform = /obj/item/clothing/under/ship/officer/admiral/fleet diff --git a/nsv13/code/game/general_quarters/squad_management.dm b/nsv13/code/modules/squads/squad_computers.dm similarity index 61% rename from nsv13/code/game/general_quarters/squad_management.dm rename to nsv13/code/modules/squads/squad_computers.dm index 20f21aeeb2d..f5c9370929f 100644 --- a/nsv13/code/game/general_quarters/squad_management.dm +++ b/nsv13/code/modules/squads/squad_computers.dm @@ -21,48 +21,25 @@ var/list/squads_info = list() for(var/datum/squad/S in GLOB.squad_manager.squads) var/list/squad_info = list() - squad_info["squad_leader_name"] = (S.leader) ? compose_rank(S.leader)+S.leader?.name : "Unassigned" + squad_info["squad_leader_name"] = "[(S.leader) ? "[compose_rank(S.leader)] [S.leader.name]" : "Unassigned"]" squad_info["squad_leader_id"] = S.leader ? "\ref[S.leader]" : null squad_info["hidden"] = S.hidden squad_info["weapons_clearance"] = S.weapons_clearance squad_info["desc"] = S.desc squad_info["name"] = S.name + squad_info["role"] = S.role squad_info["primary_objective"] = S.primary_objective squad_info["secondary_objective"] = S.secondary_objective squad_info["access_enabled"] = S.access_enabled squad_info["id"] = "\ref[S]" - //Get info about SGTs... - var/list/sergeants_info = list() - for(var/mob/living/M in S.sergeants) - var/list/sergeant_info = list() - sergeant_info["name"] = compose_rank(M)+M.real_name - sergeant_info["id"] = "\ref[M]" - sergeants_info[++sergeants_info.len] = sergeant_info - squad_info["sergeants"] = sergeants_info - //Get info about engis... - var/list/engineers = list() - for(var/mob/living/M in S.engineers) - var/list/engineer_info = list() - engineer_info["name"] = compose_rank(M)+M.real_name - engineer_info["id"] = "\ref[M]" - engineers[++engineers.len] = engineer_info - squad_info["engineers"] = engineers - //Get info about medics... - var/list/medics = list() - for(var/mob/living/M in S.medics) - var/list/medic_info = list() - medic_info["name"] = compose_rank(M)+M.real_name - medic_info["id"] = "\ref[M]" - medics[++medics.len] = medic_info - squad_info["medics"] = medics - //Get info about grunts... - var/list/grunts = list() - for(var/mob/living/M in S.grunts) - var/list/grunt_info = list() - grunt_info["name"] = compose_rank(M)+M.real_name - grunt_info["id"] = "\ref[M]" - grunts[++grunts.len] = grunt_info - squad_info["grunts"] = grunts + //Get info about members... + var/list/members_info = list() + for(var/mob/living/M in S.members) + var/list/member_info = list() + member_info["name"] = "[compose_rank(M)] [M.real_name]" + member_info["id"] = "\ref[M]" + members_info[++members_info.len] = member_info + squad_info["members"] = members_info squads_info[++squads_info.len] = squad_info data["squads_info"] = squads_info return data @@ -84,12 +61,14 @@ if("primary_objective") if(!S) return FALSE - var/orders = stripped_input(usr, message="Set primary objective:", max_length=MAX_BROADCAST_LEN, default=S.primary_objective) + var/orders = input(usr, "Choose squad role:", "Squad Setup") as null|anything in SQUAD_TYPES if(!orders || length(orders) <= 0) return log_say("[S]: [usr] set primary objective: [orders]") - S.primary_objective = orders - S.broadcast(S,"New Primary Objective: "+orders, list('nsv13/sound/effects/notice2.ogg')) + S.retask(orders) + for(var/mob/living/L in S.members) + to_chat(L, "[S.primary_objective]") + ui_update() if("secondary_objective") if(!S) return FALSE @@ -98,13 +77,26 @@ return log_say("[S]: [usr] set secondary objective: [orders]") S.secondary_objective = orders - S.broadcast(S,"New Secondary Objective: "+orders, list('nsv13/sound/effects/notice2.ogg')) + for(var/mob/living/L in S.members) + to_chat(L, "Secondary squad objective: [S.secondary_objective]") + ui_update() if("toggle_access") if(!S) return FALSE S.access_enabled = !S.access_enabled log_game("[S]: [usr] set squad's elevated access to [S.access_enabled]") - S.broadcast(S,"[S.access_enabled ? "Elevated squad access has been granted." : "Elevated squad access has been rescinded"]", list('nsv13/sound/effects/notice2.ogg')) + S.broadcast(S,"[S.access_enabled ? "Elevated squad access granted." : "Elevated squad access rescinded"]", list('nsv13/sound/effects/notice2.ogg')) + ui_update() + if("set_leader") + if(!M) + return FALSE + M.squad.set_leader(M) + ui_update() + if("demote_leader") + if(!M) + return FALSE + M.squad.unset_leader(M) // There is a check for whether they're the leader or not, it'll be fine + ui_update() if("transfer") if(!M) return FALSE @@ -114,22 +106,18 @@ if(M.squad) M.squad.remove_member(M) newSquad.add_member(M) - if("reassign") - if(!M) - return FALSE - var/newRole = input(usr, "Re-assign [M]:", "Squad Setup") as null|anything in GLOB.squad_manager.specialisations - if(newRole) - log_game("[M.squad]: [usr] reassigned [M] to [newRole]") - M.squad.set_role(M, newRole) + ui_update() if("toggle_hidden") if(!S) return FALSE S.hidden = !S.hidden + ui_update() //WE HAVE YOU SURROUNDED, SURRENDER YOUR NERF GUNS if("toggle_beararms") if(!S) return FALSE S.weapons_clearance = !S.weapons_clearance + ui_update() if("print_pass") if(!S || world.time < next_major_action) return FALSE @@ -147,7 +135,7 @@ program_icon_state = "ntnrc_idle" extended_desc = "A program to allow you to manage the ship's squads while on the go!" requires_ntnet = TRUE - transfer_access = ACCESS_HEADS + transfer_access = list(ACCESS_CAPTAIN, ACCESS_HOP) network_destination = "squad management" size = 2 tgui_id = "NtosSquadManager" @@ -158,48 +146,25 @@ var/list/squads_info = list() for(var/datum/squad/S in GLOB.squad_manager.squads) var/list/squad_info = list() - squad_info["squad_leader_name"] = (S.leader) ? S.leader.compose_rank(S.leader)+S.leader?.name : "Unassigned" + squad_info["squad_leader_name"] = "[(S.leader) ? "[S.leader.compose_rank()] [S.leader.name]" : "Unassigned"]" squad_info["squad_leader_id"] = S.leader ? "\ref[S.leader]" : null squad_info["hidden"] = S.hidden squad_info["weapons_clearance"] = S.weapons_clearance squad_info["desc"] = S.desc squad_info["name"] = S.name + squad_info["role"] = S.role squad_info["primary_objective"] = S.primary_objective squad_info["secondary_objective"] = S.secondary_objective squad_info["access_enabled"] = S.access_enabled squad_info["id"] = "\ref[S]" - //Get info about SGTs... - var/list/sergeants_info = list() - for(var/mob/living/M in S.sergeants) - var/list/sergeant_info = list() - sergeant_info["name"] = M.compose_rank(M)+M.real_name - sergeant_info["id"] = "\ref[M]" - sergeants_info[++sergeants_info.len] = sergeant_info - squad_info["sergeants"] = sergeants_info - //Get info about engis... - var/list/engineers = list() - for(var/mob/living/M in S.engineers) - var/list/engineer_info = list() - engineer_info["name"] = M.compose_rank(M)+M.real_name - engineer_info["id"] = "\ref[M]" - engineers[++engineers.len] = engineer_info - squad_info["engineers"] = engineers - //Get info about medics... - var/list/medics = list() - for(var/mob/living/M in S.medics) - var/list/medic_info = list() - medic_info["name"] = M.compose_rank(M)+M.real_name - medic_info["id"] = "\ref[M]" - medics[++medics.len] = medic_info - squad_info["medics"] = medics - //Get info about grunts... - var/list/grunts = list() - for(var/mob/living/M in S.grunts) - var/list/grunt_info = list() - grunt_info["name"] = M.compose_rank(M)+M.real_name - grunt_info["id"] = "\ref[M]" - grunts[++grunts.len] = grunt_info - squad_info["grunts"] = grunts + //Get info about members... + var/list/members_info = list() + for(var/mob/living/M in S.members) + var/list/member_info = list() + member_info["name"] = "[M.compose_rank()] [M.real_name]" + member_info["id"] = "\ref[M]" + members_info[++members_info.len] = member_info + squad_info["members"] = members_info squads_info[++squads_info.len] = squad_info data["squads_info"] = squads_info return data @@ -222,12 +187,14 @@ if("primary_objective") if(!S) return FALSE - var/orders = stripped_input(usr, message="Set primary objective:", max_length=MAX_BROADCAST_LEN, default=S.primary_objective) + var/orders = input(usr, "Choose squad role:", "Squad Setup") as null|anything in SQUAD_TYPES if(!orders || length(orders) <= 0) return log_say("[S]: [usr] set primary objective: [orders]") - S.primary_objective = orders - S.broadcast(S,"New Primary Objective: "+orders, list('nsv13/sound/effects/notice2.ogg')) + S.retask(orders) + for(var/mob/living/L in S.members) + to_chat(L, "[S.primary_objective]") + ui_update() if("secondary_objective") if(!S) return FALSE @@ -236,13 +203,26 @@ return log_say("[S]: [usr] set secondary objective: [orders]") S.secondary_objective = orders - S.broadcast(S,"New Secondary Objective: "+orders, list('nsv13/sound/effects/notice2.ogg')) + for(var/mob/living/L in S.members) + to_chat(L, "Secondary squad objective: [S.secondary_objective]") + ui_update() if("toggle_access") if(!S) return FALSE S.access_enabled = !S.access_enabled log_game("[S]: [usr] set squad's elevated access to [S.access_enabled]") - S.broadcast(S,"[S.access_enabled ? "Elevated squad access has been granted." : "Elevated squad access has been rescinded"]", list('nsv13/sound/effects/notice2.ogg')) + S.broadcast(S,"[S.access_enabled ? "Elevated squad access granted." : "Elevated squad access rescinded."]", list('nsv13/sound/effects/notice2.ogg')) + ui_update() + if("set_leader") + if(!M) + return FALSE + M.squad.set_leader(M) + ui_update() + if("demote_leader") + if(!M) + return FALSE + M.squad.unset_leader(M) // There is a check for whether they're the leader or not, it'll be fine + ui_update() if("transfer") if(!M) return FALSE @@ -252,22 +232,18 @@ if(M.squad) M.squad.remove_member(M) newSquad.add_member(M) - if("reassign") - if(!M) - return FALSE - var/newRole = input(usr, "Re-assign [M]:", "Squad Setup") as null|anything in GLOB.squad_manager.specialisations - if(newRole) - log_game("[M.squad]: [usr] reassigned [M] to [newRole]") - M.squad.set_role(M, newRole) + ui_update() if("toggle_hidden") if(!S) return FALSE S.hidden = !S.hidden + ui_update() //WE HAVE YOU SURROUNDED, SURRENDER YOUR NERF GUNS if("toggle_beararms") if(!S) return FALSE S.weapons_clearance = !S.weapons_clearance + ui_update() if("print_pass") if(!S || world.time < next_major_action) return FALSE diff --git a/nsv13/code/modules/squads/squad_datum.dm b/nsv13/code/modules/squads/squad_datum.dm new file mode 100644 index 00000000000..641a5568751 --- /dev/null +++ b/nsv13/code/modules/squads/squad_datum.dm @@ -0,0 +1,184 @@ +/datum/squad + var/name = "" + var/desc = "nope" + var/role = null + var/tracking_id = null // for use with SSdirection + var/colour = null //colour for helmets, etc. + var/list/access = list() //Which special access do we grant them during GQ + var/access_enabled = FALSE //Is this squad's access enabled or not? + var/hidden = FALSE //Can you join this squad by default? + var/lowpop_retasked = FALSE //Have we already given this squad a job? Don't pull them off of it. Only used when we're filling empty jobs at roundstart. + + //Positions... + + var/mob/living/carbon/human/leader + + var/list/members = list() + var/max_members = 5 + + var/primary_objective = null //Text strings + var/secondary_objective = null + var/list/disallowed_jobs = list(/datum/job/ai, /datum/job/cyborg, \ + /datum/job/captain, /datum/job/hop, /datum/job/bridge, \ + /datum/job/master_at_arms, /datum/job/pilot, /datum/job/munitions_tech, /datum/job/air_traffic_controller, \ + /datum/job/hos, /datum/job/warden, /datum/job/officer, \ + /datum/job/cmo, /datum/job/doctor, /datum/job/emt, /datum/job/brig_phys, \ + /datum/job/chief_engineer, /datum/job/engineer, /datum/job/atmos, \ + /datum/job/assistant) + var/list/allowed_jobs = null + var/datum/component/simple_teamchat/radio_dependent/squad/squad_channel = null + var/squad_channel_type + var/weapons_clearance = FALSE //Are they cleared for firearms? + +/datum/squad/New() + . = ..() + generate_channel() + +/datum/squad/proc/generate_channel() + message_admins("/datum/component/simple_teamchat/radio_dependent/squad/[name]") + squad_channel_type = text2path("/datum/component/simple_teamchat/radio_dependent/squad/[name]") //This is OOP sin. + squad_channel = AddComponent(squad_channel_type, override = TRUE) + squad_channel.squad = src + +/datum/squad/proc/retask(task) + if(role == task) + return + LAZYREMOVEASSOC(GLOB.squad_manager.role_squad_map, role, src) + role = task + LAZYADDASSOCLIST(GLOB.squad_manager.role_squad_map, role, src) + broadcast(src, "NEW ASSIGNMENT: [role]", list('nsv13/sound/effects/notice2.ogg')) + primary_objective = GLOB.squad_manager.role_objective_map[role] + access = GLOB.squad_manager.role_access_map[role] + +/** + Checks your access. +*/ +/datum/squad/proc/GetAccess() + return (access_enabled) ? access : list() + +/datum/squad/proc/broadcast(mob/living/carbon/human/sender, message, list/sounds) + if(length(message) > squad_channel.max_message_length) + to_chat(usr, "Your message \"[message]\" of [length(message)] characters exceeded maximum length of [squad_channel.max_message_length].") + return FALSE + squad_channel.send_message(sender, message, sounds) + +//Joining squads, registering people to squads. +/datum/squad/proc/handle_hud(mob/living/carbon/human/H, add=TRUE) + var/datum/atom_hud/HUD = GLOB.huds[DATA_HUD_SQUAD] + var/datum/hud/human/hud_used = H.hud_used + + if(add) + HUD.add_hud_to(H) + + if(hud_used && hud_used.squad_lead_finder) + hud_used.squad_lead_finder.invisibility = FALSE + hud_used.squad_lead_finder.alpha = 255 + hud_used.squad_lead_finder.set_squad(src, H) + + else + HUD.remove_hud_from(H) + if(hud_used && hud_used.squad_lead_finder) + hud_used.squad_lead_finder.invisibility = INVISIBILITY_ABSTRACT + hud_used.squad_lead_finder.alpha = 0 + +/datum/squad/proc/add_member(mob/living/carbon/human/H, give_items=FALSE) + if(!ishuman(H)) + return FALSE + + members += H + + if(leader) + var/myRank = H.compose_rank() + var/theirRank = leader.compose_rank() + if(check_rank_pecking_order(myRank, theirRank)) + leader = H + else //First one in + leader = H + + equip(H, give_items) + handle_hud(H, TRUE) + + to_chat(H, "You are a member of [name] squad! \n[desc] \n[primary_objective]") + to_chat(H, "[primary_objective]") + if(secondary_objective) + to_chat(H, "[secondary_objective]") + broadcast(src,"[H.name] assigned to squad.", list('nsv13/sound/effects/notice2.ogg')) + + +/datum/squad/proc/remove_member(mob/living/carbon/human/H) + handle_hud(H, FALSE) + //If we're changing into a new squad. + if(H.squad == src) + H.squad = null + members -= H + if(leader == H) + unset_leader() + assign_leader() + broadcast(src,"[H.name] removed from squad.", list('nsv13/sound/effects/notice2.ogg')) //Change order of this when done testing. + +/datum/squad/proc/assign_leader() + //Whoever ranks highest is in charge + if(!length(members)) + return + var/mob/living/carbon/human/highest = members[1] + for(var/mob/living/carbon/human/H in members) + if(check_rank_pecking_order(H.compose_rank(), highest.compose_rank())) + highest = H + if(highest != leader) + unset_leader() + set_leader(highest) + +/datum/squad/proc/equip(mob/living/carbon/human/H, give_items) + var/datum/squad/oldSquad = H.squad + H.squad = src + oldSquad?.remove_member(H) + + //If they're a new-spawn, give them their gear. + if(give_items) + var/obj/item/storage/backpack/bag = H.get_item_by_slot(ITEM_SLOT_BACK) + new /obj/item/squad_pager(bag, src) + new /obj/item/clothing/neck/squad(bag, src) + +/datum/squad/proc/set_leader(mob/living/carbon/human/H) + if(leader && leader != H) + unset_leader() + leader = H + if(!(LAZYFIND(members, H))) + add_member(H) + to_chat(H, "You are the squad leader of [name] Squad!. You have authority over the members of this squadron, and may direct them as you see fit. In general, you should use your squad members to help you repair damaged areas during general quarters") + broadcast(src,"[leader.name] assigned as squad leader.", list('nsv13/sound/effects/notice2.ogg')) + +/datum/squad/proc/unset_leader(mob/living/carbon/human/H) + if(!leader || (H && H != leader)) + return + if(!H && leader) //No leader passed in but we need to demote the current one + H = leader + to_chat(H, "You have been demoted from your position as [name] Squad Lead.") + broadcast(src,"[H] demoted from squad lead.", list('nsv13/sound/effects/notice2.ogg')) + leader = null + +/datum/squad/able + name = "Able" + desc = "Able squad is the ship's high-alert squad. Able Squad can be activated to commandeer enemy vessels or deal with threats, though by default they are expected to help with combat repairs." + role = DC_SQUAD + colour = "#e61919" + +/datum/squad/baker + name = "Baker" + desc = "Baker squad is the ship's reservist squad. They specialise in search-and-rescue and emergency medical care." + role = MEDICAL_SQUAD + colour = "#4148c8" + +//Backup squads for the XO to use. + +/datum/squad/charlie + name = "Charlie" + desc = "Charlie squad is the ship's secondary engineering squad. They are usually activated during complex boarding operations when Able becomes overcrowded." + role = DC_SQUAD + colour = "#ffc32d" + +/datum/squad/duff + name = "Duff" + desc = "Duff squad is comprised of conscripts and deserters. While they're a band of rogues, they can be useful when munitions is understaffed. Give them access to weapons at your own risk." + role = MUNITIONS_SUPPORT + colour = "#c864c8" diff --git a/nsv13/code/modules/squads/squad_helmets.dm b/nsv13/code/modules/squads/squad_helmets.dm new file mode 100644 index 00000000000..5740613c2fc --- /dev/null +++ b/nsv13/code/modules/squads/squad_helmets.dm @@ -0,0 +1,3 @@ +/obj/machinery/computer/security/telescreen/squadcam + name = "Squad Helmet Cam Monitor" + network = list("squad_headcam") diff --git a/nsv13/code/modules/squads/squad_hud.dm b/nsv13/code/modules/squads/squad_hud.dm new file mode 100644 index 00000000000..256dfe578c2 --- /dev/null +++ b/nsv13/code/modules/squads/squad_hud.dm @@ -0,0 +1,2 @@ +/datum/atom_hud/data/human/squad_hud + hud_icons = list(SQUAD_HUD) diff --git a/nsv13/code/modules/squads/squad_human.dm b/nsv13/code/modules/squads/squad_human.dm new file mode 100644 index 00000000000..2c74c91b6de --- /dev/null +++ b/nsv13/code/modules/squads/squad_human.dm @@ -0,0 +1,31 @@ +/mob/living/carbon/human + var/datum/squad/squad = null + +//Show relevent squad info on status panel. +/mob/living/carbon/human/proc/get_stat_tab_squad() + var/list/tab_data = list() + + if(!squad) + tab_data["Assigned Squad"] = list( + text = "None", + type = STAT_TEXT + ) + return tab_data + + tab_data["Assigned Squad"] = list( + text = "[squad.name || "Unassigned"]", + type = STAT_TEXT + ) + tab_data["Squad Leader"] = list( + text = "[squad.leader || "None"]", + type = STAT_TEXT + ) + tab_data["Primary Objective"] = list( + text = "[squad.primary_objective || "None"]", + type = STAT_TEXT + ) + tab_data["Secondary Objective"] = list( + text = "[squad.secondary_objective || "None"]", + type = STAT_TEXT + ) + return tab_data diff --git a/nsv13/code/game/general_quarters/squad_items.dm b/nsv13/code/modules/squads/squad_items.dm similarity index 97% rename from nsv13/code/game/general_quarters/squad_items.dm rename to nsv13/code/modules/squads/squad_items.dm index 21dc9eccc68..09c4b13ffd2 100644 --- a/nsv13/code/game/general_quarters/squad_items.dm +++ b/nsv13/code/modules/squads/squad_items.dm @@ -76,7 +76,7 @@ . = ..() //Lets you choose any squad to message, at any time. for(var/datum/squad/S in GLOB.squad_manager.squads) - squad_channel = src.AddComponent(S.squad_channel_type) + squad_channel = AddComponent(S.squad_channel_type, override = TRUE) squad_channel.squad = squad /obj/item/squad_pager/Initialize(mapload, datum/squad/squad) @@ -85,6 +85,12 @@ return apply_squad(squad) +/obj/item/squad_pager/attack_self(mob/user) + if(!squad_channel && squad) + squad_channel = AddComponent(squad.squad_channel_type) + squad_channel.squad = squad + squad_channel.show_last_message(user) + /obj/item/squad_pager/equipped(mob/equipper, slot) . = ..() if(global_access) @@ -95,8 +101,9 @@ apply_squad(H.squad) /obj/item/squad_pager/proc/apply_squad(datum/squad/squad) - squad_channel?.RemoveComponent() - qdel(squad_channel) + if(squad_channel) + squad_channel.RemoveComponent() + QDEL_NULL(squad_channel) cut_overlays() src.squad = squad //Ahoy mr squadward! Ack ack ack. name = "[squad] pager" @@ -106,7 +113,7 @@ stripes.color = squad.colour add_overlay(new /mutable_appearance(stripes)) if(squad) - squad_channel = src.AddComponent(squad.squad_channel_type) + squad_channel = AddComponent(squad.squad_channel_type) squad_channel.squad = squad /obj/item/clothing/suit/ship/squad @@ -298,9 +305,9 @@ name = "[squad] [initial(name)]" icon_state = "hudsquad" if ( user && ishuman( user ) ) - if ( user.squad_role == SQUAD_MEDIC ) + if ( user.squad.role == MEDICAL_SQUAD ) icon_state = "hudsquad_medic" - else if ( user.squad_role == SQUAD_ENGI ) + else if ( user.squad.role == DC_SQUAD ) icon_state = "hudsquad_engineer" item_color = "hudsquad" generate_clothing_overlay(src, "[icon_state]_stripes", squad.colour) diff --git a/nsv13/code/modules/squads/squad_jobs.dm b/nsv13/code/modules/squads/squad_jobs.dm new file mode 100644 index 00000000000..11714272afa --- /dev/null +++ b/nsv13/code/modules/squads/squad_jobs.dm @@ -0,0 +1,16 @@ +/datum/job/after_spawn(mob/living/H, mob/M, latejoin = FALSE) + . = ..() + addtimer(CALLBACK(src, .proc/register_squad, H), 5 SECONDS) + +/datum/job/proc/register_squad(mob/living/H) + if(!ishuman(H)) + return //No + + var/datum/squad/squad = null + if(H.client?.prefs?.preferred_squad) + squad = GLOB.squad_manager.get_squad(H.client.prefs.preferred_squad) + if(!squad || (length(squad.members) > squad.max_members) || (LAZYFIND(squad.disallowed_jobs, type) && !LAZYFIND(squad.allowed_jobs, type))) + squad = GLOB.squad_manager.get_joinable_squad(src) + if(!squad) + return + squad.add_member(H, give_items=TRUE) diff --git a/nsv13/code/modules/squads/squad_lead_finder.dm b/nsv13/code/modules/squads/squad_lead_finder.dm new file mode 100644 index 00000000000..bde9d88b19f --- /dev/null +++ b/nsv13/code/modules/squads/squad_lead_finder.dm @@ -0,0 +1,55 @@ +/datum/hud/human + var/atom/movable/screen/squad_lead_finder/squad_lead_finder = null + +/datum/hud/human/New(mob/living/carbon/human/owner) + . = ..() + squad_lead_finder = new /atom/movable/screen/squad_lead_finder() + squad_lead_finder.hud = src + squad_lead_finder.alpha = 0 + squad_lead_finder.invisibility = INVISIBILITY_ABSTRACT + infodisplay += squad_lead_finder + +/atom/movable/screen/squad_lead_finder + icon = 'nsv13/icons/mob/screen_squad.dmi' + icon_state = "leadfinder" + name = "Squad Lead Locator" + desc = "Allows you to track your squad leader anywhere in the world!" + screen_loc = "EAST-1:28,CENTER-4:10" + var/datum/squad/squad = null + var/mob/user = null + var/mutable_appearance/pointer + +/atom/movable/screen/squad_lead_finder/examine(mob/user) + . = ..() + if(squad && squad.leader) + . += "Your squad leader is: [squad.leader.real_name]" + +/atom/movable/screen/squad_lead_finder/proc/set_squad(datum/squad/squad, mob/living/user) + src.squad = squad + src.user = user + pointer = mutable_appearance(src.icon, "arrow") + pointer.dir = dir + add_overlay(pointer) + START_PROCESSING(SSobj, src) + +/atom/movable/screen/squad_lead_finder/Destroy() + if(pointer) + cut_overlay(pointer) + QDEL_NULL(pointer) + STOP_PROCESSING(SSobj, src) + return ..() + +/atom/movable/screen/squad_lead_finder/process() + var/mob/SL = squad?.leader + if(!SL) + return + var/turf/Q = get_turf(SL) + var/turf/A = get_turf(user) + if(Q.z != A.z) //Different Z-level. + return + var/Qdir = get_dir(user, Q) + var/finder_icon = "arrow" //Overlay showed when adjacent to or on top of the queen! + if(squad.leader == user) + finder_icon = "youaretheleader" + pointer.dir = Qdir + pointer.icon_state = finder_icon diff --git a/nsv13/code/modules/squads/squad_manager.dm b/nsv13/code/modules/squads/squad_manager.dm new file mode 100644 index 00000000000..8c6cab8da6a --- /dev/null +++ b/nsv13/code/modules/squads/squad_manager.dm @@ -0,0 +1,126 @@ +GLOBAL_DATUM_INIT(squad_manager, /datum/squad_manager, new) + +/datum/squad_manager + var/name = "Squad Manager" + var/static/list/squads = list() + var/static/list/role_squad_map = list() + //Think "what do they need that squad vendors can't give them?" + //These aren't granted by default, someone has to enable access + var/static/list/role_access_map = list( + DC_SQUAD = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_ATMOSPHERICS), //Low staffing? Guess you better get the engine running + MEDICAL_SQUAD = list(ACCESS_MEDICAL, ACCESS_SURGERY), + SECURITY_SQUAD = list(ACCESS_BRIG, ACCESS_SEC_DOORS), + MUNITIONS_SUPPORT = list(ACCESS_MUNITIONS, ACCESS_MUNITIONS_STORAGE), + COMBAT_AIR_PATROL = list(ACCESS_COMBAT_PILOT, ACCESS_MUNITIONS), //Hangar is typically through munitions + CIC_OPS = list(ACCESS_HEADS, ACCESS_RC_ANNOUNCE), + ) + var/static/list/role_objective_map = list( + DC_SQUAD = "
During General Quarters report to the squad vendors to obtain your equipment.
\ + Your primary duties are to repair the ship, seal breaches, and bring injured to medbay.
\ + Listen to your squad leader, who may issue further orders.
", + MEDICAL_SQUAD = "
During General Quarters report to the squad vendors to obtain your equipment.
\ + Your primary duties are to provide first-aid to injured crewmen and bring stabilized patients to medbay.
\ + Listen to your squad leader, who may issue further orders.
", + SECURITY_SQUAD = "
During General Quarters report to the squad vendors to obtain your equipment.
\ + Your primary duties are to assist security in repelling boarders and participate in boarding actions.
\ + Listen to your squad leader, who may issue further orders.
", + COMBAT_AIR_PATROL = "
During General Quarters report to the squad vendors to obtain your equipment.
\ + Your primary duty is to man any available fighters. If all fighters are manned by pilots, report to the XO for re-assignment.
\ + Listen to your squad leader, who may issue further orders.
", + MUNITIONS_SUPPORT = "
During General Quarters report to the squad vendors to obtain your equipment.
\ + Your primary duty is to assist munitions with loading and firing the guns. If there are no munitions techs, you are acting munitions techs.
\ + Listen to your squad leader, who may issue further orders.
", + CIC_OPS = "
During General Quarters report to the squad vendors to obtain your equipment.
\ + Your primary duty is to ensure the navigation and tactical consoles are manned. If all stations are manned by bridge crew, report to the XO for re-assignment.
\ + Listen to your squad leader, who may issue further orders.
", + ) + +/datum/squad_manager/New() + . = ..() + for(var/_type in subtypesof(/datum/squad)) + var/datum/squad/squad = new _type() + squads |= squad + LAZYADDASSOCLIST(role_squad_map, squad.role, squad) + squad.retask(squad.role) + addtimer(CALLBACK(src, .proc/check_squad_assignments), 5 MINUTES) //Kick off a timer to check if we need to finagle some people into jobs. Ensure people have a chance to join. + +/datum/squad_manager/proc/get_squad(name) + for(var/datum/squad/S in squads) + if(S.name == name) + return S + +// Try to find a squad that's not already tasked that can do the job +/datum/squad_manager/proc/assign_squad(role) + var/datum/squad/assigned = role_squad_map[role] + if(assigned && length(assigned.members)) + assigned.lowpop_retasked = TRUE + assigned.access_enabled = TRUE // They won't be much help without this + return + + //Prefer DC squads by default. Make sure there are people in them and we haven't tasked them already + var/list/possible = role_squad_map[DC_SQUAD] + for(var/datum/squad/S in possible) + if(S.lowpop_retasked || !length(S.members)) + possible -= S + //Okay, is anyone left? + if(!length(possible)) + for(var/datum/squad/S in squads) + if(!S.lowpop_retasked && length(S.members)) + possible |= S + if(!length(possible)) + //Well, we did our best + return + + var/datum/squad/stuckee = pick(possible) + stuckee.retask(role) + stuckee.lowpop_retasked = TRUE + stuckee.access_enabled = TRUE // They won't be much help without this + minor_announce("[stuckee] has been retasked as a [role] due to staffing issues", "WhiteRapids Bureaucratic Corps") + +// Method which runs just slightly after roundstart, and ensures that the ship has at least its BASIC roles filled +/datum/squad_manager/proc/check_squad_assignments() + var/datum/job/job = SSjob.GetJob("Bridge Staff") + if(!istype(job)) + message_admins("Could not get Bridge Staff job datum") + else if(!job.current_positions) + assign_squad(CIC_OPS) + + job = SSjob.GetJob("Munitions Technician") + if(!istype(job)) + message_admins("Could not get Munitions Technician job datum") + else if(!job.current_positions) + assign_squad(MUNITIONS_SUPPORT) + + var/tally = 0 + job = SSjob.GetJob("Station Engineer") + if(!istype(job)) + message_admins("Could not get Station Engineer job datum") + else + tally += job.current_positions + job = SSjob.GetJob("Atmospheric Technician") + if(!istype(job)) + message_admins("Could not get Atmospheric Technician job datum") + else + tally += job.current_positions + if(!tally) + assign_squad(DC_SQUAD) + +/datum/squad_manager/proc/get_joinable_squad(datum/job/J) + var/list/joinable = list() + var/datum/squad/smallest_squad = null + var/datum/squad/least_members = 99 + for(var/datum/squad/squad in squads) + if(!squad.hidden) + if(LAZYFIND(squad.disallowed_jobs, J.type) && !LAZYFIND(squad.allowed_jobs, J.type)) + continue + joinable += squad + var/squad_size = length(squad.members) + if(least_members > squad_size) + smallest_squad = squad + least_members = squad_size + if(!length(joinable)) + return null + var/datum/squad/chosen = pick(joinable) + if(length(chosen.members) >= chosen.max_members) + return smallest_squad + return chosen diff --git a/nsv13/code/game/general_quarters/squad_vendor.dm b/nsv13/code/modules/squads/squad_vendor.dm similarity index 69% rename from nsv13/code/game/general_quarters/squad_vendor.dm rename to nsv13/code/modules/squads/squad_vendor.dm index 1c89d71f9b7..2cf8750ad5f 100644 --- a/nsv13/code/game/general_quarters/squad_vendor.dm +++ b/nsv13/code/modules/squads/squad_vendor.dm @@ -31,11 +31,19 @@ max_integrity = 500 //Tough nut to crack, due to how it'll spit out a crap load of squad gear like a goddamned pinata. resistance_flags = ACID_PROOF | FIRE_PROOF req_one_access = list(ACCESS_HOP, ACCESS_HOS) - var/static/list/loans = list() //List of mobs who have taken a kit without returning it. To get a new kit, you have to return the old one. var/static/list/loans_info = list() var/static/list/loadouts = list() var/static/list/requires_weapons_clearance = list(/obj/item/ammo_box, /obj/item/gun) +/obj/machinery/squad_vendor/Initialize() + . = ..() + if(!length(loadouts)) + for(var/instance in subtypesof(/datum/squad_loadout)) + loadouts += new instance + +/obj/machinery/squad_vendor/attackby(obj/item/I, mob/living/user, params) + return return_item(user, I) || ..() + /obj/machinery/squad_vendor/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) @@ -45,12 +53,12 @@ /obj/machinery/squad_vendor/ui_data(mob/user) var/list/data = list() data["user_name"] = (user) ? compose_rank(user)+user.name : "Unassigned" - data["already_loaned"] = (user in loans) + data["already_loaned"] = (user in loans_info) var/mob/living/carbon/human/H = user var/datum/squad/squad = ishuman(H) ? H?.squad : null var/list/kits = list() for(var/datum/squad_loadout/S in loadouts) - if(!squad || !(LAZYFIND(S.allowed_ranks, H.squad_role))) + if(!squad || !(LAZYFIND(S.allowed_roles, H.squad.role))) continue var/list/kit = list() kit["name"] = S.name @@ -63,71 +71,110 @@ /obj/machinery/squad_vendor/ui_act(action, params) if(..()) return - var/datum/squad_loadout/S = locate(params["item_id"]) + var/datum/squad_loadout/loadout = locate(params["item_id"]) var/mob/living/carbon/human/H = usr if(!istype(H) || !H.squad) return FALSE switch(action) if("vend") - if(!S) + if(!loadout) return FALSE if(!H.squad) return FALSE var/obj/item/storage/box/squad_kit/box = new(get_turf(src)) - var/loaned_amount = 0 //How much gear have we loaned them? - for(var/path in S.items) + var/list/must_return = loadout.items.Copy() + //If they don't have weapons clearance, don't expect them to return guns that they don't get vended. + if(!H.squad.weapons_clearance) + for(var/banned in requires_weapons_clearance) + for(var/path in must_return) + if(ispath(path, banned)) + must_return -= path + for(var/path in must_return) var/obj/item/I = new path(src) - if(!H.squad.weapons_clearance) - for(var/disallowed in requires_weapons_clearance) - if(istype(I, disallowed)) - qdel(I) - continue //They don't have the clearance for that one :) I.forceMove(box) - //If they don't have weapons clearance, don't expect them to return guns that they don't get vended. - if(H.squad.weapons_clearance) - loaned_amount = S.must_return.len - else - loaned_amount = S.must_return.len - requires_weapons_clearance.len playsound(src, 'sound/machines/machine_vend.ogg', 50, TRUE, extrarange = -3) - loans += H - loans_info[H] = list(S, loaned_amount) + loans_info[H] = must_return return TRUE if("return_gear") - if(!loans_info[usr]) + if(!loans_info[H]) return FALSE - var/list/L = loans_info[H] - var/datum/squad_loadout/loan = L[1] - var/loan_amount = L[2] + var/list/must_return = loans_info[H] var/obj/item/storage/backpack/bag = H.get_item_by_slot(ITEM_SLOT_BACK) - var/list/nicked = list() for(var/atom/movable/AM in bag) - if(LAZYFIND(loan.must_return, AM.type)) - nicked += AM - if(nicked.len < loan_amount) - playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0) - to_chat(H, "You still have [loan_amount - nicked.len] more item(s) to return....") + return_item(usr, AM, quiet=TRUE) // Don't spam them, we'll handle the notification ourselves + notify(H) + if(length(must_return)) return FALSE - playsound(src, 'sound/machines/terminal_insert_disc.ogg', 100, 0) - say("Items returned. Have a secure day.") - for(var/atom/movable/AM in nicked) - AM.forceMove(src) - qdel(AM) - loans -= H - loans_info[H] = null + loans_info -= H return TRUE - -/obj/machinery/squad_vendor/Initialize() - . = ..() - if(!loadouts.len) - for(var/instance in subtypesof(/datum/squad_loadout)) - loadouts += new instance + if("pay_fine") + if(!loans_info[H]) + return FALSE + var/list/must_return = loans_info[H] + var/total = length(must_return) * 300 + if(alert(usr, "You will be charged [total] credits.", "Lost Item Fine", "OK", "Cancel") == "OK") + // Why the fuck is there no proc for this + var/obj/item/card/id/C = H.get_idcard(TRUE) + if(!C) + say("No ID card found.") + return + else if (!C.registered_account) + say("No bank account found.") + return + var/datum/bank_account/account = C.registered_account + if(!account.adjust_money(-total)) + say("You do not possess the funds for this.") + return + // Success! + loans_info -= H + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 100, 0) + say("Fee processed. Have a secure day.") + ui_update() + return TRUE + +/obj/machinery/squad_vendor/proc/return_item(mob/living/user, obj/item/I, quiet=FALSE) + var/list/must_return = loans_info[user] + if(length(must_return) && LAZYFIND(must_return, I.type)) + I.forceMove(src) + LAZYREMOVE(must_return, I.type) + qdel(I) + if(!quiet) + notify(user) + if(!length(must_return)) + loans_info -= user + ui_update() + return TRUE + if(istype(I, /obj/item/storage/box/squad_kit)) + if(length(I.contents)) + for(var/obj/item/thing in I.contents) + return_item(user, thing, quiet=TRUE) + if(!quiet) + notify(user) + if(!length(I.contents)) // This is two blocks so I can only tell them about returned items if there were items to return + I.forceMove(src) + qdel(I) + if(!quiet) + say("Thank you for recycling.") + else if(!quiet) + to_chat(user, "The box must be empty to be returned.") + ui_update() + return TRUE + +/obj/machinery/squad_vendor/proc/notify(mob/living/user) + var/list/must_return = loans_info[user] + if(length(must_return)) + playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0) + to_chat(user, "You still have [length(must_return)] more item(s) to return.") + else + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 100, 0) + say("Items returned. Have a secure day.") /datum/squad_loadout var/name = "Parent" var/desc = "A standardised equipment set for Blue Phalanx marines. This set is designed for use in pressurized areas, it comes with lightweight armour to protect the wearer from most hazards." var/list/items = list(/obj/item/clothing/under/ship/marine, /obj/item/clothing/suit/ship/squad, /obj/item/clothing/head/helmet/ship/squad, /obj/item/ammo_box/magazine/glock/lethal, /obj/item/gun/ballistic/automatic/pistol/glock) - var/list/must_return = list() - var/list/allowed_ranks = list(SQUAD_MARINE, SQUAD_SERGEANT) + var/leader_only = FALSE + var/list/allowed_roles = SQUAD_TYPES /datum/squad_loadout/marine name = "Squad Marine (Standard)" @@ -137,16 +184,11 @@ desc = "For hazardous, low pressure environments. This kit contains a reinforced skinsuit which, while slow, will protect marines from the elements." items = list(/obj/item/clothing/under/ship/marine, /obj/item/clothing/suit/ship/squad/space, /obj/item/clothing/head/helmet/ship/squad/space, /obj/item/ammo_box/magazine/glock/lethal, /obj/item/gun/ballistic/automatic/pistol/glock) -/datum/squad_loadout/New() - . = ..() - if(!must_return.len) - must_return = items - /datum/squad_loadout/leader name = "Squad Leader (Standard)" desc = "For hazardous, low pressure environments. This kit contains a reinforced skinsuit which, while slow, will protect marines from the elements." items = list(/obj/item/clothing/under/ship/marine, /obj/item/megaphone, /obj/item/clothing/suit/ship/squad, /obj/item/clothing/head/helmet/ship/squad/leader, /obj/item/ammo_box/magazine/glock/lethal, /obj/item/gun/ballistic/automatic/pistol/glock) - allowed_ranks = list(SQUAD_LEAD) + leader_only = TRUE /datum/squad_loadout/leader/space name = "Squad Leader (Hazardous Environment)" @@ -157,7 +199,7 @@ name = "Squad Engineer (Standard)" desc = "This kit contains everything a squad engineer needs to effect repairs in non-hazardous environments. Recommended only for planetside operations where speed is necessary." items = list(/obj/item/clothing/under/ship/marine/engineer, /obj/item/storage/belt/utility/full, /obj/item/storage/box/damage_control, /obj/item/clothing/glasses/welding, /obj/item/clothing/suit/ship/squad, /obj/item/clothing/head/helmet/ship/squad, /obj/item/ammo_box/magazine/glock/lethal, /obj/item/gun/ballistic/automatic/pistol/glock) - allowed_ranks = list(SQUAD_ENGI) + allowed_roles = list(DC_SQUAD, MUNITIONS_SUPPORT, COMBAT_AIR_PATROL) /datum/squad_loadout/engineer/space name = "Squad Engineer (Hazardous Environment)" @@ -168,7 +210,7 @@ name = "Squad Medic (Standard)" desc = "A kit containing battlefield medical equipment and light squad armour." items = list(/obj/item/clothing/under/ship/marine/medic, /obj/item/storage/firstaid/regular, /obj/item/reagent_containers/medspray/sterilizine, /obj/item/reagent_containers/medspray/styptic, /obj/item/clothing/suit/ship/squad, /obj/item/clothing/head/helmet/ship/squad, /obj/item/ammo_box/magazine/glock/lethal, /obj/item/gun/ballistic/automatic/pistol/glock) - allowed_ranks = list(SQUAD_MEDIC) + allowed_roles = list(MEDICAL_SQUAD) /datum/squad_loadout/medic/space name = "Squad Medic (Hazardous Environment)" diff --git a/tgui/packages/tgui/interfaces/NtosSquadManager.js b/tgui/packages/tgui/interfaces/NtosSquadManager.js index 935217d7805..db9d139f998 100644 --- a/tgui/packages/tgui/interfaces/NtosSquadManager.js +++ b/tgui/packages/tgui/interfaces/NtosSquadManager.js @@ -2,7 +2,7 @@ import { Fragment } from 'inferno'; import { useBackend, useLocalState } from '../backend'; -import { Button, Section } from '../components'; +import { Box, Button, LabeledList, Section, Table } from '../components'; import { NtosWindow } from '../layouts'; export const NtosSquadManager = (props, context) => { @@ -10,30 +10,18 @@ export const NtosSquadManager = (props, context) => { return ( {Object.keys(data.squads_info).map(key => { let value = data.squads_info[key]; return ( -
-
- {Object.keys(value.engineers).map(key => { - let member = value.engineers[key]; - return ( -
-
-
- {Object.keys(value.medics).map(key => { - let member = value.medics[key]; - return ( -
-
-
- {Object.keys(value.grunts).map(key => { - let member = value.grunts[key]; - return ( -
-
-
); +
+ ); })} diff --git a/tgui/packages/tgui/interfaces/SquadManager.js b/tgui/packages/tgui/interfaces/SquadManager.js index 57b3d970603..0dc2d09a0fa 100644 --- a/tgui/packages/tgui/interfaces/SquadManager.js +++ b/tgui/packages/tgui/interfaces/SquadManager.js @@ -2,7 +2,7 @@ import { Fragment } from 'inferno'; import { useBackend, useLocalState } from '../backend'; -import { Box, Button, LabeledList, NumberInput, Section } from '../components'; +import { Box, Button, LabeledList, Section, Table } from '../components'; import { Window } from '../layouts'; export const SquadManager = (props, context) => { @@ -11,30 +11,18 @@ export const SquadManager = (props, context) => { {Object.keys(data.squads_info).map(key => { let value = data.squads_info[key]; return ( -
-
- {Object.keys(value.engineers).map(key => { - let member = value.engineers[key]; - return ( -
-
-
- {Object.keys(value.medics).map(key => { - let member = value.medics[key]; - return ( -
-
-
- {Object.keys(value.grunts).map(key => { - let member = value.grunts[key]; - return ( -
-
-
); +
+ ); })} diff --git a/tgui/packages/tgui/interfaces/SquadVendor.js b/tgui/packages/tgui/interfaces/SquadVendor.js index 1a0ecac8ce7..61d7307569f 100644 --- a/tgui/packages/tgui/interfaces/SquadVendor.js +++ b/tgui/packages/tgui/interfaces/SquadVendor.js @@ -17,12 +17,19 @@ export const SquadVendor = (props, context) => {
{!!data.already_loaned && (
act('return_gear')} - /> + <> +