diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm index c267f9fb7d..a8f9178a83 100644 --- a/_maps/map_files/generic/CentCom.dmm +++ b/_maps/map_files/generic/CentCom.dmm @@ -16794,6 +16794,10 @@ }, /turf/open/indestructible/boss/air, /area/centcom/holding) +"Mu" = ( +/obj/machinery/computer/robotics, +/turf/open/indestructible/hotelwood, +/area/syndicate_mothership) "Mv" = ( /obj/structure/table/reinforced, /obj/item/storage/fancy/donut_box, @@ -17309,6 +17313,9 @@ }, /turf/open/floor/mineral/titanium/blue, /area/centcom/holding) +"OQ" = ( +/turf/open/indestructible/hotelwood, +/area/syndicate_mothership) "OS" = ( /obj/structure/mecha_wreckage/mauler, /turf/open/floor/plasteel/dark, @@ -17327,10 +17334,23 @@ }, /turf/open/floor/wood, /area/syndicate_mothership) +"OY" = ( +/obj/machinery/light{ + dir = 8 + }, +/turf/open/indestructible/hotelwood, +/area/syndicate_mothership) "OZ" = ( /obj/effect/turf_decal/delivery, /turf/open/floor/plating, /area/syndicate_mothership) +"Pc" = ( +/turf/closed/indestructible{ + icon = 'icons/turf/walls/wood_wall.dmi'; + icon_state = "wood"; + smooth = 1 + }, +/area/syndicate_mothership) "Pg" = ( /obj/machinery/light{ dir = 1 @@ -18557,6 +18577,10 @@ }, /turf/open/indestructible/hotelwood, /area/centcom/holding) +"WB" = ( +/obj/effect/landmark/start/slaver, +/turf/open/floor/carpet, +/area/syndicate_mothership) "WC" = ( /obj/structure/table/reinforced, /obj/item/pen, @@ -18654,6 +18678,10 @@ /obj/item/vending_refill/snack, /turf/open/indestructible/hotelwood, /area/centcom/holding) +"Xc" = ( +/obj/effect/landmark/start/slaver_leader, +/turf/open/floor/carpet, +/area/syndicate_mothership) "Xd" = ( /obj/structure/flora/ausbushes/fernybush, /obj/structure/flora/ausbushes/fullgrass, @@ -18771,6 +18799,10 @@ "XN" = ( /turf/open/floor/carpet/red, /area/centcom/holding) +"XP" = ( +/obj/machinery/computer/telecrystals, +/turf/open/indestructible/hotelwood, +/area/syndicate_mothership) "XT" = ( /obj/structure/table/wood, /obj/item/reagent_containers/food/snacks/sashimi, @@ -18837,6 +18869,10 @@ /obj/structure/dresser, /turf/open/floor/plasteel/dark, /area/syndicate_mothership) +"Yj" = ( +/obj/machinery/computer/slavery, +/turf/open/indestructible/hotelwood, +/area/syndicate_mothership) "Ym" = ( /obj/machinery/computer/arcade/orion_trail, /turf/open/indestructible/hotelwood, @@ -53000,24 +53036,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc aa aa aa @@ -53257,24 +53293,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +Pc aa aa aa @@ -53514,24 +53550,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +Pc aa aa aa @@ -53771,24 +53807,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OY +OQ +Pc aa aa aa @@ -54028,24 +54064,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +OQ +OQ +OQ +OY +OQ +OQ +OQ +OQ +OQ +OQ +OY +OQ +OQ +OQ +OY +OQ +Pc aa aa aa @@ -54285,24 +54321,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +Pc aa aa aa @@ -54542,24 +54578,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +Pc aa aa aa @@ -54799,24 +54835,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +OQ +OQ +OY +OQ +Mu +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +Pc aa aa aa @@ -55056,24 +55092,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +OQ +OQ +OQ +OQ +OQ +OQ +OY +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +Pc aa aa aa @@ -55313,24 +55349,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +WB +OQ +OQ +OQ +OQ +OQ +OQ +OQ +Pc aa aa aa @@ -55570,24 +55606,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +OQ +OQ +OQ +OQ +Yj +OQ +Xc +OQ +WB +OQ +OQ +OQ +OQ +OQ +OQ +OQ +Pc aa aa aa @@ -55827,24 +55863,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +WB +OQ +OY +OQ +OQ +OQ +OQ +OQ +Pc aa aa aa @@ -56084,24 +56120,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +OQ +OQ +OY +OQ +OQ +OQ +OQ +OQ +WB +OQ +OQ +OQ +OQ +OY +OQ +OQ +Pc aa aa aa @@ -56341,24 +56377,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +WB +OQ +OQ +OQ +OQ +OQ +OQ +OQ +Pc aa aa aa @@ -56598,24 +56634,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +OQ +OQ +OQ +OQ +OQ +XP +OY +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +Pc aa aa aa @@ -56855,24 +56891,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +Pc aa aa aa @@ -57112,24 +57148,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +Pc aa aa aa @@ -57369,24 +57405,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +OQ +OQ +OY +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OY +OQ +OQ +OQ +Pc aa aa aa @@ -57626,24 +57662,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +Pc aa aa aa @@ -57883,24 +57919,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +OQ +Pc aa aa aa @@ -58140,24 +58176,24 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc +Pc aa aa aa diff --git a/code/__DEFINES/access.dm b/code/__DEFINES/access.dm index c2021a86f2..a7b690e210 100644 --- a/code/__DEFINES/access.dm +++ b/code/__DEFINES/access.dm @@ -83,6 +83,7 @@ //The Syndicate #define ACCESS_SYNDICATE 150//General Syndicate Access. Includes Syndicate mechs and ruins. #define ACCESS_SYNDICATE_LEADER 151//Nuke Op Leader Access +#define ACCESS_SLAVER 152 //Slaver traders //Away Missions or Ruins /*For generic away-mission/ruin access. Why would normal crew have access to a long-abandoned derelict diff --git a/code/__DEFINES/atom_hud.dm b/code/__DEFINES/atom_hud.dm index 386473a3ae..d060944d70 100644 --- a/code/__DEFINES/atom_hud.dm +++ b/code/__DEFINES/atom_hud.dm @@ -60,7 +60,8 @@ #define ANTAG_HUD_BROTHER 23 #define ANTAG_HUD_BLOODSUCKER 24 #define ANTAG_HUD_FUGITIVE 25 -#define ANTAG_HUD_HERETIC 26 +#define ANTAG_HUD_HERETIC 26 +#define ANTAG_HUD_SLAVER 27 // Notification action types #define NOTIFY_JUMP "jump" diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 19ccf5fdc1..7fd88c5fe1 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -9,6 +9,7 @@ #define ROLE_SYNDICATE "Syndicate" #define ROLE_TRAITOR "traitor" #define ROLE_OPERATIVE "operative" +#define ROLE_SLAVER "slaver" #define ROLE_CHANGELING "changeling" #define ROLE_WIZARD "wizard" #define ROLE_MALF "malf AI" @@ -55,6 +56,7 @@ GLOBAL_LIST_INIT(special_roles, list( ROLE_TRAITOR = /datum/game_mode/traitor, ROLE_BROTHER = /datum/game_mode/traitor/bros, ROLE_OPERATIVE = /datum/game_mode/nuclear, + ROLE_SLAVER, ROLE_CHANGELING = /datum/game_mode/changeling, ROLE_WIZARD = /datum/game_mode/wizard, ROLE_MALF, diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 811ad111c4..40abb10ff7 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -335,6 +335,7 @@ #define DOMAIN_TRAIT "domain" #define NUKEOP_TRAIT "nuke-op" #define CLOWNOP_TRAIT "clown-op" +#define SLAVER_TRAIT "slaver" #define MEGAFAUNA_TRAIT "megafauna" #define DEATHSQUAD_TRAIT "deathsquad" #define SLIMEPUDDLE_TRAIT "slimepuddle" diff --git a/code/_globalvars/lists/mapping.dm b/code/_globalvars/lists/mapping.dm index 1e3f8d25eb..c831edba85 100644 --- a/code/_globalvars/lists/mapping.dm +++ b/code/_globalvars/lists/mapping.dm @@ -21,6 +21,8 @@ GLOBAL_LIST_EMPTY(jobspawn_overrides) //These will take precedence over norm GLOBAL_LIST_EMPTY(wizardstart) GLOBAL_LIST_EMPTY(nukeop_start) GLOBAL_LIST_EMPTY(nukeop_leader_start) +GLOBAL_LIST_EMPTY(slaver_start) +GLOBAL_LIST_EMPTY(slaver_leader_start) GLOBAL_LIST_EMPTY(newplayer_start) GLOBAL_LIST_EMPTY(prisonwarp) //prisoners go to these GLOBAL_LIST_EMPTY(holdingfacility) //captured people go here diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm index 9abc37c7e4..662e122419 100644 --- a/code/_globalvars/lists/objects.dm +++ b/code/_globalvars/lists/objects.dm @@ -26,6 +26,7 @@ GLOBAL_LIST_EMPTY(rcd_list) //list of Rapid Construction Devices. GLOBAL_LIST_EMPTY(apcs_list) //list of all Area Power Controller machines, separate from machines for powernet speeeeeeed. GLOBAL_LIST_EMPTY(tracked_implants) //list of all current implants that are tracked to work out what sort of trek everyone is on. Sadly not on lavaworld not implemented... GLOBAL_LIST_EMPTY(tracked_chem_implants) //list of implants the prisoner console can track and send inject commands too +GLOBAL_LIST_EMPTY(tracked_slaves) //list of mobs with slaver collars equipped. GLOBAL_LIST_EMPTY(poi_list) //list of points of interest for observe/follow GLOBAL_LIST_EMPTY(pinpointer_list) //list of all pinpointers. Used to change stuff they are pointing to all at once. GLOBAL_LIST_EMPTY(zombie_infection_list) // A list of all zombie_infection organs, for any mass "animation" diff --git a/code/datums/hud.dm b/code/datums/hud.dm index 1c23d5f2a0..fcf13cac4c 100644 --- a/code/datums/hud.dm +++ b/code/datums/hud.dm @@ -29,7 +29,8 @@ GLOBAL_LIST_INIT(huds, list( ANTAG_HUD_BROTHER = new/datum/atom_hud/antag/hidden(), ANTAG_HUD_BLOODSUCKER = new/datum/atom_hud/antag/bloodsucker(), ANTAG_HUD_FUGITIVE = new/datum/atom_hud/antag(), - ANTAG_HUD_HERETIC = new/datum/atom_hud/antag/hidden() + ANTAG_HUD_HERETIC = new/datum/atom_hud/antag/hidden(), + ANTAG_HUD_SLAVER = new/datum/atom_hud/antag(), )) /datum/atom_hud diff --git a/code/datums/mind.dm b/code/datums/mind.dm index fe8a7db23d..33d640c4dd 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -234,6 +234,12 @@ remove_antag_datum(nuke.type) special_role = null +/datum/mind/proc/remove_slaver() + var/datum/antagonist/slaver/slaver = has_antag_datum(/datum/antagonist/slaver,TRUE) + if(slaver) + remove_antag_datum(slaver.type) + special_role = null + /datum/mind/proc/remove_wizard() remove_antag_datum(/datum/antagonist/wizard) special_role = null @@ -263,6 +269,7 @@ remove_changeling() remove_traitor() remove_nukeop() + remove_slaver() remove_wizard() remove_cultist() remove_rev() @@ -367,6 +374,13 @@ N.nukeop_outfit = null add_antag_datum(N,converter.nuke_team) + else if(is_slaver(creator)) + var/datum/antagonist/slaver/converter = creator.mind.has_antag_datum(/datum/antagonist/slaver,TRUE) + var/datum/antagonist/slaver/S = new() + S.send_to_spawnpoint = FALSE + S.slaver_outfit = null + add_antag_datum(S,converter.slaver_team) + enslaved_to = creator diff --git a/code/game/gamemodes/bloodsucker/bloodsucker.dm b/code/game/gamemodes/bloodsucker/bloodsucker.dm index aa8edeaa72..6acedb0d52 100644 --- a/code/game/gamemodes/bloodsucker/bloodsucker.dm +++ b/code/game/gamemodes/bloodsucker/bloodsucker.dm @@ -7,7 +7,7 @@ // LISTS // var/list/vassal_allowed_antags = list(/datum/antagonist/brother, /datum/antagonist/traitor, /datum/antagonist/traitor/internal_affairs, /datum/antagonist/survivalist, \ - /datum/antagonist/rev, /datum/antagonist/nukeop, /datum/antagonist/pirate, /datum/antagonist/cult, /datum/antagonist/abductee, /datum/antagonist/valentine, /datum/antagonist/heartbreaker,) + /datum/antagonist/rev, /datum/antagonist/nukeop, /datum/antagonist/slaver, /datum/antagonist/pirate, /datum/antagonist/cult, /datum/antagonist/abductee, /datum/antagonist/valentine, /datum/antagonist/heartbreaker,) // The antags you're allowed to be if turning Vassal. /proc/AmBloodsucker(mob/living/M, falseIfInDisguise = FALSE) diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 1c6c444fb4..193ab47ad1 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -557,6 +557,15 @@ If not set, defaults to check_completion instead. Set it. It's used by cryo. return TRUE return FALSE +/datum/objective/slaver + name = "slaver" + explanation_text = "Capture some of the station crew. Bring them back to the hideout." + +/datum/objective/slaver/check_completion() + // if(SSticker && SSticker.mode && SSticker.mode.station_was_nuked) + // return TRUE + return FALSE + GLOBAL_LIST_EMPTY(possible_items) /datum/objective/steal name = "steal" diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 822302789f..df3fb00f61 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -376,6 +376,7 @@ data["authorizeName"] = authorize_name data["canLogOut"] = !issilicon(user) data["shuttleCanEvacOrFailReason"] = SSshuttle.canEvac(user, TRUE) + data["availableSlaves"] = TRUE // GLOB.tracked_slaves if (authenticated_as_non_silicon_captain(user)) data["canRequestNuke"] = TRUE diff --git a/code/game/machinery/computer/slavery.dm b/code/game/machinery/computer/slavery.dm new file mode 100644 index 0000000000..c452063621 --- /dev/null +++ b/code/game/machinery/computer/slavery.dm @@ -0,0 +1,117 @@ +/obj/machinery/computer/slavery + name = "\improper slave management console" + desc = "Used to track and manage collared slaves. The limited range reaches only as far as the hideout perimeter." + icon_screen = "explosive" + icon_keyboard = "security_key" + clockwork = TRUE + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF + req_access = list(ACCESS_SLAVER) + light_color = LIGHT_COLOR_RED + +// /obj/machinery/computer/slavery/ui_interact(mob/user) +// . = ..() +// var/dat = "" +// dat += "Refresh.
" +// dat += "[storedcrystals] telecrystals are available for distribution.
" +// dat += "

" + +// dat += "
Slaves
" +// for(var/obj/item/electropack/shockcollar/slave/S in GLOB.tracked_slaves) +// if(!isliving(loc)) +// continue +// Tr = get_turf(T.imp_in) +// if((Tr) && (Tr.z != src.z)) +// continue//Out of range + +// var/loc_display = "Unknown" +// var/mob/living/M = T.imp_in +// if(is_station_level(Tr.z) && !isspaceturf(M.loc)) +// var/turf/mob_loc = get_turf(M) +// loc_display = mob_loc.loc + +// dat += "ID: [T.imp_in.name] | Location: [loc_display]
" +// dat += "(Message Holder) |
" +// dat += "********************************
" +// dat += "
{Log Out}" + +/obj/machinery/computer/slavery/ui_interact(mob/user, datum/tgui/ui) + // priority_announce("Message test 123 123 Message test 123 123 Message test 123 123 Message test 123 123 Message test 123 123.", sender_override = "Hail from the [slaver_team.slaver_crew_name]") + // if(!GLOB.bounties_list.len) + // setup_bounties() + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "SlaveConsole", name) + ui.open() + +/obj/machinery/computer/slavery/ui_data(mob/user) + var/list/data = list() + + var/turf/curr = get_turf(src) + data["currentCoords"] = "[curr.x], [curr.y], [curr.z]" + + var/list/slaves = list() + data["slaves"] = list() + + for(var/tracked_slave in GLOB.tracked_slaves) + var/obj/item/electropack/shockcollar/slave/C = tracked_slave + if (!isliving(C.loc)) + continue; + + var/mob/living/L = C.loc + var/turf/pos = get_turf(L) + if(!pos || pos.z != curr.z || C == L.get_item_by_slot(SLOT_NECK)) + continue + + var/list/slave = list() + slave["id"] = C.collarID + priority_announce("Getting collar ID first: [C.GetID()] end.", sender_override = "toggleBought") + slave["name"] = L.real_name + slave["bought"] = C.bought + + slave["coords"] = "[pos.x], [pos.y], [pos.z]" + slave["dist"] = max(get_dist(curr, pos), 0) //Distance between the machine and slave turfs + slave["degrees"] = round(Get_Angle(curr, pos)) //0-360 degree directional bearing, for more precision. + slaves += list(slave) //Add this slave to the list of slaves + data["slaves"] = slaves + return data + +/obj/machinery/computer/slavery/ui_act(action, params) + if(..()) + return + + switch(action) + if ("makePriorityAnnouncement") + priority_announce("Announcement.", sender_override = "Beep Beep upgate") + // var/is_ai = issilicon(user) + // if(!SScommunications.can_announce(user, is_ai)) + // to_chat(user, "Intercomms recharging. Please stand by.") + // return + // var/input = stripped_input(user, "Please choose a message to announce to the station crew.", "What?") + // if(!input || !user.canUseTopic(src, !issilicon(usr))) + // return + // if(!(user.can_speak())) //No more cheating, mime/random mute guy! + // input = "..." + // to_chat(user, "You find yourself unable to speak.") + // else + // input = user.treat_message(input) //Adds slurs and so on. Someone should make this use languages too. + // SScommunications.make_announcement(user, is_ai, input) + // deadchat_broadcast(" made a priority announcement from [get_area_name(usr, TRUE)].", "[user.real_name]", user) + + if("purchaseSupplies") + priority_announce("Purchase Supplies.", sender_override = "Beep Beep upgate") + + if("toggleBought") + var/boughtID = text2num(params["id"]) + priority_announce("Collar ID is: [boughtID] end.", sender_override = "toggleBought") + + for(var/tracked_slave in GLOB.tracked_slaves) + var/obj/item/electropack/shockcollar/slave/C = tracked_slave + if (C.collarID == boughtID) + if (!isliving(C.loc)) + priority_announce("Not living location", sender_override = "toggleBought") + continue; + + var/mob/living/L = C.loc + priority_announce("Slave ckey is: [L.ckey] end.", sender_override = "toggleBought") + + diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm index 8ff4017b8c..c87b1f1133 100644 --- a/code/game/objects/effects/landmarks.dm +++ b/code/game/objects/effects/landmarks.dm @@ -270,6 +270,30 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark) GLOB.nukeop_leader_start += loc return INITIALIZE_HINT_QDEL + + +/obj/effect/landmark/start/slaver + name = "slaver" + icon = 'icons/effects/landmarks_static.dmi' + icon_state = "sslaver_spawn" + +/obj/effect/landmark/start/slaver/Initialize() + ..() + GLOB.slaver_start += loc + return INITIALIZE_HINT_QDEL + +/obj/effect/landmark/start/slaver_leader + name = "slaver leader" + icon = 'icons/effects/landmarks_static.dmi' + icon_state = "sslaver_leader_spawn" + +/obj/effect/landmark/start/slaver_leader/Initialize() + ..() + GLOB.slaver_leader_start += loc + return INITIALIZE_HINT_QDEL + + + // Must be immediate because players will // join before SSatom initializes everything. INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player) diff --git a/code/game/objects/items/devices/radio/electropack.dm b/code/game/objects/items/devices/radio/electropack.dm index c51edc8106..852316b02b 100644 --- a/code/game/objects/items/devices/radio/electropack.dm +++ b/code/game/objects/items/devices/radio/electropack.dm @@ -202,3 +202,21 @@ if(action == "power") // DO. NOT. return FALSE return ..() + +/obj/item/electropack/shockcollar/slave + name = "slave collar" + desc = "A reinforced metal collar. This one has a shock element and tracker installed." + var/static/lastID = 0; + var/collarID + var/bought = FALSE + +/obj/item/electropack/shockcollar/slave/Initialize() + . = ..() + collarID = ++lastID + GLOB.tracked_slaves += src + priority_announce("New pack", sender_override = "Beep Beep upgate") + +/obj/item/electropack/shockcollar/slave/Destroy() + . = ..() + GLOB.tracked_slaves -= src + priority_announce("pack deleted", sender_override = "Beep Beep upgate") diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index a8a7e51611..fd48d5015e 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -113,6 +113,14 @@ else message_admins("[key_name_admin(usr)] tried to create a nuke team. Unfortunately, there were not enough candidates available.") log_admin("[key_name(usr)] failed to create a nuke team.") + if("slaver") + message_admins("[key_name(usr)] is creating a slaver trader crew...") + if(src.makeSlaverTeam()) + message_admins("[key_name(usr)] created a slave trader crew.") + log_admin("[key_name(usr)] created a slave trader crew.") + else + message_admins("[key_name_admin(usr)] tried to create a slave trader crew. Unfortunately, there were not enough candidates available.") + log_admin("[key_name(usr)] failed to create a slave trader crew.") if("ninja") message_admins("[key_name(usr)] spawned a ninja.") log_admin("[key_name(usr)] spawned a ninja.") diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index 6c43d61cce..26c56fbeeb 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -19,6 +19,7 @@ Make Blob
Make Wizard (Requires Ghosts)
Make Nuke Team (Requires Ghosts)
+ Make Slave Trader Crew (Requires Ghosts)
Make CentCom Response Team (Requires Ghosts)
Make Abductor Team (Requires Ghosts)
Make Revenant (Requires Ghost)
@@ -254,6 +255,50 @@ return 0 +//Abductors +///datum/admins/proc/makeAbductorTeam() +// new /datum/round_event/ghost_role/abductor +// return 1 + +/datum/admins/proc/makeSlaverTeam() + var/list/mob/candidates = pollGhostCandidates("Do you wish to be considered for the slave trader crew entering the sector?", ROLE_SLAVER) + var/list/mob/chosen = list() + var/mob/theghost = null + + if(candidates.len) + var/numslavers = 5 + var/slavercount = 0 + + for(var/i = 0, iYou are a slave trader!") + owner.announce_objectives() + +/datum/antagonist/slaver/on_gain() + forge_objectives() + . = ..() + equip_slaver() + if(send_to_spawnpoint) + move_to_spawnpoint() + +/datum/antagonist/slaver/get_team() + return slaver_team + +/datum/antagonist/slaver/proc/forge_objectives() + objectives |= slaver_team.objectives + +/datum/antagonist/slaver/proc/move_to_spawnpoint() + owner.current.forceMove(GLOB.slaver_start[(0 % GLOB.slaver_start.len) + 1]) + +/datum/antagonist/slaver/leader/move_to_spawnpoint() + owner.current.forceMove(pick(GLOB.slaver_leader_start)) + +/datum/antagonist/slaver/admin_add(datum/mind/new_owner,mob/admin) + new_owner.assigned_role = ROLE_SLAVER + new_owner.add_antag_datum(src) + message_admins("[key_name_admin(admin)] has slaver'd [new_owner.current].") + log_admin("[key_name(admin)] has slaver'd [new_owner.current].") + +/datum/antagonist/slaver/get_admin_commands() + . = ..() + .["Send to base"] = CALLBACK(src,.proc/admin_send_to_base) + +/datum/antagonist/slaver/proc/admin_send_to_base(mob/admin) + owner.current.forceMove(pick(GLOB.slaver_start)) + +/datum/antagonist/slaver/leader + name = "Slave Master" + slaver_outfit = /datum/outfit/slaver/leader + +/datum/antagonist/slaver/leader/greet() + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0) + to_chat(owner, "You are the Slave Master for this collection job. You are responsible for organising your team and your ID is the only one who can open the launch bay doors.") + to_chat(owner, "If you feel you are not up to this task, give your ID to another slaver.") + owner.announce_objectives() + addtimer(CALLBACK(src, .proc/slavers_name_assign), 1) + + +/datum/antagonist/slaver/leader/proc/slavers_name_assign() + slaver_team.slaver_crew_name = ask_name() + // priority_announce("Message test 123 123 Message test 123 123 Message test 123 123 Message test 123 123 Message test 123 123.", sender_override = "Hail from the [slaver_team.slaver_crew_name]") + +/datum/antagonist/slaver/leader/proc/ask_name() + var/defaultname = slaver_team.slaver_crew_name + var/newname = stripped_input(owner.current, "You are the slave master. Please choose a name for your crew.", "Crew name", defaultname) + if (!newname) + newname = defaultname + else + newname = reject_bad_name(newname) + if(!newname) + newname = defaultname + + return capitalize(newname) + +/datum/team/slavers + var/slaver_crew_name = "Slave Traders" + var/core_objective = /datum/objective/slaver + +/datum/team/slavers/proc/update_objectives() + if(core_objective) + var/datum/objective/O = new core_objective + O.team = src + objectives += O + +/datum/team/pirate/roundend_report() + var/list/parts = list() + + parts += "Space Pirates were:" + + var/all_dead = TRUE + for(var/datum/mind/M in members) + if(considered_alive(M)) + all_dead = FALSE + parts += printplayerlist(members) + + parts += "Loot stolen: " + var/datum/objective/loot/L = locate() in objectives + parts += L.loot_listing() + parts += "Total loot value : [L.get_loot_value()]/[L.target_value] credits" + + if(L.check_completion() && !all_dead) + parts += "The pirate crew was successful!" + else + parts += "The pirate crew has failed." + + return "
[parts.Join("
")]
" + +/datum/team/slavers/roundend_report() + var/list/parts = list() + parts += "[slaver_crew_name] Crew:" + + var/text = "
The syndicate operatives were:" + var/purchases = "" + var/TC_uses = 0 + LAZYINITLIST(GLOB.uplink_purchase_logs_by_key) + for(var/I in members) + var/datum/mind/syndicate = I + var/datum/uplink_purchase_log/H = GLOB.uplink_purchase_logs_by_key[syndicate.key] + if(H) + TC_uses += H.total_spent + purchases += H.generate_render(show_key = FALSE) + text += printplayerlist(members) + text += "
" + text += "(Syndicates used [TC_uses] TC) [purchases]" + + parts += text + + return "
[parts.Join("
")]
" + +/datum/team/slavers/antag_listing_name() + if(slaver_crew_name) + return "[slaver_crew_name] Syndico" + else + return "Syndicaa" + +/datum/team/slavers/is_gamemode_hero() + return SSticker.mode.name == "slave hunters" + +/proc/is_slaver(mob/M) + return M && istype(M) && M.mind && M.mind.has_antag_datum(/datum/antagonist/slaver) + +// /datum/round_event_control/operative +// name = "Slave Traders" +// typepath = /datum/round_event/ghost_role/slavers +// weight = 0 //Admin only +// max_occurrences = 1 diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 5bfc6fe652..757d8847f1 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -327,6 +327,9 @@ It's fairly easy to fix if dealing with single letters but not so much with comp if("nuclear") if(M.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE)) return 2 + if("slaver") + if(M.mind.has_antag_datum(/datum/antagonist/slaver,TRUE)) + return 2 if("changeling") if(M.mind.has_antag_datum(/datum/antagonist/changeling,TRUE)) return 2 diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi index 1d2007fd63..db5371f95d 100644 Binary files a/icons/mob/hud.dmi and b/icons/mob/hud.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 0be30ab1ed..b0a25d6f09 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -946,6 +946,7 @@ #include "code\game\machinery\computer\pod.dm" #include "code\game\machinery\computer\robot.dm" #include "code\game\machinery\computer\security.dm" +#include "code\game\machinery\computer\slavery.dm" #include "code\game\machinery\computer\station_alert.dm" #include "code\game\machinery\computer\telecrystalconsoles.dm" #include "code\game\machinery\computer\teleporter.dm" @@ -1777,6 +1778,8 @@ #include "code\modules\antagonists\slaughter\slaughter.dm" #include "code\modules\antagonists\slaughter\slaughter_antag.dm" #include "code\modules\antagonists\slaughter\slaughterevent.dm" +#include "code\modules\antagonists\slaver\slaver.dm" +#include "code\modules\antagonists\slaver\equipment\slaver_outfits.dm" #include "code\modules\antagonists\space_dragon\space_dragon.dm" #include "code\modules\antagonists\space_ninja\space_ninja.dm" #include "code\modules\antagonists\survivalist\survivalist.dm" diff --git a/tgui/packages/tgui/interfaces/CommunicationsConsole.js b/tgui/packages/tgui/interfaces/CommunicationsConsole.js index a9b07a8f36..6350c43d55 100644 --- a/tgui/packages/tgui/interfaces/CommunicationsConsole.js +++ b/tgui/packages/tgui/interfaces/CommunicationsConsole.js @@ -1,7 +1,7 @@ import { sortBy } from "common/collections"; import { capitalize } from "common/string"; import { useBackend, useLocalState } from "../backend"; -import { Blink, Box, Button, Dimmer, Flex, Icon, Input, Modal, Section, TextArea } from "../components"; +import { Blink, Box, Button, Dimmer, Flex, Stack, Icon, Input, Modal, Section, TextArea, LabeledList } from "../components"; import { Window } from "../layouts"; import { sanitizeText } from "../sanitize"; @@ -317,6 +317,7 @@ export const PageMain = (props, context) => { shuttleCanEvacOrFailReason, shuttleLastCalled, shuttleRecallable, + availableSlaves, } = data; const [callingShuttle, setCallingShuttle] = useLocalState( @@ -472,6 +473,56 @@ export const PageMain = (props, context) => { + {availableSlaves && ( +
+ + + John Smith + + +
+ )} + {!!canMessageAssociates && messagingAssociates && map(parseFloat)(coords.split(', ')); + +export const SlaveConsole = (props, context) => { + const { act, data } = useBackend(context); + const { + currentCoords, + } = data; + const slaves = flow([ + map((slave, index) => { + // Calculate distance to the target. BYOND distance is capped to 127, + // that's why we roll our own calculations here. + const dist = slave.dist && ( + Math.round(vecLength(vecSubtract( + coordsToVec(currentCoords), + coordsToVec(slave.coords)))) + ); + return { ...slave, dist, index }; + }), + sortBy( + slave => slave.name), // Sort alphabetically + ])(data.slaves || []); + return ( + + +
+ + 12345 + +
+ +
+ + 12345 + +
+ +
+ 12345 +
+ +
+ +
+ +
+ + {slaves.map(slave => ( + + + + {slave.name} + + + + {slave.degrees !== undefined && ( + + )} + {slave.dist !== undefined && ( + slave.dist + 'm' + )} +
+ +
+ + {slaves.map(slave => ( + + + + {slave.name} + + + + {slave.degrees !== undefined && ( + + )} + {slave.dist !== undefined && ( + slave.dist + 'm' + )} + + + +
+
+ +
+ + {slaves.map(slave => ( + + + + {slave.name} + + + + {slave.degrees !== undefined && ( + + )} + {slave.dist !== undefined && ( + slave.dist + 'm' + )} + + + +
+
+
+
+ ); +};