From b5fe141a498cffd58c63235581fdb90fe26c73cf Mon Sep 17 00:00:00 2001 From: kevinz000 <2003111+kevinz000@users.noreply.github.com> Date: Thu, 5 Dec 2019 21:54:42 -0700 Subject: [PATCH] Supply Pod Code Update --- code/__DEFINES/admin.dm | 191 +- code/__DEFINES/cargo.dm | 4 +- code/__DEFINES/flags.dm | 187 +- code/datums/explosion.dm | 2 +- code/game/atoms.dm | 1751 +++-- code/modules/admin/admin.dm | 2050 +++--- code/modules/admin/admin_verbs.dm | 2 +- code/modules/admin/topic.dm | 5975 +++++++++-------- code/modules/admin/verbs/randomverbs.dm | 2888 ++++---- code/modules/cargo/centcom_podlauncher.dm | 120 +- code/modules/cargo/expressconsole.dm | 412 +- code/modules/cargo/gondolapod.dm | 13 +- code/modules/cargo/supplypod.dm | 139 +- code/modules/events/immovable_rod.dm | 336 +- code/modules/mob/living/silicon/silicon.dm | 824 ++- .../hostile/megafauna/megafauna.dm | 4 +- code/modules/power/supermatter/supermatter.dm | 4 +- html/create_object.html | 3 +- sound/weapons/mortar_long_whistle.ogg | Bin 0 -> 14156 bytes sound/weapons/mortar_whistle.ogg | Bin 0 -> 6885 bytes tgui/src/interfaces/centcom_podlauncher.ract | 215 +- 21 files changed, 7666 insertions(+), 7454 deletions(-) create mode 100644 sound/weapons/mortar_long_whistle.ogg create mode 100644 sound/weapons/mortar_whistle.ogg diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index 7e546218..4ec41080 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -1,95 +1,96 @@ -//A set of constants used to determine which type of mute an admin wishes to apply: -//Please read and understand the muting/automuting stuff before changing these. MUTE_IC_AUTO etc = (MUTE_IC << 1) -//Therefore there needs to be a gap between the flags for the automute flags -#define MUTE_IC (1<<0) -#define MUTE_OOC (1<<1) -#define MUTE_PRAY (1<<2) -#define MUTE_ADMINHELP (1<<3) -#define MUTE_DEADCHAT (1<<4) -#define MUTE_ALL (~0) - -//Some constants for DB_Ban -#define BANTYPE_PERMA 1 -#define BANTYPE_TEMP 2 -#define BANTYPE_JOB_PERMA 3 -#define BANTYPE_JOB_TEMP 4 -#define BANTYPE_ANY_FULLBAN 5 //used to locate stuff to unban. - -#define BANTYPE_ADMIN_PERMA 7 -#define BANTYPE_ADMIN_TEMP 8 -#define BANTYPE_ANY_JOB 9 //used to remove jobbans - -//Admin Permissions -#define R_BUILDMODE (1<<0) -#define R_ADMIN (1<<1) -#define R_BAN (1<<2) -#define R_FUN (1<<3) -#define R_SERVER (1<<4) -#define R_DEBUG (1<<5) -#define R_POSSESS (1<<6) -#define R_PERMISSIONS (1<<7) -#define R_STEALTH (1<<8) -#define R_POLL (1<<9) -#define R_VAREDIT (1<<10) -#define R_SOUNDS (1<<11) -#define R_SPAWN (1<<12) -#define R_AUTOLOGIN (1<<13) -#define R_DBRANKS (1<<14) - -#define R_DEFAULT R_AUTOLOGIN - -#define R_EVERYTHING ALL //the sum of all other rank permissions, used for +EVERYTHING - -#define ADMIN_QUE(user) "(?)" -#define ADMIN_FLW(user) "(FLW)" -#define ADMIN_PP(user) "(PP)" -#define ADMIN_VV(atom) "(VV)" -#define ADMIN_SM(user) "(SM)" -#define ADMIN_TP(user) "(TP)" -#define ADMIN_KICK(user) "(KICK)" -#define ADMIN_CENTCOM_REPLY(user) "(RPLY)" -#define ADMIN_SYNDICATE_REPLY(user) "(RPLY)" -#define ADMIN_SC(user) "(SC)" -#define ADMIN_SMITE(user) "(SMITE)" -#define ADMIN_LOOKUP(user) "[key_name_admin(user)][ADMIN_QUE(user)]" -#define ADMIN_LOOKUPFLW(user) "[key_name_admin(user)][ADMIN_QUE(user)] [ADMIN_FLW(user)]" -#define ADMIN_SET_SD_CODE "(SETCODE)" -#define ADMIN_FULLMONTY_NONAME(user) "[ADMIN_QUE(user)] [ADMIN_PP(user)] [ADMIN_VV(user)] [ADMIN_SM(user)] [ADMIN_FLW(user)] [ADMIN_TP(user)] [ADMIN_INDIVIDUALLOG(user)] [ADMIN_SMITE(user)]" -#define ADMIN_FULLMONTY(user) "[key_name_admin(user)] [ADMIN_FULLMONTY_NONAME(user)]" -#define ADMIN_JMP(src) "(JMP)" -#define COORD(src) "[src ? "([src.x],[src.y],[src.z])" : "nonexistent location"]" -#define AREACOORD(src) "[src ? "[get_area_name(src, TRUE)] ([src.x], [src.y], [src.z])" : "nonexistent location"]" -#define ADMIN_COORDJMP(src) "[src ? "[COORD(src)] [ADMIN_JMP(src)]" : "nonexistent location"]" -#define ADMIN_VERBOSEJMP(src) "[src ? "[AREACOORD(src)] [ADMIN_JMP(src)]" : "nonexistent location"]" -#define ADMIN_INDIVIDUALLOG(user) "(LOGS)" - -#define ADMIN_PUNISHMENT_LIGHTNING "Lightning bolt" -#define ADMIN_PUNISHMENT_BRAINDAMAGE "Brain damage" -#define ADMIN_PUNISHMENT_GIB "Gib" -#define ADMIN_PUNISHMENT_BSA "Bluespace Artillery Device" -#define ADMIN_PUNISHMENT_FIREBALL "Fireball" -#define ADMIN_PUNISHMENT_CLUWNE "Floor Cluwne" -#define ADMIN_PUNISHMENT_ROD "Immovable Rod" -#define ADMIN_PUNISHMENT_SUPPLYPOD "Supply Pod" -#define ADMIN_PUNISHMENT_MAZING "Puzzle" -#define ADMIN_PUNISHMENT_PIE "Cream Pie" -#define ADMIN_PUNISHMENT_TABLETIDESTATIONWIDE "Tabletide Stationwide" -#define ADMIN_PUNISHMENT_FAKEBWOINK "Fake Bwoink" -#define ADMIN_PUNISHMENT_NUGGET "Nugget" -#define ADMIN_PUNISHMENT_BREADIFY ":b:read" - -#define AHELP_ACTIVE 1 -#define AHELP_CLOSED 2 -#define AHELP_RESOLVED 3 - -#define ROUNDSTART_LOGOUT_REPORT_TIME 6000 //Amount of time (in deciseconds) after the rounds starts, that the player disconnect report is issued. - -#define SPAM_TRIGGER_WARNING 5 //Number of identical messages required before the spam-prevention will warn you to stfu -#define SPAM_TRIGGER_AUTOMUTE 10 //Number of identical messages required before the spam-prevention will automute you - -///Max length of a keypress command before it's considered to be a forged packet/bogus command -#define MAX_KEYPRESS_COMMANDLENGTH 16 -///Max amount of keypress messages per second over two seconds before client is autokicked -#define MAX_KEYPRESS_AUTOKICK 100 -///Length of held key rolling buffer -#define HELD_KEY_BUFFER_LENGTH 15 +//A set of constants used to determine which type of mute an admin wishes to apply: +//Please read and understand the muting/automuting stuff before changing these. MUTE_IC_AUTO etc = (MUTE_IC << 1) +//Therefore there needs to be a gap between the flags for the automute flags +#define MUTE_IC (1<<0) +#define MUTE_OOC (1<<1) +#define MUTE_PRAY (1<<2) +#define MUTE_ADMINHELP (1<<3) +#define MUTE_DEADCHAT (1<<4) +#define MUTE_ALL (~0) + +//Some constants for DB_Ban +#define BANTYPE_PERMA 1 +#define BANTYPE_TEMP 2 +#define BANTYPE_JOB_PERMA 3 +#define BANTYPE_JOB_TEMP 4 +#define BANTYPE_ANY_FULLBAN 5 //used to locate stuff to unban. + +#define BANTYPE_ADMIN_PERMA 7 +#define BANTYPE_ADMIN_TEMP 8 +#define BANTYPE_ANY_JOB 9 //used to remove jobbans + +//Admin Permissions +#define R_BUILDMODE (1<<0) +#define R_ADMIN (1<<1) +#define R_BAN (1<<2) +#define R_FUN (1<<3) +#define R_SERVER (1<<4) +#define R_DEBUG (1<<5) +#define R_POSSESS (1<<6) +#define R_PERMISSIONS (1<<7) +#define R_STEALTH (1<<8) +#define R_POLL (1<<9) +#define R_VAREDIT (1<<10) +#define R_SOUNDS (1<<11) +#define R_SPAWN (1<<12) +#define R_AUTOLOGIN (1<<13) +#define R_DBRANKS (1<<14) + +#define R_DEFAULT R_AUTOLOGIN + +#define R_EVERYTHING ALL //the sum of all other rank permissions, used for +EVERYTHING + +#define ADMIN_QUE(user) "(?)" +#define ADMIN_FLW(user) "(FLW)" +#define ADMIN_PP(user) "(PP)" +#define ADMIN_VV(atom) "(VV)" +#define ADMIN_SM(user) "(SM)" +#define ADMIN_TP(user) "(TP)" +#define ADMIN_KICK(user) "(KICK)" +#define ADMIN_CENTCOM_REPLY(user) "(RPLY)" +#define ADMIN_SYNDICATE_REPLY(user) "(RPLY)" +#define ADMIN_SC(user) "(SC)" +#define ADMIN_SMITE(user) "(SMITE)" +#define ADMIN_LOOKUP(user) "[key_name_admin(user)][ADMIN_QUE(user)]" +#define ADMIN_LOOKUPFLW(user) "[key_name_admin(user)][ADMIN_QUE(user)] [ADMIN_FLW(user)]" +#define ADMIN_SET_SD_CODE "(SETCODE)" +#define ADMIN_FULLMONTY_NONAME(user) "[ADMIN_QUE(user)] [ADMIN_PP(user)] [ADMIN_VV(user)] [ADMIN_SM(user)] [ADMIN_FLW(user)] [ADMIN_TP(user)] [ADMIN_INDIVIDUALLOG(user)] [ADMIN_SMITE(user)]" +#define ADMIN_FULLMONTY(user) "[key_name_admin(user)] [ADMIN_FULLMONTY_NONAME(user)]" +#define ADMIN_JMP(src) "(JMP)" +#define COORD(src) "[src ? "([src.x],[src.y],[src.z])" : "nonexistent location"]" +#define AREACOORD(src) "[src ? "[get_area_name(src, TRUE)] ([src.x], [src.y], [src.z])" : "nonexistent location"]" +#define ADMIN_COORDJMP(src) "[src ? "[COORD(src)] [ADMIN_JMP(src)]" : "nonexistent location"]" +#define ADMIN_VERBOSEJMP(src) "[src ? "[AREACOORD(src)] [ADMIN_JMP(src)]" : "nonexistent location"]" +#define ADMIN_INDIVIDUALLOG(user) "(LOGS)" + +#define ADMIN_PUNISHMENT_LIGHTNING "Lightning bolt" +#define ADMIN_PUNISHMENT_BRAINDAMAGE "Brain damage" +#define ADMIN_PUNISHMENT_GIB "Gib" +#define ADMIN_PUNISHMENT_BSA "Bluespace Artillery Device" +#define ADMIN_PUNISHMENT_FIREBALL "Fireball" +#define ADMIN_PUNISHMENT_CLUWNE "Floor Cluwne" +#define ADMIN_PUNISHMENT_ROD "Immovable Rod" +#define ADMIN_PUNISHMENT_SUPPLYPOD_QUICK "Supply Pod (Quick)" +#define ADMIN_PUNISHMENT_SUPPLYPOD "Supply Pod" +#define ADMIN_PUNISHMENT_MAZING "Puzzle" +#define ADMIN_PUNISHMENT_PIE "Cream Pie" +#define ADMIN_PUNISHMENT_TABLETIDESTATIONWIDE "Tabletide Stationwide" +#define ADMIN_PUNISHMENT_FAKEBWOINK "Fake Bwoink" +#define ADMIN_PUNISHMENT_NUGGET "Nugget" +#define ADMIN_PUNISHMENT_BREADIFY ":b:read" + +#define AHELP_ACTIVE 1 +#define AHELP_CLOSED 2 +#define AHELP_RESOLVED 3 + +#define ROUNDSTART_LOGOUT_REPORT_TIME 6000 //Amount of time (in deciseconds) after the rounds starts, that the player disconnect report is issued. + +#define SPAM_TRIGGER_WARNING 5 //Number of identical messages required before the spam-prevention will warn you to stfu +#define SPAM_TRIGGER_AUTOMUTE 10 //Number of identical messages required before the spam-prevention will automute you + +///Max length of a keypress command before it's considered to be a forged packet/bogus command +#define MAX_KEYPRESS_COMMANDLENGTH 16 +///Max amount of keypress messages per second over two seconds before client is autokicked +#define MAX_KEYPRESS_AUTOKICK 100 +///Length of held key rolling buffer +#define HELD_KEY_BUFFER_LENGTH 15 diff --git a/code/__DEFINES/cargo.dm b/code/__DEFINES/cargo.dm index e87c4d3e..4317a922 100644 --- a/code/__DEFINES/cargo.dm +++ b/code/__DEFINES/cargo.dm @@ -11,6 +11,7 @@ #define STYLE_FRUIT 11 #define STYLE_INVISIBLE 12 #define STYLE_GONDOLA 13 +#define STYLE_SEETHROUGH 14 #define POD_ICON_STATE 1 #define POD_NAME 2 @@ -29,5 +30,6 @@ list("honkpod", "\improper HONK pod", "A brightly-colored supply pod. It likely originated from the Clown Federation."),\ list("fruitpod", "\improper Orange", "An angry orange."),\ list("", "\improper S.T.E.A.L.T.H. pod MKVII", "A supply pod that, under normal circumstances, is completely invisible to conventional methods of detection. How are you even seeing this?"),\ - list("gondolapod", "gondola", "The silent walker. This one seems to be part of a delivery agency.")\ + list("gondolapod", "gondola", "The silent walker. This one seems to be part of a delivery agency."),\ + list("", "", "")\ ) \ No newline at end of file diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index 84a359f6..75209dd5 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -1,93 +1,94 @@ -/* - These defines are specific to the atom/flags_1 bitmask -*/ -#define ALL (~0) //For convenience. -#define NONE 0 - -//for convenience -#define ENABLE_BITFIELD(variable, flag) (variable |= (flag)) -#define DISABLE_BITFIELD(variable, flag) (variable &= ~(flag)) -#define CHECK_BITFIELD(variable, flag) (variable & (flag)) -#define TOGGLE_BITFIELD(variable, flag) (variable ^= (flag)) - -#define CHECK_MULTIPLE_BITFIELDS(flagvar, flags) (((flagvar) & (flags)) == (flags)) - -GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768)) - -// for /datum/var/datum_flags -#define DF_USE_TAG (1<<0) -#define DF_VAR_EDITED (1<<1) -#define DF_ISPROCESSING (1<<2) - -//FLAGS BITMASK - -#define HEAR_1 (1<<3) // This flag is what recursive_hear_check() uses to determine wether to add an item to the hearer list or not. -#define CHECK_RICOCHET_1 (1<<4) // Projectiels will check ricochet on things impacted that have this. -#define CONDUCT_1 (1<<5) // conducts electricity (metal etc.) -#define NODECONSTRUCT_1 (1<<7) // For machines and structures that should not break into parts, eg, holodeck stuff -#define OVERLAY_QUEUED_1 (1<<8) // atom queued to SSoverlay -#define ON_BORDER_1 (1<<9) // item has priority to check when entering or leaving -#define PREVENT_CLICK_UNDER_1 (1<<11) //Prevent clicking things below it on the same turf eg. doors/ fulltile windows -#define HOLOGRAM_1 (1<<12) -#define TESLA_IGNORE_1 (1<<13) // TESLA_IGNORE grants immunity from being targeted by tesla-style electricity -#define INITIALIZED_1 (1<<14) //Whether /atom/Initialize() has already run for the object -#define ADMIN_SPAWNED_1 (1<<15) //was this spawned by an admin? used for stat tracking stuff. - -//turf-only flags -#define NOJAUNT_1 (1<<0) -#define UNUSED_RESERVATION_TURF_1 (1<<1) -#define CAN_BE_DIRTY_1 (1<<2) // If a turf can be made dirty at roundstart. This is also used in areas. -#define NO_LAVA_GEN_1 (1<<6) //Blocks lava rivers being generated on the turf -#define NO_RUINS_1 (1<<10) //Blocks ruins spawning on the turf - -/* - These defines are used specifically with the atom/pass_flags bitmask - the atom/checkpass() proc uses them (tables will call movable atom checkpass(PASSTABLE) for example) -*/ -//flags for pass_flags -#define PASSTABLE (1<<0) -#define PASSGLASS (1<<1) -#define PASSGRILLE (1<<2) -#define PASSBLOB (1<<3) -#define PASSMOB (1<<4) -#define PASSCLOSEDTURF (1<<5) -#define LETPASSTHROW (1<<6) -#define PASSMACHINES (1<<7) -#define PASSCOMPUTER (1<<8) -#define PASSDOOR (1<<13) - -//Movement Types -#define GROUND (1<<0) -#define FLYING (1<<1) -#define VENTCRAWLING (1<<2) - -//Fire and Acid stuff, for resistance_flags -#define LAVA_PROOF (1<<0) -#define FIRE_PROOF (1<<1) //100% immune to fire damage (but not necessarily to lava or heat) -#define FLAMMABLE (1<<2) -#define ON_FIRE (1<<3) -#define UNACIDABLE (1<<4) //acid can't even appear on it, let alone melt it. -#define ACID_PROOF (1<<5) //acid stuck on it doesn't melt it. -#define INDESTRUCTIBLE (1<<6) //doesn't take damage -#define FREEZE_PROOF (1<<7) //can't be frozen -#define GOLIATH_RESISTANCE (1<<8) //CIT CHANGE -#define GOLIATH_WEAKNESS (1<<9) //CIT CHANGE - -//tesla_zap -#define TESLA_MACHINE_EXPLOSIVE (1<<0) -#define TESLA_ALLOW_DUPLICATES (1<<1) -#define TESLA_OBJ_DAMAGE (1<<2) -#define TESLA_MOB_DAMAGE (1<<3) -#define TESLA_MOB_STUN (1<<4) - -#define TESLA_DEFAULT_FLAGS ALL -#define TESLA_FUSION_FLAGS TESLA_OBJ_DAMAGE | TESLA_MOB_DAMAGE | TESLA_MOB_STUN - -//EMP protection -#define EMP_PROTECT_SELF (1<<0) -#define EMP_PROTECT_CONTENTS (1<<1) -#define EMP_PROTECT_WIRES (1<<2) - -// radiation -#define RAD_PROTECT_CONTENTS (1<<0) -#define RAD_NO_CONTAMINATE (1<<1) +/* + These defines are specific to the atom/flags_1 bitmask +*/ +#define ALL (~0) //For convenience. +#define NONE 0 + +//for convenience +#define ENABLE_BITFIELD(variable, flag) (variable |= (flag)) +#define DISABLE_BITFIELD(variable, flag) (variable &= ~(flag)) +#define CHECK_BITFIELD(variable, flag) (variable & (flag)) +#define TOGGLE_BITFIELD(variable, flag) (variable ^= (flag)) + +#define CHECK_MULTIPLE_BITFIELDS(flagvar, flags) (((flagvar) & (flags)) == (flags)) + +GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768)) + +// for /datum/var/datum_flags +#define DF_USE_TAG (1<<0) +#define DF_VAR_EDITED (1<<1) +#define DF_ISPROCESSING (1<<2) + +//FLAGS BITMASK + +#define HEAR_1 (1<<3) // This flag is what recursive_hear_check() uses to determine wether to add an item to the hearer list or not. +#define CHECK_RICOCHET_1 (1<<4) // Projectiels will check ricochet on things impacted that have this. +#define CONDUCT_1 (1<<5) // conducts electricity (metal etc.) +#define NODECONSTRUCT_1 (1<<7) // For machines and structures that should not break into parts, eg, holodeck stuff +#define OVERLAY_QUEUED_1 (1<<8) // atom queued to SSoverlay +#define ON_BORDER_1 (1<<9) // item has priority to check when entering or leaving +#define PREVENT_CLICK_UNDER_1 (1<<11) //Prevent clicking things below it on the same turf eg. doors/ fulltile windows +#define HOLOGRAM_1 (1<<12) +#define TESLA_IGNORE_1 (1<<13) // TESLA_IGNORE grants immunity from being targeted by tesla-style electricity +#define INITIALIZED_1 (1<<14) //Whether /atom/Initialize() has already run for the object +#define ADMIN_SPAWNED_1 (1<<15) //was this spawned by an admin? used for stat tracking stuff. +#define PREVENT_CONTENTS_EXPLOSION_1 (1<<16) /// should not get harmed if this gets caught by an explosion? + +//turf-only flags +#define NOJAUNT_1 (1<<0) +#define UNUSED_RESERVATION_TURF_1 (1<<1) +#define CAN_BE_DIRTY_1 (1<<2) // If a turf can be made dirty at roundstart. This is also used in areas. +#define NO_LAVA_GEN_1 (1<<6) //Blocks lava rivers being generated on the turf +#define NO_RUINS_1 (1<<10) //Blocks ruins spawning on the turf + +/* + These defines are used specifically with the atom/pass_flags bitmask + the atom/checkpass() proc uses them (tables will call movable atom checkpass(PASSTABLE) for example) +*/ +//flags for pass_flags +#define PASSTABLE (1<<0) +#define PASSGLASS (1<<1) +#define PASSGRILLE (1<<2) +#define PASSBLOB (1<<3) +#define PASSMOB (1<<4) +#define PASSCLOSEDTURF (1<<5) +#define LETPASSTHROW (1<<6) +#define PASSMACHINES (1<<7) +#define PASSCOMPUTER (1<<8) +#define PASSDOOR (1<<13) + +//Movement Types +#define GROUND (1<<0) +#define FLYING (1<<1) +#define VENTCRAWLING (1<<2) + +//Fire and Acid stuff, for resistance_flags +#define LAVA_PROOF (1<<0) +#define FIRE_PROOF (1<<1) //100% immune to fire damage (but not necessarily to lava or heat) +#define FLAMMABLE (1<<2) +#define ON_FIRE (1<<3) +#define UNACIDABLE (1<<4) //acid can't even appear on it, let alone melt it. +#define ACID_PROOF (1<<5) //acid stuck on it doesn't melt it. +#define INDESTRUCTIBLE (1<<6) //doesn't take damage +#define FREEZE_PROOF (1<<7) //can't be frozen +#define GOLIATH_RESISTANCE (1<<8) //CIT CHANGE +#define GOLIATH_WEAKNESS (1<<9) //CIT CHANGE + +//tesla_zap +#define TESLA_MACHINE_EXPLOSIVE (1<<0) +#define TESLA_ALLOW_DUPLICATES (1<<1) +#define TESLA_OBJ_DAMAGE (1<<2) +#define TESLA_MOB_DAMAGE (1<<3) +#define TESLA_MOB_STUN (1<<4) + +#define TESLA_DEFAULT_FLAGS ALL +#define TESLA_FUSION_FLAGS TESLA_OBJ_DAMAGE | TESLA_MOB_DAMAGE | TESLA_MOB_STUN + +//EMP protection +#define EMP_PROTECT_SELF (1<<0) +#define EMP_PROTECT_CONTENTS (1<<1) +#define EMP_PROTECT_WIRES (1<<2) + +// radiation +#define RAD_PROTECT_CONTENTS (1<<0) +#define RAD_NO_CONTAMINATE (1<<1) diff --git a/code/datums/explosion.dm b/code/datums/explosion.dm index b3c57e48..7be4489e 100644 --- a/code/datums/explosion.dm +++ b/code/datums/explosion.dm @@ -198,7 +198,7 @@ GLOBAL_LIST_EMPTY(explosions) var/list/items = list() for(var/I in T) var/atom/A = I - if (!A.prevent_content_explosion()) //The atom/contents_explosion() proc returns null if the contents ex_acting has been handled by the atom, and TRUE if it hasn't. + if (!(A.flags_1 & PREVENT_CONTENTS_EXPLOSION_1)) //The atom/contents_explosion() proc returns null if the contents ex_acting has been handled by the atom, and TRUE if it hasn't. items += A.GetAllContents() for(var/O in items) var/atom/A = O diff --git a/code/game/atoms.dm b/code/game/atoms.dm index c63c5b3e..7cd112ac 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1,877 +1,874 @@ -/atom - layer = TURF_LAYER - plane = GAME_PLANE - var/level = 2 - var/article // If non-null, overrides a/an/some in all cases - - var/flags_1 = NONE - var/interaction_flags_atom = NONE - var/datum/reagents/reagents = null - - //This atom's HUD (med/sec, etc) images. Associative list. - var/list/image/hud_list = null - //HUD images that this atom can provide. - var/list/hud_possible - - /// Last name used to calculate a color for the chatmessage overlays - var/chat_color_name - /// Last color calculated for the the chatmessage overlays - var/chat_color - /// A luminescence-shifted value of the last color calculated for chatmessage overlays - var/chat_color_darkened - - //Value used to increment ex_act() if reactionary_explosions is on - var/explosion_block = 0 - - var/list/atom_colours //used to store the different colors on an atom - //its inherent color, the colored paint applied on it, special color effect etc... - - var/list/priority_overlays //overlays that should remain on top and not normally removed when using cut_overlay functions, like c4. - var/list/remove_overlays // a very temporary list of overlays to remove - var/list/add_overlays // a very temporary list of overlays to add - - var/list/managed_vis_overlays //vis overlays managed by SSvis_overlays to automaticaly turn them like other overlays - var/list/managed_overlays - var/datum/proximity_monitor/proximity_monitor - var/buckle_message_cooldown = 0 - var/fingerprintslast - - var/list/filter_data //For handling persistent filters - - var/datum/component/orbiter/orbiters - - var/rad_flags = NONE // Will move to flags_1 when i can be arsed to - var/rad_insulation = RAD_NO_INSULATION - - var/icon/blood_splatter_icon - var/icon/cum_splatter_icon - var/list/fingerprints - var/list/fingerprintshidden - var/list/blood_DNA - var/list/suit_fibers - -/atom/New(loc, ...) - //atom creation method that preloads variables at creation - if(GLOB.use_preloader && (src.type == GLOB._preloader.target_path))//in case the instanciated atom is creating other atoms in New() - world.preloader_load(src) - - if(datum_flags & DF_USE_TAG) - GenerateTag() - - var/do_initialize = SSatoms.initialized - if(do_initialize != INITIALIZATION_INSSATOMS) - args[1] = do_initialize == INITIALIZATION_INNEW_MAPLOAD - if(SSatoms.InitAtom(src, args)) - //we were deleted - return - -//Called after New if the map is being loaded. mapload = TRUE -//Called from base of New if the map is not being loaded. mapload = FALSE -//This base must be called or derivatives must set initialized to TRUE -//must not sleep -//Other parameters are passed from New (excluding loc), this does not happen if mapload is TRUE -//Must return an Initialize hint. Defined in __DEFINES/subsystems.dm - -//Note: the following functions don't call the base for optimization and must copypasta: -// /turf/Initialize -// /turf/open/space/Initialize - -/atom/proc/Initialize(mapload, ...) - if(flags_1 & INITIALIZED_1) - stack_trace("Warning: [src]([type]) initialized multiple times!") - flags_1 |= INITIALIZED_1 - - //atom color stuff - if(color) - add_atom_colour(color, FIXED_COLOUR_PRIORITY) - - if (light_power && light_range) - update_light() - - if (opacity && isturf(loc)) - var/turf/T = loc - T.has_opaque_atom = TRUE // No need to recalculate it in this case, it's guaranteed to be on afterwards anyways. - - if (canSmoothWith) - canSmoothWith = typelist("canSmoothWith", canSmoothWith) - - ComponentInitialize() - - return INITIALIZE_HINT_NORMAL - -//called if Initialize returns INITIALIZE_HINT_LATELOAD -/atom/proc/LateInitialize() - return - -// Put your AddComponent() calls here -/atom/proc/ComponentInitialize() - return - -/atom/Destroy() - if(alternate_appearances) - for(var/K in alternate_appearances) - var/datum/atom_hud/alternate_appearance/AA = alternate_appearances[K] - AA.remove_from_hud(src) - - if(reagents) - qdel(reagents) - - LAZYCLEARLIST(overlays) - LAZYCLEARLIST(priority_overlays) - - QDEL_NULL(light) - - return ..() - -/atom/proc/handle_ricochet(obj/item/projectile/P) - return - -/atom/proc/CanPass(atom/movable/mover, turf/target) - return !density - -/atom/proc/onCentCom() - var/turf/T = get_turf(src) - if(!T) - return FALSE - - if(is_reserved_level(T.z)) - for(var/A in SSshuttle.mobile) - var/obj/docking_port/mobile/M = A - if(M.launch_status == ENDGAME_TRANSIT) - for(var/place in M.shuttle_areas) - var/area/shuttle/shuttle_area = place - if(T in shuttle_area) - return TRUE - - if(!is_centcom_level(T.z))//if not, don't bother - return FALSE - - //Check for centcom itself - if(istype(T.loc, /area/centcom)) - return TRUE - - //Check for centcom shuttles - for(var/A in SSshuttle.mobile) - var/obj/docking_port/mobile/M = A - if(M.launch_status == ENDGAME_LAUNCHED) - for(var/place in M.shuttle_areas) - var/area/shuttle/shuttle_area = place - if(T in shuttle_area) - return TRUE - -/atom/proc/onSyndieBase() - var/turf/T = get_turf(src) - if(!T) - return FALSE - - if(!is_centcom_level(T.z))//if not, don't bother - return FALSE - - if(istype(T.loc, /area/shuttle/syndicate) || istype(T.loc, /area/syndicate_mothership) || istype(T.loc, /area/shuttle/assault_pod)) - return TRUE - - return FALSE - -/atom/proc/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE) - SEND_SIGNAL(src, COMSIG_ATOM_HULK_ATTACK, user) - if(does_attack_animation) - user.changeNext_move(CLICK_CD_MELEE) - log_combat(user, src, "punched", "hulk powers") - user.do_attack_animation(src, ATTACK_EFFECT_SMASH) - -/atom/proc/CheckParts(list/parts_list) - for(var/A in parts_list) - if(istype(A, /datum/reagent)) - if(!reagents) - reagents = new() - reagents.reagent_list.Add(A) - reagents.conditional_update() - else if(ismovableatom(A)) - var/atom/movable/M = A - if(isliving(M.loc)) - var/mob/living/L = M.loc - L.transferItemToLoc(M, src) - else - M.forceMove(src) - -//common name -/atom/proc/update_multiz(prune_on_fail = FALSE) - return FALSE - -/atom/proc/assume_air(datum/gas_mixture/giver) - qdel(giver) - return null - -/atom/proc/remove_air(amount) - return null - -/atom/proc/return_air() - if(loc) - return loc.return_air() - else - return null - -/atom/proc/check_eye(mob/user) - return - -/atom/proc/Bumped(atom/movable/AM) - set waitfor = FALSE - -// Convenience procs to see if a container is open for chemistry handling -/atom/proc/is_open_container() - return is_refillable() && is_drainable() - -/atom/proc/is_injectable(allowmobs = TRUE) - return reagents && (reagents.reagents_holder_flags & (INJECTABLE | REFILLABLE)) - -/atom/proc/is_drawable(allowmobs = TRUE) - return reagents && (reagents.reagents_holder_flags & (DRAWABLE | DRAINABLE)) - -/atom/proc/is_refillable() - return reagents && (reagents.reagents_holder_flags & REFILLABLE) - -/atom/proc/is_drainable() - return reagents && (reagents.reagents_holder_flags & DRAINABLE) - - -/atom/proc/AllowDrop() - return FALSE - -/atom/proc/CheckExit() - return TRUE - -/atom/proc/HasProximity(atom/movable/AM as mob|obj) - return - -/atom/proc/emp_act(severity) - var/protection = SEND_SIGNAL(src, COMSIG_ATOM_EMP_ACT, severity) - if(!(protection & EMP_PROTECT_WIRES) && istype(wires)) - wires.emp_pulse() - return protection // Pass the protection value collected here upwards - -/atom/proc/bullet_act(obj/item/projectile/P, def_zone) - SEND_SIGNAL(src, COMSIG_ATOM_BULLET_ACT, P, def_zone) - . = P.on_hit(src, 0, def_zone) - -//used on altdisarm() for special interactions between the shoved victim (target) and the src, with user being the one shoving the target on it. -// IMPORTANT: if you wish to add a new own shove_act() to a certain object, remember to add SHOVABLE_ONTO to its obj_flags bitfied var first. -/atom/proc/shove_act(mob/living/target, mob/living/user) - return FALSE - -/atom/proc/in_contents_of(container)//can take class or object instance as argument - if(ispath(container)) - if(istype(src.loc, container)) - return TRUE - else if(src in container) - return TRUE - return FALSE - -/atom/proc/update_icon_state() - -/atom/proc/update_overlaysb() - SHOULD_CALL_PARENT(1) - . = list() - SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_OVERLAYS, .) - -/atom/proc/update_iconb() - var/signalOut = SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_ICON) - - if(!(signalOut & COMSIG_ATOM_NO_UPDATE_ICON_STATE)) - update_icon_state() - - if(!(signalOut & COMSIG_ATOM_NO_UPDATE_OVERLAYS)) - var/list/new_overlays = update_overlaysb() - if(managed_overlays) - cut_overlay(managed_overlays) - managed_overlays = null - if(length(new_overlays)) - managed_overlays = new_overlays - add_overlay(new_overlays) - -/atom/proc/get_examine_name(mob/user) - . = "\a [src]" - var/list/override = list(gender == PLURAL ? "some" : "a", " ", "[name]") - if(article) - . = "[article] [src]" - override[EXAMINE_POSITION_ARTICLE] = article - - var/should_override = FALSE - - if(SEND_SIGNAL(src, COMSIG_ATOM_GET_EXAMINE_NAME, user, override) & COMPONENT_EXNAME_CHANGED) - should_override = TRUE - - - if(blood_DNA && !istype(src, /obj/effect/decal)) - override[EXAMINE_POSITION_BEFORE] = " blood-stained " - should_override = TRUE - - if(should_override) - . = override.Join("") - -///Generate the full examine string of this atom (including icon for goonchat) -/atom/proc/get_examine_string(mob/user, thats = FALSE) - return "[icon2html(src, user)] [thats? "That's ":""][get_examine_name(user)]" - -/atom/proc/examine(mob/user) - . = list("[get_examine_string(user, TRUE)].") - - if(desc) - . += desc - - if(reagents) - if(reagents.reagents_holder_flags & TRANSPARENT) - . += "It contains:" - if(length(reagents.reagent_list)) - if(user.can_see_reagents()) //Show each individual reagent - for(var/datum/reagent/R in reagents.reagent_list) - . += "[R.volume] units of [R.name]" - else //Otherwise, just show the total volume - var/total_volume = 0 - for(var/datum/reagent/R in reagents.reagent_list) - total_volume += R.volume - . += "[total_volume] units of various reagents" - else - . += "Nothing." - else if(reagents.reagents_holder_flags & AMOUNT_VISIBLE) - if(reagents.total_volume) - . += "It has [reagents.total_volume] unit\s left." - else - . += "It's empty." - SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, .) - -/atom/proc/relaymove(mob/user) - if(buckle_message_cooldown <= world.time) - buckle_message_cooldown = world.time + 50 - to_chat(user, "You can't move while buckled to [src]!") - return - -/atom/proc/prevent_content_explosion() - return FALSE - -/atom/proc/contents_explosion(severity, target) - return //For handling the effects of explosions on contents that would not normally be effected - -/atom/proc/ex_act(severity, target) - set waitfor = FALSE - contents_explosion(severity, target) - SEND_SIGNAL(src, COMSIG_ATOM_EX_ACT, severity, target) - -/atom/proc/blob_act(obj/structure/blob/B) - SEND_SIGNAL(src, COMSIG_ATOM_BLOB_ACT, B) - return - -/atom/proc/fire_act(exposed_temperature, exposed_volume) - SEND_SIGNAL(src, COMSIG_ATOM_FIRE_ACT, exposed_temperature, exposed_volume) - return - -/atom/proc/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) - if(density && !has_gravity(AM)) //thrown stuff bounces off dense stuff in no grav, unless the thrown stuff ends up inside what it hit(embedding, bola, etc...). - addtimer(CALLBACK(src, .proc/hitby_react, AM), 2) - -/atom/proc/hitby_react(atom/movable/AM) - if(AM && isturf(AM.loc)) - step(AM, turn(AM.dir, 180)) - -/atom/proc/handle_slip(mob/living/carbon/C, knockdown_amount, obj/O, lube) - return - -//returns the mob's dna info as a list, to be inserted in an object's blood_DNA list -/mob/living/proc/get_blood_dna_list() - var/blood_id = get_blood_id() - if(!(blood_id in GLOB.blood_reagent_types)) - return - return list("ANIMAL DNA" = "Y-") - -/mob/living/carbon/get_blood_dna_list() - var/blood_id = get_blood_id() - if(!(blood_id in GLOB.blood_reagent_types)) - return - var/list/blood_dna = list() - if(dna) - blood_dna[dna.unique_enzymes] = dna.blood_type - else - blood_dna["UNKNOWN DNA"] = "X*" - return blood_dna - -/mob/living/carbon/alien/get_blood_dna_list() - return list("UNKNOWN DNA" = "X*") - -//to add a mob's dna info into an object's blood_DNA list. -/atom/proc/transfer_mob_blood_dna(mob/living/L) - // Returns 0 if we have that blood already - var/new_blood_dna = L.get_blood_dna_list() - if(!new_blood_dna) - return FALSE - LAZYINITLIST(blood_DNA) //if our list of DNA doesn't exist yet, initialise it. - var/old_length = blood_DNA.len - blood_DNA |= new_blood_dna - if(blood_DNA.len == old_length) - return FALSE - return TRUE - -//to add blood dna info to the object's blood_DNA list -/atom/proc/transfer_blood_dna(list/blood_dna, list/datum/disease/diseases) - LAZYINITLIST(blood_DNA) - var/old_length = blood_DNA.len - blood_DNA |= blood_dna - if(blood_DNA.len > old_length) - return TRUE - //some new blood DNA was added - -//to add blood from a mob onto something, and transfer their dna info -/atom/proc/add_mob_blood(mob/living/M) - var/list/blood_dna = M.get_blood_dna_list() - if(!blood_dna) - return FALSE - return add_blood_DNA(blood_dna, M.diseases) - -//to add blood onto something, with blood dna info to include. -/atom/proc/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) - return FALSE - -/obj/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) - return transfer_blood_dna(blood_dna, diseases) - -/obj/item/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) - . = ..() - if(!.) - return - add_blood_overlay() - -/obj/item/proc/add_blood_overlay() - if(!blood_DNA.len) - return - if(initial(icon) && initial(icon_state)) - blood_splatter_icon = icon(initial(icon), initial(icon_state), , 1) //we only want to apply blood-splatters to the initial icon_state for each object - blood_splatter_icon.Blend("#fff", ICON_ADD) //fills the icon_state with white (except where it's transparent) - blood_splatter_icon.Blend(icon('icons/effects/blood.dmi', "itemblood"), ICON_MULTIPLY) //adds blood and the remaining white areas become transparant - blood_splatter_icon.Blend(blood_DNA_to_color(), ICON_MULTIPLY) - add_overlay(blood_splatter_icon) - -/obj/item/clothing/gloves/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) - . = ..() - transfer_blood = rand(2, 4) - -/turf/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) - var/obj/effect/decal/cleanable/blood/splatter/B = locate() in src - if(!B) - B = new /obj/effect/decal/cleanable/blood/splatter(src, diseases) - B.transfer_blood_dna(blood_dna, diseases) //give blood info to the blood decal. - return TRUE //we bloodied the floor - -/mob/living/carbon/human/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) - if(head) - head.add_blood_DNA(blood_dna, diseases) - update_inv_head() - else if(wear_mask) - wear_mask.add_blood_DNA(blood_dna, diseases) - update_inv_wear_mask() - if(wear_neck) - wear_neck.add_blood_DNA(blood_dna, diseases) - update_inv_neck() - if(wear_suit) - wear_suit.add_blood_DNA(blood_dna, diseases) - update_inv_wear_suit() - else if(w_uniform) - w_uniform.add_blood_DNA(blood_dna, diseases) - update_inv_w_uniform() - if(gloves) - var/obj/item/clothing/gloves/G = gloves - G.add_blood_DNA(blood_dna, diseases) - else - transfer_blood_dna(blood_dna, diseases) - bloody_hands = rand(2, 4) - update_inv_gloves() //handles bloody hands overlays and updating - return TRUE - -/atom/proc/blood_DNA_to_color() - var/list/colors = list()//first we make a list of all bloodtypes present - for(var/bloop in blood_DNA) - if(colors[blood_DNA[bloop]]) - colors[blood_DNA[bloop]]++ - else - colors[blood_DNA[bloop]] = 1 - - var/final_rgb = BLOOD_COLOR_HUMAN //a default so we don't have white blood graphics if something messed up - - if(colors.len) - var/sum = 0 //this is all shitcode, but it works; trust me - final_rgb = bloodtype_to_color(colors[1]) - sum = colors[colors[1]] - if(colors.len > 1) - var/i = 2 - while(i <= colors.len) - var/tmp = colors[colors[i]] - final_rgb = BlendRGB(final_rgb, bloodtype_to_color(colors[i]), tmp/(tmp+sum)) - sum += tmp - i++ - - return final_rgb - -/atom/proc/clean_blood() - . = blood_DNA? TRUE : FALSE - blood_DNA = null - -/atom/proc/wash_cream() - return TRUE - -/atom/proc/isinspace() - if(isspaceturf(get_turf(src))) - return TRUE - else - return FALSE - -/atom/proc/handle_fall() - return - -/atom/proc/singularity_act() - return - -/atom/proc/singularity_pull(obj/singularity/S, current_size) - SEND_SIGNAL(src, COMSIG_ATOM_SING_PULL, S, current_size) - -/atom/proc/acid_act(acidpwr, acid_volume) - SEND_SIGNAL(src, COMSIG_ATOM_ACID_ACT, acidpwr, acid_volume) - -/atom/proc/emag_act() - SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT) - -/atom/proc/rad_act(strength) - SEND_SIGNAL(src, COMSIG_ATOM_RAD_ACT, strength) - -/atom/proc/narsie_act() - SEND_SIGNAL(src, COMSIG_ATOM_NARSIE_ACT) - -/atom/proc/ratvar_act() - SEND_SIGNAL(src, COMSIG_ATOM_RATVAR_ACT) - -/atom/proc/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) - return FALSE - -/atom/proc/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode) - SEND_SIGNAL(src, COMSIG_ATOM_RCD_ACT, user, the_rcd, passed_mode) - return FALSE - -/atom/proc/storage_contents_dump_act(obj/item/storage/src_object, mob/user) - if(GetComponent(/datum/component/storage)) - return component_storage_contents_dump_act(src_object, user) - return FALSE - -/atom/proc/component_storage_contents_dump_act(datum/component/storage/src_object, mob/user) - var/list/things = src_object.contents() - var/datum/progressbar/progress = new(user, things.len, src) - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - while (do_after(user, 10, TRUE, src, FALSE, CALLBACK(STR, /datum/component/storage.proc/handle_mass_item_insertion, things, src_object, user, progress))) - stoplag(1) - qdel(progress) - to_chat(user, "You dump as much of [src_object.parent]'s contents into [STR.insert_preposition]to [src] as you can.") - STR.orient2hud(user) - src_object.orient2hud(user) - if(user.active_storage) //refresh the HUD to show the transfered contents - user.active_storage.close(user) - user.active_storage.show_to(user) - return TRUE - -/atom/proc/get_dumping_location(obj/item/storage/source,mob/user) - return null - -//This proc is called on the location of an atom when the atom is Destroy()'d -/atom/proc/handle_atom_del(atom/A) - SEND_SIGNAL(src, COMSIG_ATOM_CONTENTS_DEL, A) - -//called when the turf the atom resides on is ChangeTurfed -/atom/proc/HandleTurfChange(turf/T) - for(var/a in src) - var/atom/A = a - A.HandleTurfChange(T) - -//the vision impairment to give to the mob whose perspective is set to that atom (e.g. an unfocused camera giving you an impaired vision when looking through it) -/atom/proc/get_remote_view_fullscreens(mob/user) - return - -//the sight changes to give to the mob whose perspective is set to that atom (e.g. A mob with nightvision loses its nightvision while looking through a normal camera) -/atom/proc/update_remote_sight(mob/living/user) - return - - -//Hook for running code when a dir change occurs -/atom/proc/setDir(newdir) - SEND_SIGNAL(src, COMSIG_ATOM_DIR_CHANGE, dir, newdir) - dir = newdir - -/atom/proc/mech_melee_attack(obj/mecha/M) - return - -//If a mob logouts/logins in side of an object you can use this proc -/atom/proc/on_log(login) - if(loc) - loc.on_log(login) - - -/* - Atom Colour Priority System - A System that gives finer control over which atom colour to colour the atom with. - The "highest priority" one is always displayed as opposed to the default of - "whichever was set last is displayed" -*/ - - -/* - Adds an instance of colour_type to the atom's atom_colours list -*/ -/atom/proc/add_atom_colour(coloration, colour_priority) - if(!atom_colours || !atom_colours.len) - atom_colours = list() - atom_colours.len = COLOUR_PRIORITY_AMOUNT //four priority levels currently. - if(!coloration) - return - if(colour_priority > atom_colours.len) - return - atom_colours[colour_priority] = coloration - update_atom_colour() - - -/* - Removes an instance of colour_type from the atom's atom_colours list -*/ -/atom/proc/remove_atom_colour(colour_priority, coloration) - if(!atom_colours) - atom_colours = list() - atom_colours.len = COLOUR_PRIORITY_AMOUNT //four priority levels currently. - if(colour_priority > atom_colours.len) - return - if(coloration && atom_colours[colour_priority] != coloration) - return //if we don't have the expected color (for a specific priority) to remove, do nothing - atom_colours[colour_priority] = null - update_atom_colour() - - -/* - Resets the atom's color to null, and then sets it to the highest priority - colour available -*/ -/atom/proc/update_atom_colour() - if(!atom_colours) - atom_colours = list() - atom_colours.len = COLOUR_PRIORITY_AMOUNT //four priority levels currently. - color = null - for(var/C in atom_colours) - if(islist(C)) - var/list/L = C - if(L.len) - color = L - return - else if(C) - color = C - return - -/atom/vv_edit_var(var_name, var_value) - if(!GLOB.Debug2) - flags_1 |= ADMIN_SPAWNED_1 - . = ..() - switch(var_name) - if("color") - add_atom_colour(color, ADMIN_COLOUR_PRIORITY) - -/atom/vv_get_dropdown() - . = ..() - . += "---" - var/turf/curturf = get_turf(src) - if (curturf) - .["Jump to"] = "?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[curturf.x];Y=[curturf.y];Z=[curturf.z]" - .["Modify Transform"] = "?_src_=vars;[HrefToken()];modtransform=[REF(src)]" - .["Add reagent"] = "?_src_=vars;[HrefToken()];addreagent=[REF(src)]" - .["Trigger EM pulse"] = "?_src_=vars;[HrefToken()];emp=[REF(src)]" - .["Trigger explosion"] = "?_src_=vars;[HrefToken()];explode=[REF(src)]" - -/atom/proc/drop_location() - var/atom/L = loc - if(!L) - return null - return L.AllowDrop() ? L : L.drop_location() - -/atom/Entered(atom/movable/AM, atom/oldLoc) - SEND_SIGNAL(src, COMSIG_ATOM_ENTERED, AM, oldLoc) - -/atom/Exit(atom/movable/AM, atom/newLoc) - . = ..() - if(SEND_SIGNAL(src, COMSIG_ATOM_EXIT, AM, newLoc) & COMPONENT_ATOM_BLOCK_EXIT) - return FALSE - -/atom/Exited(atom/movable/AM, atom/newLoc) - SEND_SIGNAL(src, COMSIG_ATOM_EXITED, AM, newLoc) - -/atom/proc/return_temperature() - return - -// Tool behavior procedure. Redirects to tool-specific procs by default. -// You can override it to catch all tool interactions, for use in complex deconstruction procs. -// Just don't forget to return ..() in the end. -/atom/proc/tool_act(mob/living/user, obj/item/I, tool_type) - switch(tool_type) - if(TOOL_CROWBAR) - return crowbar_act(user, I) - if(TOOL_MULTITOOL) - return multitool_act(user, I) - if(TOOL_SCREWDRIVER) - return screwdriver_act(user, I) - if(TOOL_WRENCH) - return wrench_act(user, I) - if(TOOL_WIRECUTTER) - return wirecutter_act(user, I) - if(TOOL_WELDER) - return welder_act(user, I) - if(TOOL_ANALYZER) - return analyzer_act(user, I) - -// Tool-specific behavior procs. To be overridden in subtypes. -/atom/proc/crowbar_act(mob/living/user, obj/item/I) - return - -/atom/proc/multitool_act(mob/living/user, obj/item/I) - return - -/atom/proc/multitool_check_buffer(user, obj/item/I, silent = FALSE) - if(!istype(I, /obj/item/multitool)) - if(user && !silent) - to_chat(user, "[I] has no data buffer!") - return FALSE - return TRUE - -/atom/proc/screwdriver_act(mob/living/user, obj/item/I) - SEND_SIGNAL(src, COMSIG_ATOM_SCREWDRIVER_ACT, user, I) - -/atom/proc/wrench_act(mob/living/user, obj/item/I) - return - -/atom/proc/wirecutter_act(mob/living/user, obj/item/I) - return - -/atom/proc/welder_act(mob/living/user, obj/item/I) - return - -/atom/proc/analyzer_act(mob/living/user, obj/item/I) - return - -/atom/proc/GenerateTag() - return - -// Generic logging helper -/atom/proc/log_message(message, message_type, color=null, log_globally=TRUE) - if(!log_globally) - return - - var/log_text = "[key_name(src)] [message] [loc_name(src)]" - switch(message_type) - if(LOG_ATTACK) - log_attack(log_text) - if(LOG_SAY) - log_say(log_text) - if(LOG_WHISPER) - log_whisper(log_text) - if(LOG_EMOTE) - log_emote(log_text) - if(LOG_DSAY) - log_dsay(log_text) - if(LOG_PDA) - log_pda(log_text) - if(LOG_CHAT) - log_chat(log_text) - if(LOG_COMMENT) - log_comment(log_text) - if(LOG_TELECOMMS) - log_telecomms(log_text) - if(LOG_OOC) - log_ooc(log_text) - if(LOG_ADMIN) - log_admin(log_text) - if(LOG_ADMIN_PRIVATE) - log_admin_private(log_text) - if(LOG_ASAY) - log_adminsay(log_text) - if(LOG_OWNERSHIP) - log_game(log_text) - if(LOG_GAME) - log_game(log_text) - else - stack_trace("Invalid individual logging type: [message_type]. Defaulting to [LOG_GAME] (LOG_GAME).") - log_game(log_text) - -// Helper for logging chat messages or other logs with arbitrary inputs (e.g. announcements) -/atom/proc/log_talk(message, message_type, tag=null, log_globally=TRUE, forced_by=null) - var/prefix = tag ? "([tag]) " : "" - var/suffix = forced_by ? " FORCED by [forced_by]" : "" - log_message("[prefix]\"[message]\"[suffix]", message_type, log_globally=log_globally) - -// Helper for logging of messages with only one sender and receiver -/proc/log_directed_talk(atom/source, atom/target, message, message_type, tag) - if(!tag) - stack_trace("Unspecified tag for private message") - tag = "UNKNOWN" - - source.log_talk(message, message_type, tag="[tag] to [key_name(target)]") - if(source != target) - target.log_talk(message, message_type, tag="[tag] from [key_name(source)]", log_globally=FALSE) - -/* -Proc for attack log creation, because really why not -1 argument is the actor performing the action -2 argument is the target of the action -3 is a verb describing the action (e.g. punched, throwed, kicked, etc.) -4 is a tool with which the action was made (usually an item) -5 is any additional text, which will be appended to the rest of the log line -*/ - -/proc/log_combat(atom/user, atom/target, what_done, atom/object=null, addition=null) - var/ssource = key_name(user) - var/starget = key_name(target) - - var/mob/living/living_target = target - var/hp = istype(living_target) ? " (NEWHP: [living_target.health]) " : "" - - var/sobject = "" - if(object) - sobject = " with [key_name(object)]" - var/saddition = "" - if(addition) - saddition = " [addition]" - - var/postfix = "[sobject][saddition][hp]" - - var/message = "has [what_done] [starget][postfix]" - user.log_message(message, LOG_ATTACK, color="red") - - if(user != target) - var/reverse_message = "has been [what_done] by [ssource][postfix]" - target.log_message(reverse_message, LOG_ATTACK, color="orange", log_globally=FALSE) - -// Filter stuff -/atom/movable/proc/add_filter(name,priority,list/params) - if(!filter_data) - filter_data = list() - var/list/p = params.Copy() - p["priority"] = priority - filter_data[name] = p - update_filters() - -/atom/movable/proc/update_filters() - filters = null - sortTim(filter_data,associative = TRUE) - for(var/f in filter_data) - var/list/data = filter_data[f] - var/list/arguments = data.Copy() - arguments -= "priority" - filters += filter(arglist(arguments)) - -/atom/movable/proc/get_filter(name) - if(filter_data && filter_data[name]) - return filters[filter_data.Find(name)] - -/atom/movable/proc/remove_filter(name) - if(filter_data[name]) - filter_data -= name - update_filters() - return TRUE - -/atom/proc/intercept_zImpact(atom/movable/AM, levels = 1) - . |= SEND_SIGNAL(src, COMSIG_ATOM_INTERCEPT_Z_FALL, AM, levels) +/atom + layer = TURF_LAYER + plane = GAME_PLANE + var/level = 2 + var/article // If non-null, overrides a/an/some in all cases + + var/flags_1 = NONE + var/interaction_flags_atom = NONE + var/datum/reagents/reagents = null + + //This atom's HUD (med/sec, etc) images. Associative list. + var/list/image/hud_list = null + //HUD images that this atom can provide. + var/list/hud_possible + + /// Last name used to calculate a color for the chatmessage overlays + var/chat_color_name + /// Last color calculated for the the chatmessage overlays + var/chat_color + /// A luminescence-shifted value of the last color calculated for chatmessage overlays + var/chat_color_darkened + + //Value used to increment ex_act() if reactionary_explosions is on + var/explosion_block = 0 + + var/list/atom_colours //used to store the different colors on an atom + //its inherent color, the colored paint applied on it, special color effect etc... + + var/list/priority_overlays //overlays that should remain on top and not normally removed when using cut_overlay functions, like c4. + var/list/remove_overlays // a very temporary list of overlays to remove + var/list/add_overlays // a very temporary list of overlays to add + + var/list/managed_vis_overlays //vis overlays managed by SSvis_overlays to automaticaly turn them like other overlays + var/list/managed_overlays + var/datum/proximity_monitor/proximity_monitor + var/buckle_message_cooldown = 0 + var/fingerprintslast + + var/list/filter_data //For handling persistent filters + + var/datum/component/orbiter/orbiters + + var/rad_flags = NONE // Will move to flags_1 when i can be arsed to + var/rad_insulation = RAD_NO_INSULATION + + var/icon/blood_splatter_icon + var/icon/cum_splatter_icon + var/list/fingerprints + var/list/fingerprintshidden + var/list/blood_DNA + var/list/suit_fibers + +/atom/New(loc, ...) + //atom creation method that preloads variables at creation + if(GLOB.use_preloader && (src.type == GLOB._preloader.target_path))//in case the instanciated atom is creating other atoms in New() + world.preloader_load(src) + + if(datum_flags & DF_USE_TAG) + GenerateTag() + + var/do_initialize = SSatoms.initialized + if(do_initialize != INITIALIZATION_INSSATOMS) + args[1] = do_initialize == INITIALIZATION_INNEW_MAPLOAD + if(SSatoms.InitAtom(src, args)) + //we were deleted + return + +//Called after New if the map is being loaded. mapload = TRUE +//Called from base of New if the map is not being loaded. mapload = FALSE +//This base must be called or derivatives must set initialized to TRUE +//must not sleep +//Other parameters are passed from New (excluding loc), this does not happen if mapload is TRUE +//Must return an Initialize hint. Defined in __DEFINES/subsystems.dm + +//Note: the following functions don't call the base for optimization and must copypasta: +// /turf/Initialize +// /turf/open/space/Initialize + +/atom/proc/Initialize(mapload, ...) + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 + + //atom color stuff + if(color) + add_atom_colour(color, FIXED_COLOUR_PRIORITY) + + if (light_power && light_range) + update_light() + + if (opacity && isturf(loc)) + var/turf/T = loc + T.has_opaque_atom = TRUE // No need to recalculate it in this case, it's guaranteed to be on afterwards anyways. + + if (canSmoothWith) + canSmoothWith = typelist("canSmoothWith", canSmoothWith) + + ComponentInitialize() + + return INITIALIZE_HINT_NORMAL + +//called if Initialize returns INITIALIZE_HINT_LATELOAD +/atom/proc/LateInitialize() + return + +// Put your AddComponent() calls here +/atom/proc/ComponentInitialize() + return + +/atom/Destroy() + if(alternate_appearances) + for(var/K in alternate_appearances) + var/datum/atom_hud/alternate_appearance/AA = alternate_appearances[K] + AA.remove_from_hud(src) + + if(reagents) + qdel(reagents) + + LAZYCLEARLIST(overlays) + LAZYCLEARLIST(priority_overlays) + + QDEL_NULL(light) + + return ..() + +/atom/proc/handle_ricochet(obj/item/projectile/P) + return + +/atom/proc/CanPass(atom/movable/mover, turf/target) + return !density + +/atom/proc/onCentCom() + var/turf/T = get_turf(src) + if(!T) + return FALSE + + if(is_reserved_level(T.z)) + for(var/A in SSshuttle.mobile) + var/obj/docking_port/mobile/M = A + if(M.launch_status == ENDGAME_TRANSIT) + for(var/place in M.shuttle_areas) + var/area/shuttle/shuttle_area = place + if(T in shuttle_area) + return TRUE + + if(!is_centcom_level(T.z))//if not, don't bother + return FALSE + + //Check for centcom itself + if(istype(T.loc, /area/centcom)) + return TRUE + + //Check for centcom shuttles + for(var/A in SSshuttle.mobile) + var/obj/docking_port/mobile/M = A + if(M.launch_status == ENDGAME_LAUNCHED) + for(var/place in M.shuttle_areas) + var/area/shuttle/shuttle_area = place + if(T in shuttle_area) + return TRUE + +/atom/proc/onSyndieBase() + var/turf/T = get_turf(src) + if(!T) + return FALSE + + if(!is_centcom_level(T.z))//if not, don't bother + return FALSE + + if(istype(T.loc, /area/shuttle/syndicate) || istype(T.loc, /area/syndicate_mothership) || istype(T.loc, /area/shuttle/assault_pod)) + return TRUE + + return FALSE + +/atom/proc/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE) + SEND_SIGNAL(src, COMSIG_ATOM_HULK_ATTACK, user) + if(does_attack_animation) + user.changeNext_move(CLICK_CD_MELEE) + log_combat(user, src, "punched", "hulk powers") + user.do_attack_animation(src, ATTACK_EFFECT_SMASH) + +/atom/proc/CheckParts(list/parts_list) + for(var/A in parts_list) + if(istype(A, /datum/reagent)) + if(!reagents) + reagents = new() + reagents.reagent_list.Add(A) + reagents.conditional_update() + else if(ismovableatom(A)) + var/atom/movable/M = A + if(isliving(M.loc)) + var/mob/living/L = M.loc + L.transferItemToLoc(M, src) + else + M.forceMove(src) + +//common name +/atom/proc/update_multiz(prune_on_fail = FALSE) + return FALSE + +/atom/proc/assume_air(datum/gas_mixture/giver) + qdel(giver) + return null + +/atom/proc/remove_air(amount) + return null + +/atom/proc/return_air() + if(loc) + return loc.return_air() + else + return null + +/atom/proc/check_eye(mob/user) + return + +/atom/proc/Bumped(atom/movable/AM) + set waitfor = FALSE + +// Convenience procs to see if a container is open for chemistry handling +/atom/proc/is_open_container() + return is_refillable() && is_drainable() + +/atom/proc/is_injectable(allowmobs = TRUE) + return reagents && (reagents.reagents_holder_flags & (INJECTABLE | REFILLABLE)) + +/atom/proc/is_drawable(allowmobs = TRUE) + return reagents && (reagents.reagents_holder_flags & (DRAWABLE | DRAINABLE)) + +/atom/proc/is_refillable() + return reagents && (reagents.reagents_holder_flags & REFILLABLE) + +/atom/proc/is_drainable() + return reagents && (reagents.reagents_holder_flags & DRAINABLE) + + +/atom/proc/AllowDrop() + return FALSE + +/atom/proc/CheckExit() + return TRUE + +/atom/proc/HasProximity(atom/movable/AM as mob|obj) + return + +/atom/proc/emp_act(severity) + var/protection = SEND_SIGNAL(src, COMSIG_ATOM_EMP_ACT, severity) + if(!(protection & EMP_PROTECT_WIRES) && istype(wires)) + wires.emp_pulse() + return protection // Pass the protection value collected here upwards + +/atom/proc/bullet_act(obj/item/projectile/P, def_zone) + SEND_SIGNAL(src, COMSIG_ATOM_BULLET_ACT, P, def_zone) + . = P.on_hit(src, 0, def_zone) + +//used on altdisarm() for special interactions between the shoved victim (target) and the src, with user being the one shoving the target on it. +// IMPORTANT: if you wish to add a new own shove_act() to a certain object, remember to add SHOVABLE_ONTO to its obj_flags bitfied var first. +/atom/proc/shove_act(mob/living/target, mob/living/user) + return FALSE + +/atom/proc/in_contents_of(container)//can take class or object instance as argument + if(ispath(container)) + if(istype(src.loc, container)) + return TRUE + else if(src in container) + return TRUE + return FALSE + +/atom/proc/update_icon_state() + +/atom/proc/update_overlaysb() + SHOULD_CALL_PARENT(1) + . = list() + SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_OVERLAYS, .) + +/atom/proc/update_iconb() + var/signalOut = SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_ICON) + + if(!(signalOut & COMSIG_ATOM_NO_UPDATE_ICON_STATE)) + update_icon_state() + + if(!(signalOut & COMSIG_ATOM_NO_UPDATE_OVERLAYS)) + var/list/new_overlays = update_overlaysb() + if(managed_overlays) + cut_overlay(managed_overlays) + managed_overlays = null + if(length(new_overlays)) + managed_overlays = new_overlays + add_overlay(new_overlays) + +/atom/proc/get_examine_name(mob/user) + . = "\a [src]" + var/list/override = list(gender == PLURAL ? "some" : "a", " ", "[name]") + if(article) + . = "[article] [src]" + override[EXAMINE_POSITION_ARTICLE] = article + + var/should_override = FALSE + + if(SEND_SIGNAL(src, COMSIG_ATOM_GET_EXAMINE_NAME, user, override) & COMPONENT_EXNAME_CHANGED) + should_override = TRUE + + + if(blood_DNA && !istype(src, /obj/effect/decal)) + override[EXAMINE_POSITION_BEFORE] = " blood-stained " + should_override = TRUE + + if(should_override) + . = override.Join("") + +///Generate the full examine string of this atom (including icon for goonchat) +/atom/proc/get_examine_string(mob/user, thats = FALSE) + return "[icon2html(src, user)] [thats? "That's ":""][get_examine_name(user)]" + +/atom/proc/examine(mob/user) + . = list("[get_examine_string(user, TRUE)].") + + if(desc) + . += desc + + if(reagents) + if(reagents.reagents_holder_flags & TRANSPARENT) + . += "It contains:" + if(length(reagents.reagent_list)) + if(user.can_see_reagents()) //Show each individual reagent + for(var/datum/reagent/R in reagents.reagent_list) + . += "[R.volume] units of [R.name]" + else //Otherwise, just show the total volume + var/total_volume = 0 + for(var/datum/reagent/R in reagents.reagent_list) + total_volume += R.volume + . += "[total_volume] units of various reagents" + else + . += "Nothing." + else if(reagents.reagents_holder_flags & AMOUNT_VISIBLE) + if(reagents.total_volume) + . += "It has [reagents.total_volume] unit\s left." + else + . += "It's empty." + SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, .) + +/atom/proc/relaymove(mob/user) + if(buckle_message_cooldown <= world.time) + buckle_message_cooldown = world.time + 50 + to_chat(user, "You can't move while buckled to [src]!") + return + +/atom/proc/contents_explosion(severity, target) + return //For handling the effects of explosions on contents that would not normally be effected + +/atom/proc/ex_act(severity, target) + set waitfor = FALSE + contents_explosion(severity, target) + SEND_SIGNAL(src, COMSIG_ATOM_EX_ACT, severity, target) + +/atom/proc/blob_act(obj/structure/blob/B) + SEND_SIGNAL(src, COMSIG_ATOM_BLOB_ACT, B) + return + +/atom/proc/fire_act(exposed_temperature, exposed_volume) + SEND_SIGNAL(src, COMSIG_ATOM_FIRE_ACT, exposed_temperature, exposed_volume) + return + +/atom/proc/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) + if(density && !has_gravity(AM)) //thrown stuff bounces off dense stuff in no grav, unless the thrown stuff ends up inside what it hit(embedding, bola, etc...). + addtimer(CALLBACK(src, .proc/hitby_react, AM), 2) + +/atom/proc/hitby_react(atom/movable/AM) + if(AM && isturf(AM.loc)) + step(AM, turn(AM.dir, 180)) + +/atom/proc/handle_slip(mob/living/carbon/C, knockdown_amount, obj/O, lube) + return + +//returns the mob's dna info as a list, to be inserted in an object's blood_DNA list +/mob/living/proc/get_blood_dna_list() + var/blood_id = get_blood_id() + if(!(blood_id in GLOB.blood_reagent_types)) + return + return list("ANIMAL DNA" = "Y-") + +/mob/living/carbon/get_blood_dna_list() + var/blood_id = get_blood_id() + if(!(blood_id in GLOB.blood_reagent_types)) + return + var/list/blood_dna = list() + if(dna) + blood_dna[dna.unique_enzymes] = dna.blood_type + else + blood_dna["UNKNOWN DNA"] = "X*" + return blood_dna + +/mob/living/carbon/alien/get_blood_dna_list() + return list("UNKNOWN DNA" = "X*") + +//to add a mob's dna info into an object's blood_DNA list. +/atom/proc/transfer_mob_blood_dna(mob/living/L) + // Returns 0 if we have that blood already + var/new_blood_dna = L.get_blood_dna_list() + if(!new_blood_dna) + return FALSE + LAZYINITLIST(blood_DNA) //if our list of DNA doesn't exist yet, initialise it. + var/old_length = blood_DNA.len + blood_DNA |= new_blood_dna + if(blood_DNA.len == old_length) + return FALSE + return TRUE + +//to add blood dna info to the object's blood_DNA list +/atom/proc/transfer_blood_dna(list/blood_dna, list/datum/disease/diseases) + LAZYINITLIST(blood_DNA) + var/old_length = blood_DNA.len + blood_DNA |= blood_dna + if(blood_DNA.len > old_length) + return TRUE + //some new blood DNA was added + +//to add blood from a mob onto something, and transfer their dna info +/atom/proc/add_mob_blood(mob/living/M) + var/list/blood_dna = M.get_blood_dna_list() + if(!blood_dna) + return FALSE + return add_blood_DNA(blood_dna, M.diseases) + +//to add blood onto something, with blood dna info to include. +/atom/proc/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) + return FALSE + +/obj/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) + return transfer_blood_dna(blood_dna, diseases) + +/obj/item/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) + . = ..() + if(!.) + return + add_blood_overlay() + +/obj/item/proc/add_blood_overlay() + if(!blood_DNA.len) + return + if(initial(icon) && initial(icon_state)) + blood_splatter_icon = icon(initial(icon), initial(icon_state), , 1) //we only want to apply blood-splatters to the initial icon_state for each object + blood_splatter_icon.Blend("#fff", ICON_ADD) //fills the icon_state with white (except where it's transparent) + blood_splatter_icon.Blend(icon('icons/effects/blood.dmi', "itemblood"), ICON_MULTIPLY) //adds blood and the remaining white areas become transparant + blood_splatter_icon.Blend(blood_DNA_to_color(), ICON_MULTIPLY) + add_overlay(blood_splatter_icon) + +/obj/item/clothing/gloves/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) + . = ..() + transfer_blood = rand(2, 4) + +/turf/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) + var/obj/effect/decal/cleanable/blood/splatter/B = locate() in src + if(!B) + B = new /obj/effect/decal/cleanable/blood/splatter(src, diseases) + B.transfer_blood_dna(blood_dna, diseases) //give blood info to the blood decal. + return TRUE //we bloodied the floor + +/mob/living/carbon/human/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) + if(head) + head.add_blood_DNA(blood_dna, diseases) + update_inv_head() + else if(wear_mask) + wear_mask.add_blood_DNA(blood_dna, diseases) + update_inv_wear_mask() + if(wear_neck) + wear_neck.add_blood_DNA(blood_dna, diseases) + update_inv_neck() + if(wear_suit) + wear_suit.add_blood_DNA(blood_dna, diseases) + update_inv_wear_suit() + else if(w_uniform) + w_uniform.add_blood_DNA(blood_dna, diseases) + update_inv_w_uniform() + if(gloves) + var/obj/item/clothing/gloves/G = gloves + G.add_blood_DNA(blood_dna, diseases) + else + transfer_blood_dna(blood_dna, diseases) + bloody_hands = rand(2, 4) + update_inv_gloves() //handles bloody hands overlays and updating + return TRUE + +/atom/proc/blood_DNA_to_color() + var/list/colors = list()//first we make a list of all bloodtypes present + for(var/bloop in blood_DNA) + if(colors[blood_DNA[bloop]]) + colors[blood_DNA[bloop]]++ + else + colors[blood_DNA[bloop]] = 1 + + var/final_rgb = BLOOD_COLOR_HUMAN //a default so we don't have white blood graphics if something messed up + + if(colors.len) + var/sum = 0 //this is all shitcode, but it works; trust me + final_rgb = bloodtype_to_color(colors[1]) + sum = colors[colors[1]] + if(colors.len > 1) + var/i = 2 + while(i <= colors.len) + var/tmp = colors[colors[i]] + final_rgb = BlendRGB(final_rgb, bloodtype_to_color(colors[i]), tmp/(tmp+sum)) + sum += tmp + i++ + + return final_rgb + +/atom/proc/clean_blood() + . = blood_DNA? TRUE : FALSE + blood_DNA = null + +/atom/proc/wash_cream() + return TRUE + +/atom/proc/isinspace() + if(isspaceturf(get_turf(src))) + return TRUE + else + return FALSE + +/atom/proc/handle_fall() + return + +/atom/proc/singularity_act() + return + +/atom/proc/singularity_pull(obj/singularity/S, current_size) + SEND_SIGNAL(src, COMSIG_ATOM_SING_PULL, S, current_size) + +/atom/proc/acid_act(acidpwr, acid_volume) + SEND_SIGNAL(src, COMSIG_ATOM_ACID_ACT, acidpwr, acid_volume) + +/atom/proc/emag_act() + SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT) + +/atom/proc/rad_act(strength) + SEND_SIGNAL(src, COMSIG_ATOM_RAD_ACT, strength) + +/atom/proc/narsie_act() + SEND_SIGNAL(src, COMSIG_ATOM_NARSIE_ACT) + +/atom/proc/ratvar_act() + SEND_SIGNAL(src, COMSIG_ATOM_RATVAR_ACT) + +/atom/proc/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) + return FALSE + +/atom/proc/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode) + SEND_SIGNAL(src, COMSIG_ATOM_RCD_ACT, user, the_rcd, passed_mode) + return FALSE + +/atom/proc/storage_contents_dump_act(obj/item/storage/src_object, mob/user) + if(GetComponent(/datum/component/storage)) + return component_storage_contents_dump_act(src_object, user) + return FALSE + +/atom/proc/component_storage_contents_dump_act(datum/component/storage/src_object, mob/user) + var/list/things = src_object.contents() + var/datum/progressbar/progress = new(user, things.len, src) + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + while (do_after(user, 10, TRUE, src, FALSE, CALLBACK(STR, /datum/component/storage.proc/handle_mass_item_insertion, things, src_object, user, progress))) + stoplag(1) + qdel(progress) + to_chat(user, "You dump as much of [src_object.parent]'s contents into [STR.insert_preposition]to [src] as you can.") + STR.orient2hud(user) + src_object.orient2hud(user) + if(user.active_storage) //refresh the HUD to show the transfered contents + user.active_storage.close(user) + user.active_storage.show_to(user) + return TRUE + +/atom/proc/get_dumping_location(obj/item/storage/source,mob/user) + return null + +//This proc is called on the location of an atom when the atom is Destroy()'d +/atom/proc/handle_atom_del(atom/A) + SEND_SIGNAL(src, COMSIG_ATOM_CONTENTS_DEL, A) + +//called when the turf the atom resides on is ChangeTurfed +/atom/proc/HandleTurfChange(turf/T) + for(var/a in src) + var/atom/A = a + A.HandleTurfChange(T) + +//the vision impairment to give to the mob whose perspective is set to that atom (e.g. an unfocused camera giving you an impaired vision when looking through it) +/atom/proc/get_remote_view_fullscreens(mob/user) + return + +//the sight changes to give to the mob whose perspective is set to that atom (e.g. A mob with nightvision loses its nightvision while looking through a normal camera) +/atom/proc/update_remote_sight(mob/living/user) + return + + +//Hook for running code when a dir change occurs +/atom/proc/setDir(newdir) + SEND_SIGNAL(src, COMSIG_ATOM_DIR_CHANGE, dir, newdir) + dir = newdir + +/atom/proc/mech_melee_attack(obj/mecha/M) + return + +//If a mob logouts/logins in side of an object you can use this proc +/atom/proc/on_log(login) + if(loc) + loc.on_log(login) + + +/* + Atom Colour Priority System + A System that gives finer control over which atom colour to colour the atom with. + The "highest priority" one is always displayed as opposed to the default of + "whichever was set last is displayed" +*/ + + +/* + Adds an instance of colour_type to the atom's atom_colours list +*/ +/atom/proc/add_atom_colour(coloration, colour_priority) + if(!atom_colours || !atom_colours.len) + atom_colours = list() + atom_colours.len = COLOUR_PRIORITY_AMOUNT //four priority levels currently. + if(!coloration) + return + if(colour_priority > atom_colours.len) + return + atom_colours[colour_priority] = coloration + update_atom_colour() + + +/* + Removes an instance of colour_type from the atom's atom_colours list +*/ +/atom/proc/remove_atom_colour(colour_priority, coloration) + if(!atom_colours) + atom_colours = list() + atom_colours.len = COLOUR_PRIORITY_AMOUNT //four priority levels currently. + if(colour_priority > atom_colours.len) + return + if(coloration && atom_colours[colour_priority] != coloration) + return //if we don't have the expected color (for a specific priority) to remove, do nothing + atom_colours[colour_priority] = null + update_atom_colour() + + +/* + Resets the atom's color to null, and then sets it to the highest priority + colour available +*/ +/atom/proc/update_atom_colour() + if(!atom_colours) + atom_colours = list() + atom_colours.len = COLOUR_PRIORITY_AMOUNT //four priority levels currently. + color = null + for(var/C in atom_colours) + if(islist(C)) + var/list/L = C + if(L.len) + color = L + return + else if(C) + color = C + return + +/atom/vv_edit_var(var_name, var_value) + if(!GLOB.Debug2) + flags_1 |= ADMIN_SPAWNED_1 + . = ..() + switch(var_name) + if("color") + add_atom_colour(color, ADMIN_COLOUR_PRIORITY) + +/atom/vv_get_dropdown() + . = ..() + . += "---" + var/turf/curturf = get_turf(src) + if (curturf) + .["Jump to"] = "?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[curturf.x];Y=[curturf.y];Z=[curturf.z]" + .["Modify Transform"] = "?_src_=vars;[HrefToken()];modtransform=[REF(src)]" + .["Add reagent"] = "?_src_=vars;[HrefToken()];addreagent=[REF(src)]" + .["Trigger EM pulse"] = "?_src_=vars;[HrefToken()];emp=[REF(src)]" + .["Trigger explosion"] = "?_src_=vars;[HrefToken()];explode=[REF(src)]" + +/atom/proc/drop_location() + var/atom/L = loc + if(!L) + return null + return L.AllowDrop() ? L : L.drop_location() + +/atom/Entered(atom/movable/AM, atom/oldLoc) + SEND_SIGNAL(src, COMSIG_ATOM_ENTERED, AM, oldLoc) + +/atom/Exit(atom/movable/AM, atom/newLoc) + . = ..() + if(SEND_SIGNAL(src, COMSIG_ATOM_EXIT, AM, newLoc) & COMPONENT_ATOM_BLOCK_EXIT) + return FALSE + +/atom/Exited(atom/movable/AM, atom/newLoc) + SEND_SIGNAL(src, COMSIG_ATOM_EXITED, AM, newLoc) + +/atom/proc/return_temperature() + return + +// Tool behavior procedure. Redirects to tool-specific procs by default. +// You can override it to catch all tool interactions, for use in complex deconstruction procs. +// Just don't forget to return ..() in the end. +/atom/proc/tool_act(mob/living/user, obj/item/I, tool_type) + switch(tool_type) + if(TOOL_CROWBAR) + return crowbar_act(user, I) + if(TOOL_MULTITOOL) + return multitool_act(user, I) + if(TOOL_SCREWDRIVER) + return screwdriver_act(user, I) + if(TOOL_WRENCH) + return wrench_act(user, I) + if(TOOL_WIRECUTTER) + return wirecutter_act(user, I) + if(TOOL_WELDER) + return welder_act(user, I) + if(TOOL_ANALYZER) + return analyzer_act(user, I) + +// Tool-specific behavior procs. To be overridden in subtypes. +/atom/proc/crowbar_act(mob/living/user, obj/item/I) + return + +/atom/proc/multitool_act(mob/living/user, obj/item/I) + return + +/atom/proc/multitool_check_buffer(user, obj/item/I, silent = FALSE) + if(!istype(I, /obj/item/multitool)) + if(user && !silent) + to_chat(user, "[I] has no data buffer!") + return FALSE + return TRUE + +/atom/proc/screwdriver_act(mob/living/user, obj/item/I) + SEND_SIGNAL(src, COMSIG_ATOM_SCREWDRIVER_ACT, user, I) + +/atom/proc/wrench_act(mob/living/user, obj/item/I) + return + +/atom/proc/wirecutter_act(mob/living/user, obj/item/I) + return + +/atom/proc/welder_act(mob/living/user, obj/item/I) + return + +/atom/proc/analyzer_act(mob/living/user, obj/item/I) + return + +/atom/proc/GenerateTag() + return + +// Generic logging helper +/atom/proc/log_message(message, message_type, color=null, log_globally=TRUE) + if(!log_globally) + return + + var/log_text = "[key_name(src)] [message] [loc_name(src)]" + switch(message_type) + if(LOG_ATTACK) + log_attack(log_text) + if(LOG_SAY) + log_say(log_text) + if(LOG_WHISPER) + log_whisper(log_text) + if(LOG_EMOTE) + log_emote(log_text) + if(LOG_DSAY) + log_dsay(log_text) + if(LOG_PDA) + log_pda(log_text) + if(LOG_CHAT) + log_chat(log_text) + if(LOG_COMMENT) + log_comment(log_text) + if(LOG_TELECOMMS) + log_telecomms(log_text) + if(LOG_OOC) + log_ooc(log_text) + if(LOG_ADMIN) + log_admin(log_text) + if(LOG_ADMIN_PRIVATE) + log_admin_private(log_text) + if(LOG_ASAY) + log_adminsay(log_text) + if(LOG_OWNERSHIP) + log_game(log_text) + if(LOG_GAME) + log_game(log_text) + else + stack_trace("Invalid individual logging type: [message_type]. Defaulting to [LOG_GAME] (LOG_GAME).") + log_game(log_text) + +// Helper for logging chat messages or other logs with arbitrary inputs (e.g. announcements) +/atom/proc/log_talk(message, message_type, tag=null, log_globally=TRUE, forced_by=null) + var/prefix = tag ? "([tag]) " : "" + var/suffix = forced_by ? " FORCED by [forced_by]" : "" + log_message("[prefix]\"[message]\"[suffix]", message_type, log_globally=log_globally) + +// Helper for logging of messages with only one sender and receiver +/proc/log_directed_talk(atom/source, atom/target, message, message_type, tag) + if(!tag) + stack_trace("Unspecified tag for private message") + tag = "UNKNOWN" + + source.log_talk(message, message_type, tag="[tag] to [key_name(target)]") + if(source != target) + target.log_talk(message, message_type, tag="[tag] from [key_name(source)]", log_globally=FALSE) + +/* +Proc for attack log creation, because really why not +1 argument is the actor performing the action +2 argument is the target of the action +3 is a verb describing the action (e.g. punched, throwed, kicked, etc.) +4 is a tool with which the action was made (usually an item) +5 is any additional text, which will be appended to the rest of the log line +*/ + +/proc/log_combat(atom/user, atom/target, what_done, atom/object=null, addition=null) + var/ssource = key_name(user) + var/starget = key_name(target) + + var/mob/living/living_target = target + var/hp = istype(living_target) ? " (NEWHP: [living_target.health]) " : "" + + var/sobject = "" + if(object) + sobject = " with [key_name(object)]" + var/saddition = "" + if(addition) + saddition = " [addition]" + + var/postfix = "[sobject][saddition][hp]" + + var/message = "has [what_done] [starget][postfix]" + user.log_message(message, LOG_ATTACK, color="red") + + if(user != target) + var/reverse_message = "has been [what_done] by [ssource][postfix]" + target.log_message(reverse_message, LOG_ATTACK, color="orange", log_globally=FALSE) + +// Filter stuff +/atom/movable/proc/add_filter(name,priority,list/params) + if(!filter_data) + filter_data = list() + var/list/p = params.Copy() + p["priority"] = priority + filter_data[name] = p + update_filters() + +/atom/movable/proc/update_filters() + filters = null + sortTim(filter_data,associative = TRUE) + for(var/f in filter_data) + var/list/data = filter_data[f] + var/list/arguments = data.Copy() + arguments -= "priority" + filters += filter(arglist(arguments)) + +/atom/movable/proc/get_filter(name) + if(filter_data && filter_data[name]) + return filters[filter_data.Find(name)] + +/atom/movable/proc/remove_filter(name) + if(filter_data[name]) + filter_data -= name + update_filters() + return TRUE + +/atom/proc/intercept_zImpact(atom/movable/AM, levels = 1) + . |= SEND_SIGNAL(src, COMSIG_ATOM_INTERCEPT_Z_FALL, AM, levels) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index ad244ec6..bc778a6c 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -1,1013 +1,1037 @@ - -//////////////////////////////// -/proc/message_admins(msg) - msg = "ADMIN LOG: [msg]" - to_chat(GLOB.admins, msg) - -/proc/relay_msg_admins(msg) - msg = "RELAY: [msg]" - to_chat(GLOB.admins, msg) - - -///////////////////////////////////////////////////////////////////////////////////////////////Panels - -/datum/admins/proc/show_player_panel(mob/M in GLOB.mob_list) - set category = "Admin" - set name = "Show Player Panel" - set desc="Edit player (respawn, ban, heal, etc)" - - if(!check_rights()) - return - - log_admin("[key_name(usr)] checked the individual player panel for [key_name(M)][isobserver(usr)?"":" while in game"].") - - if(!M) - to_chat(usr, "You seem to be selecting a mob that doesn't exist anymore.") - return - - var/body = "Options for [M.key]" - body += "Options panel for [M]" - if(M.client) - body += " played by [M.client] " - body += "\[[M.client.holder ? M.client.holder.rank : "Player"]\]" - if(CONFIG_GET(flag/use_exp_tracking)) - body += "\[" + M.client.get_exp_living() + "\]" - - if(isnewplayer(M)) - body += " Hasn't Entered Game " - else - body += " \[Heal\] " - - if(M.client) - body += "
\[First Seen: [M.client.player_join_date]\]\[Byond account registered on: [M.client.account_join_date]\]" - body += "

CentCom Galactic Ban DB: " - if(CONFIG_GET(string/centcom_ban_db)) - body += "Search" - else - body += "Disabled" - body += "

Show related accounts by: " - body += "\[ CID | " - body += "IP \]" - var/rep = 0 - rep += SSpersistence.antag_rep[M.ckey] - body += "

Antagonist reputation: [rep]" - body += "
\[increase\] " - body += "\[decrease\] " - body += "\[set\] " - body += "\[zero\]" - var/full_version = "Unknown" - if(M.client.byond_version) - full_version = "[M.client.byond_version].[M.client.byond_build ? M.client.byond_build : "xxx"]" - body += "
\[Byond version: [full_version]\]
" - - - body += "

\[ " - body += "VV - " - if(M.mind) - body += "TP - " - else - body += "Init Mind - " - if (iscyborg(M)) - body += "BP - " - body += "PM - " - body += "SM - " - if (ishuman(M) && M.mind) - body += "HM - " - body += "FLW - " - //Default to client logs if available - var/source = LOGSRC_MOB - if(M.client) - source = LOGSRC_CLIENT - body += "LOGS\]
" - - body += "Mob type = [M.type]

" - - body += "Kick | " - body += "Ban | " - body += "Jobban | " - body += "Identity Ban | " - var/rm = REF(M) - if(jobban_isbanned(M, "OOC")) - body+= "OOCBan | " - else - body+= "OOCBan | " - if(QDELETED(M) || QDELETED(usr)) - return - if(jobban_isbanned(M, "emote")) - body+= "EmoteBan | " - else - body+= "Emoteban | " - if(QDELETED(M) || QDELETED(usr)) - return - - body += "Notes | Messages | Watchlist | " - if(M.client) - body += "| Prison | " - body += "\ Send back to Lobby | " - var/muted = M.client.prefs.muted - body += "
Mute: " - body += "\[IC | " - body += "OOC | " - body += "PRAY | " - body += "ADMINHELP | " - body += "DEADCHAT\]" - body += "(toggle all)" - - body += "

" - body += "Jump to | " - body += "Get | " - body += "Send To" - - body += "

" - body += "Traitor panel | " - body += "Narrate to | " - body += "Subtle message | " - body += "Language Menu" - - if (M.client) - if(!isnewplayer(M)) - body += "

" - body += "Transformation:" - body += "
" - - //Human - if(ishuman(M)) - body += "Human | " - else - body += "Humanize | " - - //Monkey - if(ismonkey(M)) - body += "Monkeyized | " - else - body += "Monkeyize | " - - //Corgi - if(iscorgi(M)) - body += "Corgized | " - else - body += "Corgize | " - - //AI / Cyborg - if(isAI(M)) - body += "Is an AI " - else if(ishuman(M)) - body += "Make AI | " - body += "Make Robot | " - body += "Make Alien | " - body += "Make Slime | " - body += "Make Blob | " - - //Simple Animals - if(isanimal(M)) - body += "Re-Animalize | " - else - body += "Animalize | " - - body += "

" - body += "Rudimentary transformation:
These transformations only create a new mob type and copy stuff over. They do not take into account MMIs and similar mob-specific things. The buttons in 'Transformations' are preferred, when possible.

" - body += "Observer | " - body += "\[ Alien: Drone, " - body += "Hunter, " - body += "Sentinel, " - body += "Praetorian, " - body += "Queen, " - body += "Larva \] " - body += "Human " - body += "\[ slime: Baby, " - body += "Adult \] " - body += "Monkey | " - body += "Cyborg | " - body += "Cat | " - body += "Runtime | " - body += "Corgi | " - body += "Ian | " - body += "Crab | " - body += "Coffee | " - body += "\[ Construct: Juggernaut , " - body += "Artificer , " - body += "Wraith \] " - body += "Shade" - body += "
" - - body += "

" - body += "Other actions:" - body += "
" - body += "Forcesay | " - body += "Thunderdome 1 | " - body += "Thunderdome 2 | " - body += "Thunderdome Admin | " - body += "Thunderdome Observer | " - body += "Make mentor | " - body += "Remove mentor" - body += "Allow reentering round" - body += "
" - body += "" - - usr << browse(body, "window=adminplayeropts-[REF(M)];size=550x515") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Player Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - - -/datum/admins/proc/access_news_network() //MARKER - set category = "Fun" - set name = "Access Newscaster Network" - set desc = "Allows you to view, add and edit news feeds." - - if (!istype(src, /datum/admins)) - src = usr.client.holder - if (!istype(src, /datum/admins)) - to_chat(usr, "Error: you are not an admin!") - return - var/dat - dat = text("Admin Newscaster

Admin Newscaster Unit

") - - switch(admincaster_screen) - if(0) - dat += "Welcome to the admin newscaster.
Here you can add, edit and censor every newspiece on the network." - dat += "
Feed channels and stories entered through here will be uneditable and handled as official news by the rest of the units." - dat += "
Note that this panel allows full freedom over the news network, there are no constrictions except the few basic ones. Don't break things!" - if(GLOB.news_network.wanted_issue.active) - dat+= "
Read Wanted Issue" - dat+= "

Create Feed Channel" - dat+= "
View Feed Channels" - dat+= "
Submit new Feed story" - dat+= "

Exit" - var/wanted_already = 0 - if(GLOB.news_network.wanted_issue.active) - wanted_already = 1 - dat+="
Feed Security functions:
" - dat+="
[(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue" - dat+="
Censor Feed Stories" - dat+="
Mark Feed Channel with Kinaris D-Notice (disables and locks the channel)." - dat+="

The newscaster recognises you as:
[src.admin_signature]
" - if(1) - dat+= "Station Feed Channels
" - if( isemptylist(GLOB.news_network.network_channels) ) - dat+="No active channels found..." - else - for(var/datum/newscaster/feed_channel/CHANNEL in GLOB.news_network.network_channels) - if(CHANNEL.is_admin_channel) - dat+="[CHANNEL.channel_name]
" - else - dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ""]
" - dat+="

Refresh" - dat+="
Back" - if(2) - dat+="Creating new Feed Channel..." - dat+="
Channel Name: [src.admincaster_feed_channel.channel_name]
" - dat+="Channel Author: [src.admin_signature]
" - dat+="Will Accept Public Feeds: [(src.admincaster_feed_channel.locked) ? ("NO") : ("YES")]

" - dat+="
Submit

Cancel
" - if(3) - dat+="Creating new Feed Message..." - dat+="
Receiving Channel: [src.admincaster_feed_channel.channel_name]
" //MARK - dat+="Message Author: [src.admin_signature]
" - dat+="Message Body: [src.admincaster_feed_message.returnBody(-1)]
" - dat+="
Submit

Cancel
" - if(4) - dat+="Feed story successfully submitted to [src.admincaster_feed_channel.channel_name].

" - dat+="
Return
" - if(5) - dat+="Feed Channel [src.admincaster_feed_channel.channel_name] created successfully.

" - dat+="
Return
" - if(6) - dat+="ERROR: Could not submit Feed story to Network.

" - if(src.admincaster_feed_channel.channel_name=="") - dat+="•Invalid receiving channel name.
" - if(src.admincaster_feed_message.returnBody(-1) == "" || src.admincaster_feed_message.returnBody(-1) == "\[REDACTED\]") - dat+="•Invalid message body.
" - dat+="
Return
" - if(7) - dat+="ERROR: Could not submit Feed Channel to Network.

" - if(src.admincaster_feed_channel.channel_name =="" || src.admincaster_feed_channel.channel_name == "\[REDACTED\]") - dat+="•Invalid channel name.
" - var/check = 0 - for(var/datum/newscaster/feed_channel/FC in GLOB.news_network.network_channels) - if(FC.channel_name == src.admincaster_feed_channel.channel_name) - check = 1 - break - if(check) - dat+="•Channel name already in use.
" - dat+="
Return
" - if(9) - dat+="[admincaster_feed_channel.channel_name]: \[created by: [admincaster_feed_channel.returnAuthor(-1)]\]
" - if(src.admincaster_feed_channel.censored) - dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a Kinaris D-Notice.
" - dat+="No further feed story additions are allowed while the D-Notice is in effect.

" - else - if( isemptylist(src.admincaster_feed_channel.messages) ) - dat+="No feed messages found in channel...
" - else - var/i = 0 - for(var/datum/newscaster/feed_message/MESSAGE in src.admincaster_feed_channel.messages) - i++ - dat+="-[MESSAGE.returnBody(-1)]
" - if(MESSAGE.img) - usr << browse_rsc(MESSAGE.img, "tmp_photo[i].png") - dat+="

" - dat+="\[Story by [MESSAGE.returnAuthor(-1)]\]
" - dat+="[MESSAGE.comments.len] comment[MESSAGE.comments.len > 1 ? "s" : ""]:
" - for(var/datum/newscaster/feed_comment/comment in MESSAGE.comments) - dat+="[comment.body]
[comment.author] [comment.time_stamp]
" - dat+="
" - dat+="

Refresh" - dat+="
Back" - if(10) - dat+="Kinaris Feed Censorship Tool
" - dat+="NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.
" - dat+="Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it.
" - dat+="
Select Feed channel to get Stories from:
" - if(isemptylist(GLOB.news_network.network_channels)) - dat+="No feed channels found active...
" - else - for(var/datum/newscaster/feed_channel/CHANNEL in GLOB.news_network.network_channels) - dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ""]
" - dat+="
Cancel" - if(11) - dat+="Kinaris D-Notice Handler
" - dat+="A D-Notice is to be bestowed upon the channel if the handling Authority deems it as harmful for the station's" - dat+="morale, integrity or disciplinary behaviour. A D-Notice will render a channel unable to be updated by anyone, without deleting any feed" - dat+="stories it might contain at the time. You can lift a D-Notice if you have the required access at any time.
" - if(isemptylist(GLOB.news_network.network_channels)) - dat+="No feed channels found active...
" - else - for(var/datum/newscaster/feed_channel/CHANNEL in GLOB.news_network.network_channels) - dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ""]
" - - dat+="
Back" - if(12) - dat+="[src.admincaster_feed_channel.channel_name]: \[ created by: [src.admincaster_feed_channel.returnAuthor(-1)] \]
" - dat+="[(src.admincaster_feed_channel.authorCensor) ? ("Undo Author censorship") : ("Censor channel Author")]
" - - if( isemptylist(src.admincaster_feed_channel.messages) ) - dat+="No feed messages found in channel...
" - else - for(var/datum/newscaster/feed_message/MESSAGE in src.admincaster_feed_channel.messages) - dat+="-[MESSAGE.returnBody(-1)]
\[Story by [MESSAGE.returnAuthor(-1)]\]
" - dat+="[(MESSAGE.bodyCensor) ? ("Undo story censorship") : ("Censor story")] - [(MESSAGE.authorCensor) ? ("Undo Author Censorship") : ("Censor message Author")]
" - dat+="[MESSAGE.comments.len] comment[MESSAGE.comments.len > 1 ? "s" : ""]: [MESSAGE.locked ? "Unlock" : "Lock"]
" - for(var/datum/newscaster/feed_comment/comment in MESSAGE.comments) - dat+="[comment.body] X
[comment.author] [comment.time_stamp]
" - dat+="
Back" - if(13) - dat+="[src.admincaster_feed_channel.channel_name]: \[ created by: [src.admincaster_feed_channel.returnAuthor(-1)] \]
" - dat+="Channel messages listed below. If you deem them dangerous to the station, you can Bestow a D-Notice upon the channel.
" - if(src.admincaster_feed_channel.censored) - dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a Kinaris D-Notice.
" - dat+="No further feed story additions are allowed while the D-Notice is in effect.

" - else - if( isemptylist(src.admincaster_feed_channel.messages) ) - dat+="No feed messages found in channel...
" - else - for(var/datum/newscaster/feed_message/MESSAGE in src.admincaster_feed_channel.messages) - dat+="-[MESSAGE.returnBody(-1)]
\[Story by [MESSAGE.returnAuthor(-1)]\]
" - dat+="
Back" - if(14) - dat+="Wanted Issue Handler:" - var/wanted_already = 0 - var/end_param = 1 - if(GLOB.news_network.wanted_issue.active) - wanted_already = 1 - end_param = 2 - if(wanted_already) - dat+="
A wanted issue is already in Feed Circulation. You can edit or cancel it below.
" - dat+="
" - dat+="Criminal Name: [src.admincaster_wanted_message.criminal]
" - dat+="Description: [src.admincaster_wanted_message.body]
" - if(wanted_already) - dat+="Wanted Issue created by:[GLOB.news_network.wanted_issue.scannedUser]
" - else - dat+="Wanted Issue will be created under prosecutor:[src.admin_signature]
" - dat+="
[(wanted_already) ? ("Edit Issue") : ("Submit")]" - if(wanted_already) - dat+="
Take down Issue" - dat+="
Cancel" - if(15) - dat+="Wanted issue for [src.admincaster_wanted_message.criminal] is now in Network Circulation.

" - dat+="
Return
" - if(16) - dat+="ERROR: Wanted Issue rejected by Network.

" - if(src.admincaster_wanted_message.criminal =="" || src.admincaster_wanted_message.criminal == "\[REDACTED\]") - dat+="•Invalid name for person wanted.
" - if(src.admincaster_wanted_message.body == "" || src.admincaster_wanted_message.body == "\[REDACTED\]") - dat+="•Invalid description.
" - dat+="
Return
" - if(17) - dat+="Wanted Issue successfully deleted from Circulation
" - dat+="
Return
" - if(18) - dat+="-- STATIONWIDE WANTED ISSUE --
\[Submitted by: [GLOB.news_network.wanted_issue.scannedUser]\]
" - dat+="Criminal: [GLOB.news_network.wanted_issue.criminal]
" - dat+="Description: [GLOB.news_network.wanted_issue.body]
" - dat+="Photo:: " - if(GLOB.news_network.wanted_issue.img) - usr << browse_rsc(GLOB.news_network.wanted_issue.img, "tmp_photow.png") - dat+="
" - else - dat+="None" - dat+="
Back
" - if(19) - dat+="Wanted issue for [src.admincaster_wanted_message.criminal] successfully edited.

" - dat+="
Return
" - else - dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com" - - usr << browse(dat, "window=admincaster_main;size=400x600") - onclose(usr, "admincaster_main") - - -/datum/admins/proc/Game() - if(!check_rights(0)) - return - - var/dat = {" -
Game Panel

\n - Change Game Mode
- "} - if(GLOB.master_mode == "secret") - dat += "(Force Secret Mode)
" - - if(GLOB.master_mode == "dynamic") - if(SSticker.current_state <= GAME_STATE_PREGAME) - dat += "(Force Roundstart Rulesets)
" - if (GLOB.dynamic_forced_roundstart_ruleset.len > 0) - for(var/datum/dynamic_ruleset/roundstart/rule in GLOB.dynamic_forced_roundstart_ruleset) - dat += {"-> [rule.name] <-
"} - dat += "(Clear Rulesets)
" - dat += "(Dynamic mode options)
" - else if (SSticker.IsRoundInProgress()) - dat += "(Force Next Latejoin Ruleset)
" - if (SSticker && SSticker.mode && istype(SSticker.mode,/datum/game_mode/dynamic)) - var/datum/game_mode/dynamic/mode = SSticker.mode - if (mode.forced_latejoin_rule) - dat += {"-> [mode.forced_latejoin_rule.name] <-
"} - dat += "(Execute Midround Ruleset!)
" - dat += "
" - if(SSticker.IsRoundInProgress()) - dat += "(Game Mode Panel)
" - - dat += {" -
- Create Object
- Quick Create Object
- Create Turf
- Create Mob
- "} - - if(marked_datum && istype(marked_datum, /atom)) - dat += "Duplicate Marked Datum
" - - usr << browse(dat, "window=admin2;size=210x200") - return - -/////////////////////////////////////////////////////////////////////////////////////////////////admins2.dm merge -//i.e. buttons/verbs - - -/datum/admins/proc/restart() - set category = "Server" - set name = "Reboot World" - set desc="Restarts the world immediately" - if (!usr.client.holder) - return - - var/list/options = list("Regular Restart", "Hard Restart (No Delay/Feeback Reason)", "Hardest Restart (No actions, just reboot)") - if(world.TgsAvailable()) - options += "Server Restart (Kill and restart DD)"; - - var/rebootconfirm - if(SSticker.admin_delay_notice) - if(alert(usr, "Are you sure? An admin has already delayed the round end for the following reason: [SSticker.admin_delay_notice]", "Confirmation", "Yes", "No") == "Yes") - rebootconfirm = TRUE - else - rebootconfirm = TRUE - if(rebootconfirm) - var/result = input(usr, "Select reboot method", "World Reboot", options[1]) as null|anything in options - if(result) - SSblackbox.record_feedback("tally", "admin_verb", 1, "Reboot World") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - var/init_by = "Initiated by [usr.client.holder.fakekey ? "Admin" : usr.key]." - switch(result) - if("Regular Restart") - SSticker.Reboot(init_by, "admin reboot - by [usr.key] [usr.client.holder.fakekey ? "(stealth)" : ""]", 10) - if("Hard Restart (No Delay, No Feeback Reason)") - to_chat(world, "World reboot - [init_by]") - world.Reboot() - if("Hardest Restart (No actions, just reboot)") - to_chat(world, "Hard world reboot - [init_by]") - world.Reboot(fast_track = TRUE) - if("Server Restart (Kill and restart DD)") - to_chat(world, "Server restart - [init_by]") - world.TgsEndProcess() - -/datum/admins/proc/end_round() - set category = "Server" - set name = "End Round" - set desc = "Attempts to produce a round end report and then restart the server organically." - - if (!usr.client.holder) - return - var/confirm = alert("End the round and restart the game world?", "End Round", "Yes", "Cancel") - if(confirm == "Cancel") - return - if(confirm == "Yes") - SSticker.force_ending = 1 - SSblackbox.record_feedback("tally", "admin_verb", 1, "End Round") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - - -/datum/admins/proc/announce() - set category = "Special Verbs" - set name = "Announce" - set desc="Announce your desires to the world" - if(!check_rights(0)) - return - - var/message = input("Global message to send:", "Admin Announce", null, null) as message - if(message) - if(!check_rights(R_SERVER,0)) - message = adminscrub(message,500) - to_chat(world, "[usr.client.holder.fakekey ? "Administrator" : usr.key] Announces:\n \t [message]") - log_admin("Announce: [key_name(usr)] : [message]") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Announce") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/datum/admins/proc/set_admin_notice() - set category = "Special Verbs" - set name = "Set Admin Notice" - set desc ="Set an announcement that appears to everyone who joins the server. Only lasts this round" - if(!check_rights(0)) - return - - var/new_admin_notice = input(src,"Set a public notice for this round. Everyone who joins the server will see it.\n(Leaving it blank will delete the current notice):","Set Notice",GLOB.admin_notice) as message|null - if(new_admin_notice == null) - return - if(new_admin_notice == GLOB.admin_notice) - return - if(new_admin_notice == "") - message_admins("[key_name(usr)] removed the admin notice.") - log_admin("[key_name(usr)] removed the admin notice:\n[GLOB.admin_notice]") - else - message_admins("[key_name(usr)] set the admin notice.") - log_admin("[key_name(usr)] set the admin notice:\n[new_admin_notice]") - to_chat(world, "Admin Notice:\n \t [new_admin_notice]") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Set Admin Notice") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - GLOB.admin_notice = new_admin_notice - return - -/datum/admins/proc/toggleooc() - set category = "Server" - set desc="Toggle dis bitch" - set name="Toggle OOC" - toggle_ooc() - log_admin("[key_name(usr)] toggled OOC.") - message_admins("[key_name_admin(usr)] toggled OOC.") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle OOC", "[GLOB.ooc_allowed ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/datum/admins/proc/toggleooclocal() - set category = "Server" - set desc="Toggle dat bitch" - set name="Toggle Local OOC" - toggle_looc() - log_admin("[key_name(usr)] toggled LOOC.") - message_admins("[key_name_admin(usr)] toggled LOOC.") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Local OOC", "[GLOB.ooc_allowed ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/datum/admins/proc/toggleoocdead() - set category = "Server" - set desc="Toggle dis bitch" - set name="Toggle Dead OOC" - toggle_dooc() - - log_admin("[key_name(usr)] toggled Dead OOC.") - message_admins("[key_name_admin(usr)] toggled Dead OOC.") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Dead OOC", "[GLOB.dooc_allowed ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/datum/admins/proc/toggleaooc() - set category = "Server" - set desc="Toggle to bitch" - set name="Toggle Antag OOC" - toggle_aooc() - log_admin("[key_name(usr)] toggled Antagonist OOC.") - message_admins("[key_name_admin(usr)] toggled Antagonist OOC.") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Antag OOC", "[GLOB.aooc_allowed ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/datum/admins/proc/startnow() - set category = "Server" - set desc="Start the round RIGHT NOW" - set name="Start Now" - if(SSticker.current_state == GAME_STATE_PREGAME || SSticker.current_state == GAME_STATE_STARTUP) - SSticker.start_immediately = TRUE - log_admin("[usr.key] has started the game.") - var/msg = "" - if(SSticker.current_state == GAME_STATE_STARTUP) - msg = " (The server is still setting up, but the round will be \ - started as soon as possible.)" - message_admins("\ - [usr.key] has started the game.[msg]") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Start Now") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - return 1 - else - to_chat(usr, "Error: Start Now: Game has already started.") - - return 0 - -/datum/admins/proc/toggleenter() - set category = "Server" - set desc="People can't enter" - set name="Toggle Entering" - GLOB.enter_allowed = !( GLOB.enter_allowed ) - if (!( GLOB.enter_allowed )) - to_chat(world, "New players may no longer enter the game.") - else - to_chat(world, "New players may now enter the game.") - log_admin("[key_name(usr)] toggled new player game entering.") - message_admins("[key_name_admin(usr)] toggled new player game entering.") - world.update_status() - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Entering", "[GLOB.enter_allowed ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/datum/admins/proc/toggleAI() - set category = "Server" - set desc="People can't be AI" - set name="Toggle AI" - var/alai = CONFIG_GET(flag/allow_ai) - CONFIG_SET(flag/allow_ai, !alai) - if (alai) - to_chat(world, "The AI job is no longer chooseable.") - else - to_chat(world, "The AI job is chooseable now.") - log_admin("[key_name(usr)] toggled AI allowed.") - world.update_status() - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle AI", "[!alai ? "Disabled" : "Enabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/datum/admins/proc/toggleMulticam() - set category = "Server" - set desc="Turns mutlicam on and off." - set name="Toggle Multicam" - var/almcam = CONFIG_GET(flag/allow_ai_multicam) - CONFIG_SET(flag/allow_ai_multicam, !almcam) - if (almcam) - to_chat(world, "The AI no longer has multicam.") - for(var/i in GLOB.ai_list) - var/mob/living/silicon/ai/aiPlayer = i - if(aiPlayer.multicam_on) - aiPlayer.end_multicam() - else - to_chat(world, "The AI now has multicam.") - log_admin("[key_name(usr)] toggled AI multicam.") - world.update_status() - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Multicam", "[!almcam ? "Disabled" : "Enabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/datum/admins/proc/toggleaban() - set category = "Server" - set desc="Respawn basically" - set name="Toggle Respawn" - var/new_nores = !CONFIG_GET(flag/norespawn) - CONFIG_SET(flag/norespawn, new_nores) - if (!new_nores) - to_chat(world, "You may now respawn.") - else - to_chat(world, "You may no longer respawn :(") - message_admins("[key_name_admin(usr)] toggled respawn to [!new_nores ? "On" : "Off"].") - log_admin("[key_name(usr)] toggled respawn to [!new_nores ? "On" : "Off"].") - world.update_status() - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Respawn", "[!new_nores ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/datum/admins/proc/delay() - set category = "Server" - set desc="Delay the game start" - set name="Delay pre-game" - - var/newtime = input("Set a new time in seconds. Set -1 for indefinite delay.","Set Delay",round(SSticker.GetTimeLeft()/10)) as num|null - if(SSticker.current_state > GAME_STATE_PREGAME) - return alert("Too late... The game has already started!") - if(newtime) - newtime = newtime*10 - SSticker.SetTimeLeft(newtime) - if(newtime < 0) - to_chat(world, "The game start has been delayed.") - log_admin("[key_name(usr)] delayed the round start.") - else - to_chat(world, "The game will start in [DisplayTimeText(newtime)].") - SEND_SOUND(world, sound('sound/ai/attention.ogg')) - log_admin("[key_name(usr)] set the pre-game delay to [DisplayTimeText(newtime)].") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Delay Game Start") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/datum/admins/proc/unprison(mob/M in GLOB.mob_list) - set category = "Admin" - set name = "Unprison" - if (is_centcom_level(M.z)) - SSjob.SendToLateJoin(M) - message_admins("[key_name_admin(usr)] has unprisoned [key_name_admin(M)]") - log_admin("[key_name(usr)] has unprisoned [key_name(M)]") - else - alert("[M.name] is not prisoned.") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Unprison") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -////////////////////////////////////////////////////////////////////////////////////////////////ADMIN HELPER PROCS - -/datum/admins/proc/spawn_atom(object as text) - set category = "Debug" - set desc = "(atom path) Spawn an atom" - set name = "Spawn" - - if(!check_rights(R_SPAWN)) - return - - var/chosen = pick_closest_path(object) - if(!chosen) - return - if(ispath(chosen, /turf)) - var/turf/T = get_turf(usr.loc) - T.ChangeTurf(chosen) - else - var/atom/A = new chosen(usr.loc) - A.flags_1 |= ADMIN_SPAWNED_1 - - log_admin("[key_name(usr)] spawned [chosen] at [AREACOORD(usr)]") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Spawn Atom") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/datum/admins/proc/spawn_cargo(object as text) - set category = "Debug" - set desc = "(atom path) Spawn a cargo crate" - set name = "Spawn Cargo" - - if(!check_rights(R_SPAWN)) - return - - var/chosen = pick_closest_path(object, make_types_fancy(subtypesof(/datum/supply_pack))) - if(!chosen) - return - var/datum/supply_pack/S = new chosen - S.admin_spawned = TRUE - S.generate(get_turf(usr)) - - log_admin("[key_name(usr)] spawned cargo pack [chosen] at [AREACOORD(usr)]") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Spawn Cargo") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - - -/datum/admins/proc/show_traitor_panel(mob/M in GLOB.mob_list) - set category = "Admin" - set desc = "Edit mobs's memory and role" - set name = "Show Traitor Panel" - - if(!istype(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - if(!M.mind) - to_chat(usr, "This mob has no mind!") - return - - M.mind.traitor_panel() - SSblackbox.record_feedback("tally", "admin_verb", 1, "Traitor Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - - -/datum/admins/proc/toggletintedweldhelmets() - set category = "Debug" - set desc="Reduces view range when wearing welding helmets" - set name="Toggle tinted welding helmes" - GLOB.tinted_weldhelh = !( GLOB.tinted_weldhelh ) - if (GLOB.tinted_weldhelh) - to_chat(world, "The tinted_weldhelh has been enabled!") - else - to_chat(world, "The tinted_weldhelh has been disabled!") - log_admin("[key_name(usr)] toggled tinted_weldhelh.") - message_admins("[key_name_admin(usr)] toggled tinted_weldhelh.") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Tinted Welding Helmets", "[GLOB.tinted_weldhelh ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/datum/admins/proc/toggleguests() - set category = "Server" - set desc="Guests can't enter" - set name="Toggle guests" - var/new_guest_ban = !CONFIG_GET(flag/guest_ban) - CONFIG_SET(flag/guest_ban, new_guest_ban) - if (new_guest_ban) - to_chat(world, "Guests may no longer enter the game.") - else - to_chat(world, "Guests may now enter the game.") - log_admin("[key_name(usr)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.") - message_admins("[key_name_admin(usr)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Guests", "[!new_guest_ban ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/datum/admins/proc/output_ai_laws() - var/ai_number = 0 - for(var/i in GLOB.silicon_mobs) - var/mob/living/silicon/S = i - ai_number++ - if(isAI(S)) - to_chat(usr, "AI [key_name(S, usr)]'s laws:") - else if(iscyborg(S)) - var/mob/living/silicon/robot/R = S - to_chat(usr, "CYBORG [key_name(S, usr)] [R.connected_ai?"(Slaved to: [key_name(R.connected_ai)])":"(Independent)"]: laws:") - else if (ispAI(S)) - to_chat(usr, "pAI [key_name(S, usr)]'s laws:") - else - to_chat(usr, "SOMETHING SILICON [key_name(S, usr)]'s laws:") - - if (S.laws == null) - to_chat(usr, "[key_name(S, usr)]'s laws are null?? Contact a coder.") - else - S.laws.show_laws(usr) - if(!ai_number) - to_chat(usr, "No AIs located" ) - -/datum/admins/proc/output_all_devil_info() - var/devil_number = 0 - for(var/datum/mind/D in SSticker.mode.devils) - devil_number++ - var/datum/antagonist/devil/devil = D.has_antag_datum(/datum/antagonist/devil) - to_chat(usr, "Devil #[devil_number]:

" + devil.printdevilinfo()) - if(!devil_number) - to_chat(usr, "No Devils located" ) - -/datum/admins/proc/output_devil_info(mob/living/M) - if(is_devil(M)) - var/datum/antagonist/devil/devil = M.mind.has_antag_datum(/datum/antagonist/devil) - to_chat(usr, devil.printdevilinfo()) - else - to_chat(usr, "[M] is not a devil.") - -/datum/admins/proc/manage_free_slots() - if(!check_rights()) - return - var/datum/browser/browser = new(usr, "jobmanagement", "Manage Free Slots", 520) - var/list/dat = list() - var/count = 0 - - if(!SSjob.initialized) - alert(usr, "You cannot manage jobs before the job subsystem is initialized!") - return - - dat += "" - - for(var/j in SSjob.occupations) - var/datum/job/job = j - count++ - var/J_title = html_encode(job.title) - var/J_opPos = html_encode(job.total_positions - (job.total_positions - job.current_positions)) - var/J_totPos = html_encode(job.total_positions) - dat += "" - dat += "" - else - dat += "Limit" - - browser.height = min(100 + count * 20, 650) - browser.set_content(dat.Join()) - browser.open() - -/datum/admins/proc/dynamic_mode_options(mob/user) - var/dat = {" -

Dynamic Mode Options


-
-

Common options

- All these options can be changed midround.
-
- Force extended: - Option is [GLOB.dynamic_forced_extended ? "ON" : "OFF"]. -
This will force the round to be extended. No rulesets will be drafted.
-
- No stacking: - Option is [GLOB.dynamic_no_stacking ? "ON" : "OFF"]. -
Unless the threat goes above [GLOB.dynamic_stacking_limit], only one "round-ender" ruleset will be drafted.
-
- Classic secret mode: - Option is [GLOB.dynamic_classic_secret ? "ON" : "OFF"]. -
Only one roundstart ruleset will be drafted. Only traitors and minor roles will latespawn.
-
-
- Chaos level: Current value : [GLOB.dynamic_chaos_level]. -
The Chaos value for the round. Only set between 0 and 5!
-
- Forced threat level: Current value : [GLOB.dynamic_forced_threat_level]. -
The value threat is set to if it is higher than -1.
-
- High population limit: Current value : [GLOB.dynamic_high_pop_limit]. -
The threshold at which "high population override" will be in effect.
-
- Stacking threeshold: Current value : [GLOB.dynamic_stacking_limit]. -
The threshold at which "round-ender" rulesets will stack. A value higher than 100 ensure this never happens.
-

Advanced parameters

- Curve centre: -> [GLOB.dynamic_curve_centre] <-
- Curve width: -> [GLOB.dynamic_curve_width] <-
- Latejoin injection delay:
- Minimum: -> [GLOB.dynamic_latejoin_delay_min / 60 / 10] <- Minutes
- Maximum: -> [GLOB.dynamic_latejoin_delay_max / 60 / 10] <- Minutes
- Midround injection delay:
- Minimum: -> [GLOB.dynamic_midround_delay_min / 60 / 10] <- Minutes
- Maximum: -> [GLOB.dynamic_midround_delay_max / 60 / 10] <- Minutes
- "} - - user << browse(dat, "window=dyn_mode_options;size=900x650") - -/datum/admins/proc/create_or_modify_area() - set category = "Debug" - set name = "Create or modify area" - create_area(usr) - -// -// -//ALL DONE -//********************************************************************************************************* -//TO-DO: -// -// - -//RIP ferry snowflakes - -//Kicks all the clients currently in the lobby. The second parameter (kick_only_afk) determins if an is_afk() check is ran, or if all clients are kicked -//defaults to kicking everyone (afk + non afk clients in the lobby) -//returns a list of ckeys of the kicked clients -/proc/kick_clients_in_lobby(message, kick_only_afk = 0) - var/list/kicked_client_names = list() - for(var/client/C in GLOB.clients) - if(isnewplayer(C.mob)) - if(kick_only_afk && !C.is_afk()) //Ignore clients who are not afk - continue - if(message) - to_chat(C, message) - kicked_client_names.Add("[C.key]") - qdel(C) - return kicked_client_names - -//returns 1 to let the dragdrop code know we are trapping this event -//returns 0 if we don't plan to trap the event -/datum/admins/proc/cmd_ghost_drag(mob/dead/observer/frommob, mob/tomob) - - //this is the exact two check rights checks required to edit a ckey with vv. - if (!check_rights(R_VAREDIT,0) || !check_rights(R_SPAWN|R_DEBUG,0)) - return 0 - - if (!frommob.ckey) - return 0 - - var/question = "" - if (tomob.ckey) - question = "This mob already has a user ([tomob.key]) in control of it! " - question += "Are you sure you want to place [frommob.name]([frommob.key]) in control of [tomob.name]?" - - var/ask = alert(question, "Place ghost in control of mob?", "Yes", "No") - if (ask != "Yes") - return 1 - - if (!frommob || !tomob) //make sure the mobs don't go away while we waited for a response - return 1 - - tomob.ghostize(0) - - message_admins("[key_name_admin(usr)] has put [frommob.key] in control of [tomob.name].") - log_admin("[key_name(usr)] stuffed [frommob.key] into [tomob.name].") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Ghost Drag Control") - - tomob.ckey = frommob.ckey - qdel(frommob) - - return 1 - -/client/proc/adminGreet(logout) - if(SSticker.HasRoundStarted()) - var/string - if(logout && CONFIG_GET(flag/announce_admin_logout)) - string = pick( - "Admin logout: [key_name(src)]") - else if(!logout && CONFIG_GET(flag/announce_admin_login) && (prefs.toggles & ANNOUNCE_LOGIN)) - string = pick( - "Admin login: [key_name(src)]") - if(string) - message_admins("[string]") - -/client/proc/cmd_admin_man_up(mob/M in GLOB.mob_list) - set category = "Special Verbs" - set name = "Man Up" - - if(!M) - return - if(!check_rights(R_ADMIN)) - return - - to_chat(M, "Man up, and deal with it.
Move on.") - M.playsound_local(M, 'modular_citadel/sound/misc/manup.ogg', 50, FALSE, pressure_affected = FALSE) - - log_admin("Man up: [key_name(usr)] told [key_name(M)] to man up") - var/message = "[key_name_admin(usr)] told [key_name_admin(M)] to man up." - message_admins(message) - admin_ticket_log(M, message) - SSblackbox.record_feedback("tally", "admin_verb", 1, "Man Up") - -/client/proc/cmd_admin_man_up_global() - set category = "Special Verbs" - set name = "Man Up Global" - - if(!check_rights(R_ADMIN)) - return - - to_chat(world, "Man up, and deal with it.
Move on.") - for(var/mob/M in GLOB.player_list) - M.playsound_local(M, 'modular_citadel/sound/misc/manup.ogg', 50, FALSE, pressure_affected = FALSE) - - log_admin("Man up global: [key_name(usr)] told everybody to man up") - message_admins("[key_name_admin(usr)] told everybody to man up.") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Man Up Global") + +//////////////////////////////// +/proc/message_admins(msg) + msg = "ADMIN LOG: [msg]" + to_chat(GLOB.admins, msg) + +/proc/relay_msg_admins(msg) + msg = "RELAY: [msg]" + to_chat(GLOB.admins, msg) + + +///////////////////////////////////////////////////////////////////////////////////////////////Panels + +/datum/admins/proc/show_player_panel(mob/M in GLOB.mob_list) + set category = "Admin" + set name = "Show Player Panel" + set desc="Edit player (respawn, ban, heal, etc)" + + if(!check_rights()) + return + + log_admin("[key_name(usr)] checked the individual player panel for [key_name(M)][isobserver(usr)?"":" while in game"].") + + if(!M) + to_chat(usr, "You seem to be selecting a mob that doesn't exist anymore.") + return + + var/body = "Options for [M.key]" + body += "Options panel for [M]" + if(M.client) + body += " played by [M.client] " + body += "\[[M.client.holder ? M.client.holder.rank : "Player"]\]" + if(CONFIG_GET(flag/use_exp_tracking)) + body += "\[" + M.client.get_exp_living() + "\]" + + if(isnewplayer(M)) + body += " Hasn't Entered Game " + else + body += " \[Heal\] " + + if(M.client) + body += "
\[First Seen: [M.client.player_join_date]\]\[Byond account registered on: [M.client.account_join_date]\]" + body += "

CentCom Galactic Ban DB: " + if(CONFIG_GET(string/centcom_ban_db)) + body += "Search" + else + body += "Disabled" + body += "

Show related accounts by: " + body += "\[ CID | " + body += "IP \]" + var/rep = 0 + rep += SSpersistence.antag_rep[M.ckey] + body += "

Antagonist reputation: [rep]" + body += "
\[increase\] " + body += "\[decrease\] " + body += "\[set\] " + body += "\[zero\]" + var/full_version = "Unknown" + if(M.client.byond_version) + full_version = "[M.client.byond_version].[M.client.byond_build ? M.client.byond_build : "xxx"]" + body += "
\[Byond version: [full_version]\]
" + + + body += "

\[ " + body += "VV - " + if(M.mind) + body += "TP - " + else + body += "Init Mind - " + if (iscyborg(M)) + body += "BP - " + body += "PM - " + body += "SM - " + if (ishuman(M) && M.mind) + body += "HM - " + body += "FLW - " + //Default to client logs if available + var/source = LOGSRC_MOB + if(M.client) + source = LOGSRC_CLIENT + body += "LOGS\]
" + + body += "Mob type = [M.type]

" + + body += "Kick | " + body += "Ban | " + body += "Jobban | " + body += "Identity Ban | " + var/rm = REF(M) + if(jobban_isbanned(M, "OOC")) + body+= "OOCBan | " + else + body+= "OOCBan | " + if(QDELETED(M) || QDELETED(usr)) + return + if(jobban_isbanned(M, "emote")) + body+= "EmoteBan | " + else + body+= "Emoteban | " + if(QDELETED(M) || QDELETED(usr)) + return + + body += "Notes | Messages | Watchlist | " + if(M.client) + body += "| Prison | " + body += "\ Send back to Lobby | " + var/muted = M.client.prefs.muted + body += "
Mute: " + body += "\[IC | " + body += "OOC | " + body += "PRAY | " + body += "ADMINHELP | " + body += "DEADCHAT\]" + body += "(toggle all)" + + body += "

" + body += "Jump to | " + body += "Get | " + body += "Send To" + + body += "

" + body += "Traitor panel | " + body += "Narrate to | " + body += "Subtle message | " + body += "Language Menu" + + if (M.client) + if(!isnewplayer(M)) + body += "

" + body += "Transformation:" + body += "
" + + //Human + if(ishuman(M)) + body += "Human | " + else + body += "Humanize | " + + //Monkey + if(ismonkey(M)) + body += "Monkeyized | " + else + body += "Monkeyize | " + + //Corgi + if(iscorgi(M)) + body += "Corgized | " + else + body += "Corgize | " + + //AI / Cyborg + if(isAI(M)) + body += "Is an AI " + else if(ishuman(M)) + body += "Make AI | " + body += "Make Robot | " + body += "Make Alien | " + body += "Make Slime | " + body += "Make Blob | " + + //Simple Animals + if(isanimal(M)) + body += "Re-Animalize | " + else + body += "Animalize | " + + body += "

" + body += "Rudimentary transformation:
These transformations only create a new mob type and copy stuff over. They do not take into account MMIs and similar mob-specific things. The buttons in 'Transformations' are preferred, when possible.

" + body += "Observer | " + body += "\[ Alien: Drone, " + body += "Hunter, " + body += "Sentinel, " + body += "Praetorian, " + body += "Queen, " + body += "Larva \] " + body += "Human " + body += "\[ slime: Baby, " + body += "Adult \] " + body += "Monkey | " + body += "Cyborg | " + body += "Cat | " + body += "Runtime | " + body += "Corgi | " + body += "Ian | " + body += "Crab | " + body += "Coffee | " + body += "\[ Construct: Juggernaut , " + body += "Artificer , " + body += "Wraith \] " + body += "Shade" + body += "
" + + body += "

" + body += "Other actions:" + body += "
" + body += "Forcesay | " + body += "Thunderdome 1 | " + body += "Thunderdome 2 | " + body += "Thunderdome Admin | " + body += "Thunderdome Observer | " + body += "Make mentor | " + body += "Remove mentor" + body += "Allow reentering round" + body += "
" + body += "" + + usr << browse(body, "window=adminplayeropts-[REF(M)];size=550x515") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Player Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +/datum/admins/proc/access_news_network() //MARKER + set category = "Fun" + set name = "Access Newscaster Network" + set desc = "Allows you to view, add and edit news feeds." + + if (!istype(src, /datum/admins)) + src = usr.client.holder + if (!istype(src, /datum/admins)) + to_chat(usr, "Error: you are not an admin!") + return + var/dat + dat = text("Admin Newscaster

Admin Newscaster Unit

") + + switch(admincaster_screen) + if(0) + dat += "Welcome to the admin newscaster.
Here you can add, edit and censor every newspiece on the network." + dat += "
Feed channels and stories entered through here will be uneditable and handled as official news by the rest of the units." + dat += "
Note that this panel allows full freedom over the news network, there are no constrictions except the few basic ones. Don't break things!" + if(GLOB.news_network.wanted_issue.active) + dat+= "
Read Wanted Issue" + dat+= "

Create Feed Channel" + dat+= "
View Feed Channels" + dat+= "
Submit new Feed story" + dat+= "

Exit" + var/wanted_already = 0 + if(GLOB.news_network.wanted_issue.active) + wanted_already = 1 + dat+="
Feed Security functions:
" + dat+="
[(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue" + dat+="
Censor Feed Stories" + dat+="
Mark Feed Channel with Kinaris D-Notice (disables and locks the channel)." + dat+="

The newscaster recognises you as:
[src.admin_signature]
" + if(1) + dat+= "Station Feed Channels
" + if( isemptylist(GLOB.news_network.network_channels) ) + dat+="No active channels found..." + else + for(var/datum/newscaster/feed_channel/CHANNEL in GLOB.news_network.network_channels) + if(CHANNEL.is_admin_channel) + dat+="[CHANNEL.channel_name]
" + else + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ""]
" + dat+="

Refresh" + dat+="
Back" + if(2) + dat+="Creating new Feed Channel..." + dat+="
Channel Name: [src.admincaster_feed_channel.channel_name]
" + dat+="Channel Author:[src.admin_signature]
" + dat+="Will Accept Public Feeds: [(src.admincaster_feed_channel.locked) ? ("NO") : ("YES")]

" + dat+="
Submit

Cancel
" + if(3) + dat+="Creating new Feed Message..." + dat+="
Receiving Channel: [src.admincaster_feed_channel.channel_name]
" //MARK + dat+="Message Author:[src.admin_signature]
" + dat+="Message Body: [src.admincaster_feed_message.returnBody(-1)]
" + dat+="
Submit

Cancel
" + if(4) + dat+="Feed story successfully submitted to [src.admincaster_feed_channel.channel_name].

" + dat+="
Return
" + if(5) + dat+="Feed Channel [src.admincaster_feed_channel.channel_name] created successfully.

" + dat+="
Return
" + if(6) + dat+="ERROR: Could not submit Feed story to Network.

" + if(src.admincaster_feed_channel.channel_name=="") + dat+="•Invalid receiving channel name.
" + if(src.admincaster_feed_message.returnBody(-1) == "" || src.admincaster_feed_message.returnBody(-1) == "\[REDACTED\]") + dat+="•Invalid message body.
" + dat+="
Return
" + if(7) + dat+="ERROR: Could not submit Feed Channel to Network.

" + if(src.admincaster_feed_channel.channel_name =="" || src.admincaster_feed_channel.channel_name == "\[REDACTED\]") + dat+="•Invalid channel name.
" + var/check = 0 + for(var/datum/newscaster/feed_channel/FC in GLOB.news_network.network_channels) + if(FC.channel_name == src.admincaster_feed_channel.channel_name) + check = 1 + break + if(check) + dat+="•Channel name already in use.
" + dat+="
Return
" + if(9) + dat+="[admincaster_feed_channel.channel_name]: \[created by: [admincaster_feed_channel.returnAuthor(-1)]\]
" + if(src.admincaster_feed_channel.censored) + dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a Kinaris D-Notice.
" + dat+="No further feed story additions are allowed while the D-Notice is in effect.

" + else + if( isemptylist(src.admincaster_feed_channel.messages) ) + dat+="No feed messages found in channel...
" + else + var/i = 0 + for(var/datum/newscaster/feed_message/MESSAGE in src.admincaster_feed_channel.messages) + i++ + dat+="-[MESSAGE.returnBody(-1)]
" + if(MESSAGE.img) + usr << browse_rsc(MESSAGE.img, "tmp_photo[i].png") + dat+="

" + dat+="\[Story by [MESSAGE.returnAuthor(-1)]\]
" + dat+="[MESSAGE.comments.len] comment[MESSAGE.comments.len > 1 ? "s" : ""]:
" + for(var/datum/newscaster/feed_comment/comment in MESSAGE.comments) + dat+="[comment.body]
[comment.author] [comment.time_stamp]
" + dat+="
" + dat+="

Refresh" + dat+="
Back" + if(10) + dat+="Kinaris Feed Censorship Tool
" + dat+="NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.
" + dat+="Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it.
" + dat+="
Select Feed channel to get Stories from:
" + if(isemptylist(GLOB.news_network.network_channels)) + dat+="No feed channels found active...
" + else + for(var/datum/newscaster/feed_channel/CHANNEL in GLOB.news_network.network_channels) + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ""]
" + dat+="
Cancel" + if(11) + dat+="Kinaris D-Notice Handler
" + dat+="A D-Notice is to be bestowed upon the channel if the handling Authority deems it as harmful for the station's" + dat+="morale, integrity or disciplinary behaviour. A D-Notice will render a channel unable to be updated by anyone, without deleting any feed" + dat+="stories it might contain at the time. You can lift a D-Notice if you have the required access at any time.
" + if(isemptylist(GLOB.news_network.network_channels)) + dat+="No feed channels found active...
" + else + for(var/datum/newscaster/feed_channel/CHANNEL in GLOB.news_network.network_channels) + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ""]
" + + dat+="
Back" + if(12) + dat+="[src.admincaster_feed_channel.channel_name]: \[ created by: [src.admincaster_feed_channel.returnAuthor(-1)] \]
" + dat+="[(src.admincaster_feed_channel.authorCensor) ? ("Undo Author censorship") : ("Censor channel Author")]
" + + if( isemptylist(src.admincaster_feed_channel.messages) ) + dat+="No feed messages found in channel...
" + else + for(var/datum/newscaster/feed_message/MESSAGE in src.admincaster_feed_channel.messages) + dat+="-[MESSAGE.returnBody(-1)]
\[Story by [MESSAGE.returnAuthor(-1)]\]
" + dat+="[(MESSAGE.bodyCensor) ? ("Undo story censorship") : ("Censor story")] - [(MESSAGE.authorCensor) ? ("Undo Author Censorship") : ("Censor message Author")]
" + dat+="[MESSAGE.comments.len] comment[MESSAGE.comments.len > 1 ? "s" : ""]: [MESSAGE.locked ? "Unlock" : "Lock"]
" + for(var/datum/newscaster/feed_comment/comment in MESSAGE.comments) + dat+="[comment.body] X
[comment.author] [comment.time_stamp]
" + dat+="
Back" + if(13) + dat+="[src.admincaster_feed_channel.channel_name]: \[ created by: [src.admincaster_feed_channel.returnAuthor(-1)] \]
" + dat+="Channel messages listed below. If you deem them dangerous to the station, you can Bestow a D-Notice upon the channel.
" + if(src.admincaster_feed_channel.censored) + dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a Kinaris D-Notice.
" + dat+="No further feed story additions are allowed while the D-Notice is in effect.

" + else + if( isemptylist(src.admincaster_feed_channel.messages) ) + dat+="No feed messages found in channel...
" + else + for(var/datum/newscaster/feed_message/MESSAGE in src.admincaster_feed_channel.messages) + dat+="-[MESSAGE.returnBody(-1)]
\[Story by [MESSAGE.returnAuthor(-1)]\]
" + dat+="
Back" + if(14) + dat+="Wanted Issue Handler:" + var/wanted_already = 0 + var/end_param = 1 + if(GLOB.news_network.wanted_issue.active) + wanted_already = 1 + end_param = 2 + if(wanted_already) + dat+="
A wanted issue is already in Feed Circulation. You can edit or cancel it below.
" + dat+="
" + dat+="Criminal Name: [src.admincaster_wanted_message.criminal]
" + dat+="Description: [src.admincaster_wanted_message.body]
" + if(wanted_already) + dat+="Wanted Issue created by:[GLOB.news_network.wanted_issue.scannedUser]
" + else + dat+="Wanted Issue will be created under prosecutor:[src.admin_signature]
" + dat+="
[(wanted_already) ? ("Edit Issue") : ("Submit")]" + if(wanted_already) + dat+="
Take down Issue" + dat+="
Cancel" + if(15) + dat+="Wanted issue for [src.admincaster_wanted_message.criminal] is now in Network Circulation.

" + dat+="
Return
" + if(16) + dat+="ERROR: Wanted Issue rejected by Network.

" + if(src.admincaster_wanted_message.criminal =="" || src.admincaster_wanted_message.criminal == "\[REDACTED\]") + dat+="•Invalid name for person wanted.
" + if(src.admincaster_wanted_message.body == "" || src.admincaster_wanted_message.body == "\[REDACTED\]") + dat+="•Invalid description.
" + dat+="
Return
" + if(17) + dat+="Wanted Issue successfully deleted from Circulation
" + dat+="
Return
" + if(18) + dat+="-- STATIONWIDE WANTED ISSUE --
\[Submitted by: [GLOB.news_network.wanted_issue.scannedUser]\]
" + dat+="Criminal: [GLOB.news_network.wanted_issue.criminal]
" + dat+="Description: [GLOB.news_network.wanted_issue.body]
" + dat+="Photo:: " + if(GLOB.news_network.wanted_issue.img) + usr << browse_rsc(GLOB.news_network.wanted_issue.img, "tmp_photow.png") + dat+="
" + else + dat+="None" + dat+="
Back
" + if(19) + dat+="Wanted issue for [src.admincaster_wanted_message.criminal] successfully edited.

" + dat+="
Return
" + else + dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com" + + usr << browse(dat, "window=admincaster_main;size=400x600") + onclose(usr, "admincaster_main") + + +/datum/admins/proc/Game() + if(!check_rights(0)) + return + + var/dat = {" +
Game Panel

\n + Change Game Mode
+ "} + if(GLOB.master_mode == "secret") + dat += "(Force Secret Mode)
" + + if(GLOB.master_mode == "dynamic") + if(SSticker.current_state <= GAME_STATE_PREGAME) + dat += "(Force Roundstart Rulesets)
" + if (GLOB.dynamic_forced_roundstart_ruleset.len > 0) + for(var/datum/dynamic_ruleset/roundstart/rule in GLOB.dynamic_forced_roundstart_ruleset) + dat += {"-> [rule.name] <-
"} + dat += "(Clear Rulesets)
" + dat += "(Dynamic mode options)
" + else if (SSticker.IsRoundInProgress()) + dat += "(Force Next Latejoin Ruleset)
" + if (SSticker && SSticker.mode && istype(SSticker.mode,/datum/game_mode/dynamic)) + var/datum/game_mode/dynamic/mode = SSticker.mode + if (mode.forced_latejoin_rule) + dat += {"-> [mode.forced_latejoin_rule.name] <-
"} + dat += "(Execute Midround Ruleset!)
" + dat += "
" + if(SSticker.IsRoundInProgress()) + dat += "(Game Mode Panel)
" + + dat += {" +
+ Create Object
+ Quick Create Object
+ Create Turf
+ Create Mob
+ "} + + if(marked_datum && istype(marked_datum, /atom)) + dat += "Duplicate Marked Datum
" + + usr << browse(dat, "window=admin2;size=210x200") + return + +/////////////////////////////////////////////////////////////////////////////////////////////////admins2.dm merge +//i.e. buttons/verbs + + +/datum/admins/proc/restart() + set category = "Server" + set name = "Reboot World" + set desc="Restarts the world immediately" + if (!usr.client.holder) + return + + var/list/options = list("Regular Restart", "Hard Restart (No Delay/Feeback Reason)", "Hardest Restart (No actions, just reboot)") + if(world.TgsAvailable()) + options += "Server Restart (Kill and restart DD)"; + + var/rebootconfirm + if(SSticker.admin_delay_notice) + if(alert(usr, "Are you sure? An admin has already delayed the round end for the following reason: [SSticker.admin_delay_notice]", "Confirmation", "Yes", "No") == "Yes") + rebootconfirm = TRUE + else + rebootconfirm = TRUE + if(rebootconfirm) + var/result = input(usr, "Select reboot method", "World Reboot", options[1]) as null|anything in options + if(result) + SSblackbox.record_feedback("tally", "admin_verb", 1, "Reboot World") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + var/init_by = "Initiated by [usr.client.holder.fakekey ? "Admin" : usr.key]." + switch(result) + if("Regular Restart") + SSticker.Reboot(init_by, "admin reboot - by [usr.key] [usr.client.holder.fakekey ? "(stealth)" : ""]", 10) + if("Hard Restart (No Delay, No Feeback Reason)") + to_chat(world, "World reboot - [init_by]") + world.Reboot() + if("Hardest Restart (No actions, just reboot)") + to_chat(world, "Hard world reboot - [init_by]") + world.Reboot(fast_track = TRUE) + if("Server Restart (Kill and restart DD)") + to_chat(world, "Server restart - [init_by]") + world.TgsEndProcess() + +/datum/admins/proc/end_round() + set category = "Server" + set name = "End Round" + set desc = "Attempts to produce a round end report and then restart the server organically." + + if (!usr.client.holder) + return + var/confirm = alert("End the round and restart the game world?", "End Round", "Yes", "Cancel") + if(confirm == "Cancel") + return + if(confirm == "Yes") + SSticker.force_ending = 1 + SSblackbox.record_feedback("tally", "admin_verb", 1, "End Round") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +/datum/admins/proc/announce() + set category = "Special Verbs" + set name = "Announce" + set desc="Announce your desires to the world" + if(!check_rights(0)) + return + + var/message = input("Global message to send:", "Admin Announce", null, null) as message + if(message) + if(!check_rights(R_SERVER,0)) + message = adminscrub(message,500) + to_chat(world, "[usr.client.holder.fakekey ? "Administrator" : usr.key] Announces:\n \t [message]") + log_admin("Announce: [key_name(usr)] : [message]") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Announce") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/set_admin_notice() + set category = "Special Verbs" + set name = "Set Admin Notice" + set desc ="Set an announcement that appears to everyone who joins the server. Only lasts this round" + if(!check_rights(0)) + return + + var/new_admin_notice = input(src,"Set a public notice for this round. Everyone who joins the server will see it.\n(Leaving it blank will delete the current notice):","Set Notice",GLOB.admin_notice) as message|null + if(new_admin_notice == null) + return + if(new_admin_notice == GLOB.admin_notice) + return + if(new_admin_notice == "") + message_admins("[key_name(usr)] removed the admin notice.") + log_admin("[key_name(usr)] removed the admin notice:\n[GLOB.admin_notice]") + else + message_admins("[key_name(usr)] set the admin notice.") + log_admin("[key_name(usr)] set the admin notice:\n[new_admin_notice]") + to_chat(world, "Admin Notice:\n \t [new_admin_notice]") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Set Admin Notice") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + GLOB.admin_notice = new_admin_notice + return + +/datum/admins/proc/toggleooc() + set category = "Server" + set desc="Toggle dis bitch" + set name="Toggle OOC" + toggle_ooc() + log_admin("[key_name(usr)] toggled OOC.") + message_admins("[key_name_admin(usr)] toggled OOC.") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle OOC", "[GLOB.ooc_allowed ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/toggleooclocal() + set category = "Server" + set desc="Toggle dat bitch" + set name="Toggle Local OOC" + toggle_looc() + log_admin("[key_name(usr)] toggled LOOC.") + message_admins("[key_name_admin(usr)] toggled LOOC.") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Local OOC", "[GLOB.ooc_allowed ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/toggleoocdead() + set category = "Server" + set desc="Toggle dis bitch" + set name="Toggle Dead OOC" + toggle_dooc() + + log_admin("[key_name(usr)] toggled Dead OOC.") + message_admins("[key_name_admin(usr)] toggled Dead OOC.") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Dead OOC", "[GLOB.dooc_allowed ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/toggleaooc() + set category = "Server" + set desc="Toggle to bitch" + set name="Toggle Antag OOC" + toggle_aooc() + log_admin("[key_name(usr)] toggled Antagonist OOC.") + message_admins("[key_name_admin(usr)] toggled Antagonist OOC.") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Antag OOC", "[GLOB.aooc_allowed ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/startnow() + set category = "Server" + set desc="Start the round RIGHT NOW" + set name="Start Now" + if(SSticker.current_state == GAME_STATE_PREGAME || SSticker.current_state == GAME_STATE_STARTUP) + SSticker.start_immediately = TRUE + log_admin("[usr.key] has started the game.") + var/msg = "" + if(SSticker.current_state == GAME_STATE_STARTUP) + msg = " (The server is still setting up, but the round will be \ + started as soon as possible.)" + message_admins("\ + [usr.key] has started the game.[msg]") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Start Now") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return 1 + else + to_chat(usr, "Error: Start Now: Game has already started.") + + return 0 + +/datum/admins/proc/toggleenter() + set category = "Server" + set desc="People can't enter" + set name="Toggle Entering" + GLOB.enter_allowed = !( GLOB.enter_allowed ) + if (!( GLOB.enter_allowed )) + to_chat(world, "New players may no longer enter the game.") + else + to_chat(world, "New players may now enter the game.") + log_admin("[key_name(usr)] toggled new player game entering.") + message_admins("[key_name_admin(usr)] toggled new player game entering.") + world.update_status() + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Entering", "[GLOB.enter_allowed ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/toggleAI() + set category = "Server" + set desc="People can't be AI" + set name="Toggle AI" + var/alai = CONFIG_GET(flag/allow_ai) + CONFIG_SET(flag/allow_ai, !alai) + if (alai) + to_chat(world, "The AI job is no longer chooseable.") + else + to_chat(world, "The AI job is chooseable now.") + log_admin("[key_name(usr)] toggled AI allowed.") + world.update_status() + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle AI", "[!alai ? "Disabled" : "Enabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/toggleMulticam() + set category = "Server" + set desc="Turns mutlicam on and off." + set name="Toggle Multicam" + var/almcam = CONFIG_GET(flag/allow_ai_multicam) + CONFIG_SET(flag/allow_ai_multicam, !almcam) + if (almcam) + to_chat(world, "The AI no longer has multicam.") + for(var/i in GLOB.ai_list) + var/mob/living/silicon/ai/aiPlayer = i + if(aiPlayer.multicam_on) + aiPlayer.end_multicam() + else + to_chat(world, "The AI now has multicam.") + log_admin("[key_name(usr)] toggled AI multicam.") + world.update_status() + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Multicam", "[!almcam ? "Disabled" : "Enabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/toggleaban() + set category = "Server" + set desc="Respawn basically" + set name="Toggle Respawn" + var/new_nores = !CONFIG_GET(flag/norespawn) + CONFIG_SET(flag/norespawn, new_nores) + if (!new_nores) + to_chat(world, "You may now respawn.") + else + to_chat(world, "You may no longer respawn :(") + message_admins("[key_name_admin(usr)] toggled respawn to [!new_nores ? "On" : "Off"].") + log_admin("[key_name(usr)] toggled respawn to [!new_nores ? "On" : "Off"].") + world.update_status() + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Respawn", "[!new_nores ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/delay() + set category = "Server" + set desc="Delay the game start" + set name="Delay pre-game" + + var/newtime = input("Set a new time in seconds. Set -1 for indefinite delay.","Set Delay",round(SSticker.GetTimeLeft()/10)) as num|null + if(SSticker.current_state > GAME_STATE_PREGAME) + return alert("Too late... The game has already started!") + if(newtime) + newtime = newtime*10 + SSticker.SetTimeLeft(newtime) + if(newtime < 0) + to_chat(world, "The game start has been delayed.") + log_admin("[key_name(usr)] delayed the round start.") + else + to_chat(world, "The game will start in [DisplayTimeText(newtime)].") + SEND_SOUND(world, sound('sound/ai/attention.ogg')) + log_admin("[key_name(usr)] set the pre-game delay to [DisplayTimeText(newtime)].") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Delay Game Start") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/unprison(mob/M in GLOB.mob_list) + set category = "Admin" + set name = "Unprison" + if (is_centcom_level(M.z)) + SSjob.SendToLateJoin(M) + message_admins("[key_name_admin(usr)] has unprisoned [key_name_admin(M)]") + log_admin("[key_name(usr)] has unprisoned [key_name(M)]") + else + alert("[M.name] is not prisoned.") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Unprison") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +////////////////////////////////////////////////////////////////////////////////////////////////ADMIN HELPER PROCS + +/datum/admins/proc/spawn_atom(object as text) + set category = "Debug" + set desc = "(atom path) Spawn an atom" + set name = "Spawn" + + if(!check_rights(R_SPAWN)) + return + var/turf/T = get_turf(usr) + + var/chosen = pick_closest_path(object) + if(!chosen) + return + if(ispath(chosen, /turf)) + T.ChangeTurf(chosen) + else + var/atom/A = new chosen(T) + A.flags_1 |= ADMIN_SPAWNED_1 + + log_admin("[key_name(usr)] spawned [chosen] at [AREACOORD(usr)]") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Spawn Atom") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/podspawn_atom(object as text) + set category = "Debug" + set desc = "(atom path) Spawn an atom via supply drop" + set name = "Podspawn" + + if(!check_rights(R_SPAWN)) + return + + var/chosen = pick_closest_path(object) + if(!chosen) + return + var/turf/T = get_turf(usr) + + if(ispath(chosen, /turf)) + T.ChangeTurf(chosen) + else + var/obj/structure/closet/supplypod/centcompod/pod = new() + var/atom/A = new chosen(pod) + A.flags_1 |= ADMIN_SPAWNED_1 + new /obj/effect/abstract/DPtarget(T, pod) + + log_admin("[key_name(usr)] pod-spawned [chosen] at [AREACOORD(usr)]") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Podspawn Atom") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/spawn_cargo(object as text) + set category = "Debug" + set desc = "(atom path) Spawn a cargo crate" + set name = "Spawn Cargo" + + if(!check_rights(R_SPAWN)) + return + + var/chosen = pick_closest_path(object, make_types_fancy(subtypesof(/datum/supply_pack))) + if(!chosen) + return + var/datum/supply_pack/S = new chosen + S.admin_spawned = TRUE + S.generate(get_turf(usr)) + + log_admin("[key_name(usr)] spawned cargo pack [chosen] at [AREACOORD(usr)]") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Spawn Cargo") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +/datum/admins/proc/show_traitor_panel(mob/M in GLOB.mob_list) + set category = "Admin" + set desc = "Edit mobs's memory and role" + set name = "Show Traitor Panel" + + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + if(!M.mind) + to_chat(usr, "This mob has no mind!") + return + + M.mind.traitor_panel() + SSblackbox.record_feedback("tally", "admin_verb", 1, "Traitor Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +/datum/admins/proc/toggletintedweldhelmets() + set category = "Debug" + set desc="Reduces view range when wearing welding helmets" + set name="Toggle tinted welding helmes" + GLOB.tinted_weldhelh = !( GLOB.tinted_weldhelh ) + if (GLOB.tinted_weldhelh) + to_chat(world, "The tinted_weldhelh has been enabled!") + else + to_chat(world, "The tinted_weldhelh has been disabled!") + log_admin("[key_name(usr)] toggled tinted_weldhelh.") + message_admins("[key_name_admin(usr)] toggled tinted_weldhelh.") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Tinted Welding Helmets", "[GLOB.tinted_weldhelh ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/toggleguests() + set category = "Server" + set desc="Guests can't enter" + set name="Toggle guests" + var/new_guest_ban = !CONFIG_GET(flag/guest_ban) + CONFIG_SET(flag/guest_ban, new_guest_ban) + if (new_guest_ban) + to_chat(world, "Guests may no longer enter the game.") + else + to_chat(world, "Guests may now enter the game.") + log_admin("[key_name(usr)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.") + message_admins("[key_name_admin(usr)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Guests", "[!new_guest_ban ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/output_ai_laws() + var/ai_number = 0 + for(var/i in GLOB.silicon_mobs) + var/mob/living/silicon/S = i + ai_number++ + if(isAI(S)) + to_chat(usr, "AI [key_name(S, usr)]'s laws:") + else if(iscyborg(S)) + var/mob/living/silicon/robot/R = S + to_chat(usr, "CYBORG [key_name(S, usr)] [R.connected_ai?"(Slaved to: [key_name(R.connected_ai)])":"(Independent)"]: laws:") + else if (ispAI(S)) + to_chat(usr, "pAI [key_name(S, usr)]'s laws:") + else + to_chat(usr, "SOMETHING SILICON [key_name(S, usr)]'s laws:") + + if (S.laws == null) + to_chat(usr, "[key_name(S, usr)]'s laws are null?? Contact a coder.") + else + S.laws.show_laws(usr) + if(!ai_number) + to_chat(usr, "No AIs located" ) + +/datum/admins/proc/output_all_devil_info() + var/devil_number = 0 + for(var/datum/mind/D in SSticker.mode.devils) + devil_number++ + var/datum/antagonist/devil/devil = D.has_antag_datum(/datum/antagonist/devil) + to_chat(usr, "Devil #[devil_number]:

" + devil.printdevilinfo()) + if(!devil_number) + to_chat(usr, "No Devils located" ) + +/datum/admins/proc/output_devil_info(mob/living/M) + if(is_devil(M)) + var/datum/antagonist/devil/devil = M.mind.has_antag_datum(/datum/antagonist/devil) + to_chat(usr, devil.printdevilinfo()) + else + to_chat(usr, "[M] is not a devil.") + +/datum/admins/proc/manage_free_slots() + if(!check_rights()) + return + var/datum/browser/browser = new(usr, "jobmanagement", "Manage Free Slots", 520) + var/list/dat = list() + var/count = 0 + + if(!SSjob.initialized) + alert(usr, "You cannot manage jobs before the job subsystem is initialized!") + return + + dat += "
[J_title]: [J_opPos]/[job.total_positions < 0 ? " (unlimited)" : J_totPos]" - - dat += "" - if(job.total_positions >= 0) - dat += "Custom | " - dat += "Add 1 | " - if(job.total_positions > job.current_positions) - dat += "Remove | " - else - dat += "Remove | " - dat += "Unlimit
" + + for(var/j in SSjob.occupations) + var/datum/job/job = j + count++ + var/J_title = html_encode(job.title) + var/J_opPos = html_encode(job.total_positions - (job.total_positions - job.current_positions)) + var/J_totPos = html_encode(job.total_positions) + dat += "" + dat += "" + else + dat += "Limit" + + browser.height = min(100 + count * 20, 650) + browser.set_content(dat.Join()) + browser.open() + +/datum/admins/proc/dynamic_mode_options(mob/user) + var/dat = {" +

Dynamic Mode Options


+
+

Common options

+ All these options can be changed midround.
+
+ Force extended: - Option is [GLOB.dynamic_forced_extended ? "ON" : "OFF"]. +
This will force the round to be extended. No rulesets will be drafted.
+
+ No stacking: - Option is [GLOB.dynamic_no_stacking ? "ON" : "OFF"]. +
Unless the threat goes above [GLOB.dynamic_stacking_limit], only one "round-ender" ruleset will be drafted.
+
+ Classic secret mode: - Option is [GLOB.dynamic_classic_secret ? "ON" : "OFF"]. +
Only one roundstart ruleset will be drafted. Only traitors and minor roles will latespawn.
+
+
+ Chaos level: Current value : [GLOB.dynamic_chaos_level]. +
The Chaos value for the round. Only set between 0 and 5!
+
+ Forced threat level: Current value : [GLOB.dynamic_forced_threat_level]. +
The value threat is set to if it is higher than -1.
+
+ High population limit: Current value : [GLOB.dynamic_high_pop_limit]. +
The threshold at which "high population override" will be in effect.
+
+ Stacking threeshold: Current value : [GLOB.dynamic_stacking_limit]. +
The threshold at which "round-ender" rulesets will stack. A value higher than 100 ensure this never happens.
+

Advanced parameters

+ Curve centre: -> [GLOB.dynamic_curve_centre] <-
+ Curve width: -> [GLOB.dynamic_curve_width] <-
+ Latejoin injection delay:
+ Minimum: -> [GLOB.dynamic_latejoin_delay_min / 60 / 10] <- Minutes
+ Maximum: -> [GLOB.dynamic_latejoin_delay_max / 60 / 10] <- Minutes
+ Midround injection delay:
+ Minimum: -> [GLOB.dynamic_midround_delay_min / 60 / 10] <- Minutes
+ Maximum: -> [GLOB.dynamic_midround_delay_max / 60 / 10] <- Minutes
+ "} + + user << browse(dat, "window=dyn_mode_options;size=900x650") + +/datum/admins/proc/create_or_modify_area() + set category = "Debug" + set name = "Create or modify area" + create_area(usr) + +// +// +//ALL DONE +//********************************************************************************************************* +//TO-DO: +// +// + +//RIP ferry snowflakes + +//Kicks all the clients currently in the lobby. The second parameter (kick_only_afk) determins if an is_afk() check is ran, or if all clients are kicked +//defaults to kicking everyone (afk + non afk clients in the lobby) +//returns a list of ckeys of the kicked clients +/proc/kick_clients_in_lobby(message, kick_only_afk = 0) + var/list/kicked_client_names = list() + for(var/client/C in GLOB.clients) + if(isnewplayer(C.mob)) + if(kick_only_afk && !C.is_afk()) //Ignore clients who are not afk + continue + if(message) + to_chat(C, message) + kicked_client_names.Add("[C.key]") + qdel(C) + return kicked_client_names + +//returns 1 to let the dragdrop code know we are trapping this event +//returns 0 if we don't plan to trap the event +/datum/admins/proc/cmd_ghost_drag(mob/dead/observer/frommob, mob/tomob) + + //this is the exact two check rights checks required to edit a ckey with vv. + if (!check_rights(R_VAREDIT,0) || !check_rights(R_SPAWN|R_DEBUG,0)) + return 0 + + if (!frommob.ckey) + return 0 + + var/question = "" + if (tomob.ckey) + question = "This mob already has a user ([tomob.key]) in control of it! " + question += "Are you sure you want to place [frommob.name]([frommob.key]) in control of [tomob.name]?" + + var/ask = alert(question, "Place ghost in control of mob?", "Yes", "No") + if (ask != "Yes") + return 1 + + if (!frommob || !tomob) //make sure the mobs don't go away while we waited for a response + return 1 + + tomob.ghostize(0) + + message_admins("[key_name_admin(usr)] has put [frommob.key] in control of [tomob.name].") + log_admin("[key_name(usr)] stuffed [frommob.key] into [tomob.name].") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Ghost Drag Control") + + tomob.ckey = frommob.ckey + qdel(frommob) + + return 1 + +/client/proc/adminGreet(logout) + if(SSticker.HasRoundStarted()) + var/string + if(logout && CONFIG_GET(flag/announce_admin_logout)) + string = pick( + "Admin logout: [key_name(src)]") + else if(!logout && CONFIG_GET(flag/announce_admin_login) && (prefs.toggles & ANNOUNCE_LOGIN)) + string = pick( + "Admin login: [key_name(src)]") + if(string) + message_admins("[string]") + +/client/proc/cmd_admin_man_up(mob/M in GLOB.mob_list) + set category = "Special Verbs" + set name = "Man Up" + + if(!M) + return + if(!check_rights(R_ADMIN)) + return + + to_chat(M, "Man up, and deal with it.
Move on.") + M.playsound_local(M, 'modular_citadel/sound/misc/manup.ogg', 50, FALSE, pressure_affected = FALSE) + + log_admin("Man up: [key_name(usr)] told [key_name(M)] to man up") + var/message = "[key_name_admin(usr)] told [key_name_admin(M)] to man up." + message_admins(message) + admin_ticket_log(M, message) + SSblackbox.record_feedback("tally", "admin_verb", 1, "Man Up") + +/client/proc/cmd_admin_man_up_global() + set category = "Special Verbs" + set name = "Man Up Global" + + if(!check_rights(R_ADMIN)) + return + + to_chat(world, "Man up, and deal with it.
Move on.") + for(var/mob/M in GLOB.player_list) + M.playsound_local(M, 'modular_citadel/sound/misc/manup.ogg', 50, FALSE, pressure_affected = FALSE) + + log_admin("Man up global: [key_name(usr)] told everybody to man up") + message_admins("[key_name_admin(usr)] told everybody to man up.") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Man Up Global") diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 5116e9c6..0ab823e2 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -112,7 +112,7 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list( /client/proc/roll_dices //CIT CHANGE - Adds dice verb )) GLOBAL_PROTECT(admin_verbs_spawn) -GLOBAL_LIST_INIT(admin_verbs_spawn, list(/datum/admins/proc/spawn_atom, /datum/admins/proc/spawn_cargo, /datum/admins/proc/spawn_objasmob, /client/proc/respawn_character)) +GLOBAL_LIST_INIT(admin_verbs_spawn, list(/datum/admins/proc/spawn_atom, /datum/admins/proc/podspawn_atom, /datum/admins/proc/spawn_cargo, /datum/admins/proc/spawn_objasmob, /client/proc/respawn_character)) GLOBAL_PROTECT(admin_verbs_server) GLOBAL_LIST_INIT(admin_verbs_server, world.AVerbsServer()) /world/proc/AVerbsServer() diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 101d659c..545afad9 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1,2983 +1,2992 @@ -/datum/admins/proc/CheckAdminHref(href, href_list) - var/auth = href_list["admin_token"] - . = auth && (auth == href_token || auth == GLOB.href_token) - if(.) - return - var/msg = !auth ? "no" : "a bad" - message_admins("[key_name_admin(usr)] clicked an href with [msg] authorization key!") - if(CONFIG_GET(flag/debug_admin_hrefs)) - message_admins("Debug mode enabled, call not blocked. Please ask your coders to review this round's logs.") - log_world("UAH: [href]") - return TRUE - log_admin_private("[key_name(usr)] clicked an href with [msg] authorization key! [href]") - -/datum/admins/Topic(href, href_list) - ..() - - if(usr.client != src.owner || !check_rights(0)) - message_admins("[usr.key] tried to use the admin panel without authorization.") - log_admin("[key_name(usr)] tried to use the admin panel without authorization.") - return - - if(!CheckAdminHref(href, href_list)) - return - - if(href_list["makementor"]) - makeMentor(href_list["makementor"]) - else if(href_list["removementor"]) - removeMentor(href_list["removementor"]) - - if(href_list["ahelp"]) - if(!check_rights(R_ADMIN, TRUE)) - return - - var/ahelp_ref = href_list["ahelp"] - var/datum/admin_help/AH = locate(ahelp_ref) - if(AH) - AH.Action(href_list["ahelp_action"]) - else - to_chat(usr, "Ticket [ahelp_ref] has been deleted!") - - else if(href_list["ahelp_tickets"]) - GLOB.ahelp_tickets.BrowseTickets(text2num(href_list["ahelp_tickets"])) - - else if(href_list["stickyban"]) - stickyban(href_list["stickyban"],href_list) - - else if(href_list["getplaytimewindow"]) - if(!check_rights(R_ADMIN)) - return - var/mob/M = locate(href_list["getplaytimewindow"]) in GLOB.mob_list - if(!M) - to_chat(usr, "ERROR: Mob not found.") - return - cmd_show_exp_panel(M.client) - - else if(href_list["toggleexempt"]) - if(!check_rights(R_ADMIN)) - return - var/client/C = locate(href_list["toggleexempt"]) in GLOB.clients - if(!C) - to_chat(usr, "ERROR: Client not found.") - return - toggle_exempt_status(C) - - else if(href_list["makeAntag"]) - if(!check_rights(R_ADMIN)) - return - if (!SSticker.mode) - to_chat(usr, "Not until the round starts!") - return - switch(href_list["makeAntag"]) - if("traitors") - if(src.makeTraitors()) - message_admins("[key_name_admin(usr)] created traitors.") - log_admin("[key_name(usr)] created traitors.") - else - message_admins("[key_name_admin(usr)] tried to create traitors. Unfortunately, there were no candidates available.") - log_admin("[key_name(usr)] failed to create traitors.") - if("changelings") - if(src.makeChangelings()) - message_admins("[key_name(usr)] created changelings.") - log_admin("[key_name(usr)] created changelings.") - else - message_admins("[key_name_admin(usr)] tried to create changelings. Unfortunately, there were no candidates available.") - log_admin("[key_name(usr)] failed to create changelings.") - if("revs") - if(src.makeRevs()) - message_admins("[key_name(usr)] started a revolution.") - log_admin("[key_name(usr)] started a revolution.") - else - message_admins("[key_name_admin(usr)] tried to start a revolution. Unfortunately, there were no candidates available.") - log_admin("[key_name(usr)] failed to start a revolution.") - if("cult") - if(src.makeCult()) - message_admins("[key_name(usr)] started a cult.") - log_admin("[key_name(usr)] started a cult.") - else - message_admins("[key_name_admin(usr)] tried to start a cult. Unfortunately, there were no candidates available.") - log_admin("[key_name(usr)] failed to start a cult.") - if("wizard") - message_admins("[key_name(usr)] is creating a wizard...") - if(src.makeWizard()) - message_admins("[key_name(usr)] created a wizard.") - log_admin("[key_name(usr)] created a wizard.") - else - message_admins("[key_name_admin(usr)] tried to create a wizard. Unfortunately, there were no candidates available.") - log_admin("[key_name(usr)] failed to create a wizard.") - if("nukeops") - message_admins("[key_name(usr)] is creating a nuke team...") - if(src.makeNukeTeam()) - message_admins("[key_name(usr)] created a nuke team.") - log_admin("[key_name(usr)] created a nuke team.") - 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("ninja") - message_admins("[key_name(usr)] spawned a ninja.") - log_admin("[key_name(usr)] spawned a ninja.") - src.makeSpaceNinja() - if("aliens") - message_admins("[key_name(usr)] started an alien infestation.") - log_admin("[key_name(usr)] started an alien infestation.") - src.makeAliens() - if("deathsquad") - message_admins("[key_name(usr)] is creating a death squad...") - if(src.makeDeathsquad()) - message_admins("[key_name(usr)] created a death squad.") - log_admin("[key_name(usr)] created a death squad.") - else - message_admins("[key_name_admin(usr)] tried to create a death squad. Unfortunately, there were not enough candidates available.") - log_admin("[key_name(usr)] failed to create a death squad.") - if("blob") - var/strength = input("Set Blob Resource Gain Rate","Set Resource Rate",1) as num|null - if(!strength) - return - message_admins("[key_name(usr)] spawned a blob with base resource gain [strength].") - log_admin("[key_name(usr)] spawned a blob with base resource gain [strength].") - new/datum/round_event/ghost_role/blob(TRUE, strength) - if("centcom") - message_admins("[key_name(usr)] is creating a CentCom response team...") - if(src.makeEmergencyresponseteam()) - message_admins("[key_name(usr)] created a CentCom response team.") - log_admin("[key_name(usr)] created a CentCom response team.") - else - message_admins("[key_name_admin(usr)] tried to create a CentCom response team. Unfortunately, there were not enough candidates available.") - log_admin("[key_name(usr)] failed to create a CentCom response team.") - if("abductors") - message_admins("[key_name(usr)] is creating an abductor team...") - if(src.makeAbductorTeam()) - message_admins("[key_name(usr)] created an abductor team.") - log_admin("[key_name(usr)] created an abductor team.") - else - message_admins("[key_name_admin(usr)] tried to create an abductor team. Unfortunatly there were not enough candidates available.") - log_admin("[key_name(usr)] failed to create an abductor team.") - if("clockcult") - if(src.makeClockCult()) - message_admins("[key_name(usr)] started a clockwork cult.") - log_admin("[key_name(usr)] started a clockwork cult.") - else - message_admins("[key_name_admin(usr)] tried to start a clockwork cult. Unfortunately, there were no candidates available.") - log_admin("[key_name(usr)] failed to start a clockwork cult.") - if("revenant") - if(src.makeRevenant()) - message_admins("[key_name(usr)] created a revenant.") - log_admin("[key_name(usr)] created a revenant.") - else - message_admins("[key_name_admin(usr)] tried to create a revenant. Unfortunately, there were no candidates available.") - log_admin("[key_name(usr)] failed to create a revenant.") - //Hyper - if("lewdtraitors") - if(src.makeLewdtraitors()) - message_admins("[key_name(usr)] created a lewd traitor.") - log_admin("[key_name(usr)] created a lewd traitor.") - else - message_admins("[key_name_admin(usr)] tried to create a lewd traitor. Unfortunately, there were no candidates available.") - log_admin("[key_name(usr)] failed to create a lewd traitor.") - - else if(href_list["forceevent"]) - if(!check_rights(R_FUN)) - return - var/datum/round_event_control/E = locate(href_list["forceevent"]) in SSevents.control - if(E) - E.admin_setup(usr) - var/datum/round_event/event = E.runEvent() - if(event.announceWhen>0) - event.processing = FALSE - var/prompt = alert(usr, "Would you like to alert the crew?", "Alert", "Yes", "No", "Cancel") - switch(prompt) - if("Cancel") - event.kill() - return - if("No") - event.announceWhen = -1 - event.processing = TRUE - message_admins("[key_name_admin(usr)] has triggered an event. ([E.name])") - log_admin("[key_name(usr)] has triggered an event. ([E.name])") - return - - else if(href_list["dbsearchckey"] || href_list["dbsearchadmin"] || href_list["dbsearchip"] || href_list["dbsearchcid"]) - var/adminckey = href_list["dbsearchadmin"] - var/playerckey = href_list["dbsearchckey"] - var/ip = href_list["dbsearchip"] - var/cid = href_list["dbsearchcid"] - var/page = href_list["dbsearchpage"] - - DB_ban_panel(playerckey, adminckey, ip, cid, page) - return - - else if(href_list["dbbanedit"]) - var/banedit = href_list["dbbanedit"] - var/banid = text2num(href_list["dbbanid"]) - if(!banedit || !banid) - return - - DB_ban_edit(banid, banedit) - return - - else if(href_list["dbbanaddtype"]) - if(!check_rights(R_BAN)) - return - var/bantype = text2num(href_list["dbbanaddtype"]) - var/bankey = href_list["dbbanaddkey"] - var/banckey = ckey(bankey) - var/banip = href_list["dbbanaddip"] - var/bancid = href_list["dbbanaddcid"] - var/banduration = text2num(href_list["dbbaddduration"]) - var/banjob = href_list["dbbanaddjob"] - var/banreason = href_list["dbbanreason"] - var/banseverity = href_list["dbbanaddseverity"] - - switch(bantype) - if(BANTYPE_PERMA) - if(!banckey || !banreason || !banseverity) - to_chat(usr, "Not enough parameters (Requires ckey, severity, and reason).") - return - banduration = null - banjob = null - if(BANTYPE_TEMP) - if(!banckey || !banreason || !banduration || !banseverity) - to_chat(usr, "Not enough parameters (Requires ckey, reason, severity and duration).") - return - banjob = null - if(BANTYPE_JOB_PERMA) - if(!banckey || !banreason || !banjob || !banseverity) - to_chat(usr, "Not enough parameters (Requires ckey, severity, reason and job).") - return - banduration = null - if(BANTYPE_JOB_TEMP) - if(!banckey || !banreason || !banjob || !banduration || !banseverity) - to_chat(usr, "Not enough parameters (Requires ckey, severity, reason and job).") - return - if(BANTYPE_ADMIN_PERMA) - if(!banckey || !banreason || !banseverity) - to_chat(usr, "Not enough parameters (Requires ckey, severity and reason).") - return - banduration = null - banjob = null - if(BANTYPE_ADMIN_TEMP) - if(!banckey || !banreason || !banduration || !banseverity) - to_chat(usr, "Not enough parameters (Requires ckey, severity, reason and duration).") - return - banjob = null - - var/mob/playermob - - for(var/mob/M in GLOB.player_list) - if(M.ckey == banckey) - playermob = M - break - - - banreason = "(MANUAL BAN) "+banreason - - if(!playermob) - if(banip) - banreason = "[banreason] (CUSTOM IP)" - if(bancid) - banreason = "[banreason] (CUSTOM CID)" - else - message_admins("Ban process: A mob matching [playermob.key] was found at location [playermob.x], [playermob.y], [playermob.z]. Custom ip and computer id fields replaced with the ip and computer id from the located mob.") - - if(!DB_ban_record(bantype, playermob, banduration, banreason, banjob, bankey, banip, bancid )) - to_chat(usr, "Failed to apply ban.") - return - create_message("note", bankey, null, banreason, null, null, 0, 0, null, 0, banseverity) - - else if(href_list["editrightsbrowser"]) - edit_admin_permissions(0) - - else if(href_list["editrightsbrowserlog"]) - edit_admin_permissions(1, href_list["editrightstarget"], href_list["editrightsoperation"], href_list["editrightspage"]) - - if(href_list["editrightsbrowsermanage"]) - if(href_list["editrightschange"]) - change_admin_rank(ckey(href_list["editrightschange"]), href_list["editrightschange"], TRUE) - else if(href_list["editrightsremove"]) - remove_admin(ckey(href_list["editrightsremove"]), href_list["editrightsremove"], TRUE) - else if(href_list["editrightsremoverank"]) - remove_rank(href_list["editrightsremoverank"]) - edit_admin_permissions(2) - - else if(href_list["editrights"]) - edit_rights_topic(href_list) - - else if(href_list["gamemode_panel"]) - if(!check_rights(R_ADMIN)) - return - SSticker.mode.admin_panel() - - - else if(href_list["call_shuttle"]) - if(!check_rights(R_ADMIN)) - return - - - switch(href_list["call_shuttle"]) - if("1") - if(EMERGENCY_AT_LEAST_DOCKED) - return - SSshuttle.emergency.request() - log_admin("[key_name(usr)] called the Emergency Shuttle.") - message_admins("[key_name_admin(usr)] called the Emergency Shuttle to the station.") - - if("2") - if(EMERGENCY_AT_LEAST_DOCKED) - return - switch(SSshuttle.emergency.mode) - if(SHUTTLE_CALL) - SSshuttle.emergency.cancel() - log_admin("[key_name(usr)] sent the Emergency Shuttle back.") - message_admins("[key_name_admin(usr)] sent the Emergency Shuttle back.") - else - SSshuttle.emergency.cancel() - log_admin("[key_name(usr)] called the Emergency Shuttle.") - message_admins("[key_name_admin(usr)] called the Emergency Shuttle to the station.") - - - href_list["secrets"] = "check_antagonist" - - else if(href_list["edit_shuttle_time"]) - if(!check_rights(R_SERVER)) - return - - var/timer = input("Enter new shuttle duration (seconds):","Edit Shuttle Timeleft", SSshuttle.emergency.timeLeft() ) as num|null - if(!timer) - return - SSshuttle.emergency.setTimer(timer*10) - log_admin("[key_name(usr)] edited the Emergency Shuttle's timeleft to [timer] seconds.") - minor_announce("The emergency shuttle will reach its destination in [round(SSshuttle.emergency.timeLeft(600))] minutes.") - message_admins("[key_name_admin(usr)] edited the Emergency Shuttle's timeleft to [timer] seconds.") - href_list["secrets"] = "check_antagonist" - else if(href_list["trigger_centcom_recall"]) - if(!check_rights(R_ADMIN)) - return - - usr.client.trigger_centcom_recall() - - else if(href_list["toggle_continuous"]) - if(!check_rights(R_ADMIN)) - return - var/list/continuous = CONFIG_GET(keyed_list/continuous) - if(!continuous[SSticker.mode.config_tag]) - continuous[SSticker.mode.config_tag] = TRUE - else - continuous[SSticker.mode.config_tag] = FALSE - - message_admins("[key_name_admin(usr)] toggled the round to [continuous[SSticker.mode.config_tag] ? "continue if all antagonists die" : "end with the antagonists"].") - check_antagonists() - - else if(href_list["toggle_midround_antag"]) - if(!check_rights(R_ADMIN)) - return - - var/list/midround_antag = CONFIG_GET(keyed_list/midround_antag) - if(!midround_antag[SSticker.mode.config_tag]) - midround_antag[SSticker.mode.config_tag] = TRUE - else - midround_antag[SSticker.mode.config_tag] = FALSE - - message_admins("[key_name_admin(usr)] toggled the round to [midround_antag[SSticker.mode.config_tag] ? "use" : "skip"] the midround antag system.") - check_antagonists() - - else if(href_list["alter_midround_time_limit"]) - if(!check_rights(R_ADMIN)) - return - - var/timer = input("Enter new maximum time",, CONFIG_GET(number/midround_antag_time_check)) as num|null - if(!timer) - return - CONFIG_SET(number/midround_antag_time_check, timer) - message_admins("[key_name_admin(usr)] edited the maximum midround antagonist time to [timer] minutes.") - check_antagonists() - - else if(href_list["alter_midround_life_limit"]) - if(!check_rights(R_ADMIN)) - return - - var/ratio = input("Enter new life ratio",, CONFIG_GET(number/midround_antag_life_check) * 100) as num - if(!ratio) - return - CONFIG_SET(number/midround_antag_life_check, ratio / 100) - - message_admins("[key_name_admin(usr)] edited the midround antagonist living crew ratio to [ratio]% alive.") - check_antagonists() - - else if(href_list["toggle_noncontinuous_behavior"]) - if(!check_rights(R_ADMIN)) - return - - if(!SSticker.mode.round_ends_with_antag_death) - SSticker.mode.round_ends_with_antag_death = 1 - else - SSticker.mode.round_ends_with_antag_death = 0 - - message_admins("[key_name_admin(usr)] edited the midround antagonist system to [SSticker.mode.round_ends_with_antag_death ? "end the round" : "continue as extended"] upon failure.") - check_antagonists() - - else if(href_list["delay_round_end"]) - if(!check_rights(R_SERVER)) - return - if(!SSticker.delay_end) - SSticker.admin_delay_notice = input(usr, "Enter a reason for delaying the round end", "Round Delay Reason") as null|text - if(isnull(SSticker.admin_delay_notice)) - return - else - SSticker.admin_delay_notice = null - SSticker.delay_end = !SSticker.delay_end - var/reason = SSticker.delay_end ? "for reason: [SSticker.admin_delay_notice]" : "."//laziness - var/msg = "[SSticker.delay_end ? "delayed" : "undelayed"] the round end [reason]" - log_admin("[key_name(usr)] [msg]") - message_admins("[key_name_admin(usr)] [msg]") - href_list["secrets"] = "check_antagonist" - if(SSticker.ready_for_reboot && !SSticker.delay_end) //we undelayed after standard reboot would occur - SSticker.standard_reboot() - - else if(href_list["end_round"]) - if(!check_rights(R_ADMIN)) - return - - message_admins("[key_name_admin(usr)] is considering ending the round.") - if(alert(usr, "This will end the round, are you SURE you want to do this?", "Confirmation", "Yes", "No") == "Yes") - if(alert(usr, "Final Confirmation: End the round NOW?", "Confirmation", "Yes", "No") == "Yes") - message_admins("[key_name_admin(usr)] has ended the round.") - SSticker.force_ending = 1 //Yeah there we go APC destroyed mission accomplished - return - else - message_admins("[key_name_admin(usr)] decided against ending the round.") - else - message_admins("[key_name_admin(usr)] decided against ending the round.") - - else if(href_list["simplemake"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/M = locate(href_list["mob"]) - if(!ismob(M)) - to_chat(usr, "This can only be used on instances of type /mob.") - return - - var/delmob = 0 - switch(alert("Delete old mob?","Message","Yes","No","Cancel")) - if("Cancel") - return - if("Yes") - delmob = 1 - - log_admin("[key_name(usr)] has used rudimentary transformation on [key_name(M)]. Transforming to [href_list["simplemake"]].; deletemob=[delmob]") - message_admins("[key_name_admin(usr)] has used rudimentary transformation on [key_name_admin(M)]. Transforming to [href_list["simplemake"]].; deletemob=[delmob]") - switch(href_list["simplemake"]) - if("observer") - M.change_mob_type( /mob/dead/observer , null, null, delmob ) - if("drone") - M.change_mob_type( /mob/living/carbon/alien/humanoid/drone , null, null, delmob ) - if("hunter") - M.change_mob_type( /mob/living/carbon/alien/humanoid/hunter , null, null, delmob ) - if("queen") - M.change_mob_type( /mob/living/carbon/alien/humanoid/royal/queen , null, null, delmob ) - if("praetorian") - M.change_mob_type( /mob/living/carbon/alien/humanoid/royal/praetorian , null, null, delmob ) - if("sentinel") - M.change_mob_type( /mob/living/carbon/alien/humanoid/sentinel , null, null, delmob ) - if("larva") - M.change_mob_type( /mob/living/carbon/alien/larva , null, null, delmob ) - if("human") - var/posttransformoutfit = usr.client.robust_dress_shop() - var/mob/living/carbon/human/newmob = M.change_mob_type( /mob/living/carbon/human , null, null, delmob ) - if(posttransformoutfit && istype(newmob)) - newmob.equipOutfit(posttransformoutfit) - if("slime") - M.change_mob_type( /mob/living/simple_animal/slime , null, null, delmob ) - if("monkey") - M.change_mob_type( /mob/living/carbon/monkey , null, null, delmob ) - if("robot") - M.change_mob_type( /mob/living/silicon/robot , null, null, delmob ) - if("cat") - M.change_mob_type( /mob/living/simple_animal/pet/cat , null, null, delmob ) - if("runtime") - M.change_mob_type( /mob/living/simple_animal/pet/cat/Runtime , null, null, delmob ) - if("corgi") - M.change_mob_type( /mob/living/simple_animal/pet/dog/corgi , null, null, delmob ) - if("ian") - M.change_mob_type( /mob/living/simple_animal/pet/dog/corgi/Ian , null, null, delmob ) - if("pug") - M.change_mob_type( /mob/living/simple_animal/pet/dog/pug , null, null, delmob ) - if("crab") - M.change_mob_type( /mob/living/simple_animal/crab , null, null, delmob ) - if("coffee") - M.change_mob_type( /mob/living/simple_animal/crab/Coffee , null, null, delmob ) - if("parrot") - M.change_mob_type( /mob/living/simple_animal/parrot , null, null, delmob ) - if("polyparrot") - M.change_mob_type( /mob/living/simple_animal/parrot/Poly , null, null, delmob ) - if("constructarmored") - M.change_mob_type( /mob/living/simple_animal/hostile/construct/armored , null, null, delmob ) - if("constructbuilder") - M.change_mob_type( /mob/living/simple_animal/hostile/construct/builder , null, null, delmob ) - if("constructwraith") - M.change_mob_type( /mob/living/simple_animal/hostile/construct/wraith , null, null, delmob ) - if("shade") - M.change_mob_type( /mob/living/simple_animal/shade , null, null, delmob ) - - - /////////////////////////////////////new ban stuff - else if(href_list["unbanf"]) - if(!check_rights(R_BAN)) - return - - var/banfolder = href_list["unbanf"] - GLOB.Banlist.cd = "/base/[banfolder]" - var/key = GLOB.Banlist["key"] - if(alert(usr, "Are you sure you want to unban [key]?", "Confirmation", "Yes", "No") == "Yes") - if(RemoveBan(banfolder)) - unbanpanel() - else - alert(usr, "This ban has already been lifted / does not exist.", "Error", "Ok") - unbanpanel() - - else if(href_list["unbane"]) - if(!check_rights(R_BAN)) - return - - UpdateTime() - var/reason - - var/banfolder = href_list["unbane"] - GLOB.Banlist.cd = "/base/[banfolder]" - var/reason2 = GLOB.Banlist["reason"] - var/temp = GLOB.Banlist["temp"] - - var/minutes = GLOB.Banlist["minutes"] - - var/banned_key = GLOB.Banlist["key"] - GLOB.Banlist.cd = "/base" - - var/duration - - switch(alert("Temporary Ban for [banned_key]?",,"Yes","No")) - if("Yes") - temp = 1 - var/mins = 0 - if(minutes > GLOB.CMinutes) - mins = minutes - GLOB.CMinutes - mins = input(usr,"How long (in minutes)? (Default: 1440)","Ban time",mins ? mins : 1440) as num|null - if(mins <= 0) - to_chat(usr, "[mins] is not a valid duration.") - return - minutes = GLOB.CMinutes + mins - duration = GetExp(minutes) - reason = input(usr,"Please State Reason For Banning [banned_key].","Reason",reason2) as message|null - if(!reason) - return - if("No") - temp = 0 - duration = "Perma" - reason = input(usr,"Please State Reason For Banning [banned_key].","Reason",reason2) as message|null - if(!reason) - return - - log_admin_private("[key_name(usr)] edited [banned_key]'s ban. Reason: [reason] Duration: [duration]") - ban_unban_log_save("[key_name(usr)] edited [banned_key]'s ban. Reason: [reason] Duration: [duration]") - message_admins("[key_name_admin(usr)] edited [banned_key]'s ban. Reason: [reason] Duration: [duration]") - GLOB.Banlist.cd = "/base/[banfolder]" - WRITE_FILE(GLOB.Banlist["reason"], reason) - WRITE_FILE(GLOB.Banlist["temp"], temp) - WRITE_FILE(GLOB.Banlist["minutes"], minutes) - WRITE_FILE(GLOB.Banlist["bannedby"], usr.ckey) - GLOB.Banlist.cd = "/base" - unbanpanel() - - /////////////////////////////////////new ban stuff - - else if(href_list["appearanceban"]) - if(!check_rights(R_BAN)) - return - var/mob/M = locate(href_list["appearanceban"]) - if(!ismob(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - if(!M.ckey) //sanity - to_chat(usr, "This mob has no ckey") - return - - - if(jobban_isbanned(M, "appearance")) - switch(alert("Remove appearance ban?","Please Confirm","Yes","No")) - if("Yes") - ban_unban_log_save("[key_name(usr)] removed [key_name(M)]'s appearance ban.") - log_admin_private("[key_name(usr)] removed [key_name(M)]'s appearance ban.") - DB_ban_unban(M.ckey, BANTYPE_ANY_JOB, "appearance") - if(M.client) - jobban_buildcache(M.client) - message_admins("[key_name_admin(usr)] removed [key_name_admin(M)]'s appearance ban.") - to_chat(M, "[usr.client.key] has removed your appearance ban.") - - else switch(alert("Appearance ban [M.key]?",,"Yes","No", "Cancel")) - if("Yes") - var/reason = input(usr,"Please State Reason.","Reason") as message|null - if(!reason) - return - var/severity = input("Set the severity of the note/ban.", "Severity", null, null) as null|anything in list("High", "Medium", "Minor", "None") - if(!severity) - return - if(!DB_ban_record(BANTYPE_JOB_PERMA, M, -1, reason, "appearance")) - to_chat(usr, "Failed to apply ban.") - return - if(M.client) - jobban_buildcache(M.client) - ban_unban_log_save("[key_name(usr)] appearance banned [key_name(M)]. reason: [reason]") - log_admin_private("[key_name(usr)] appearance banned [key_name(M)]. \nReason: [reason]") - create_message("note", M.key, null, "Appearance banned - [reason]", null, null, 0, 0, null, 0, severity) - message_admins("[key_name_admin(usr)] appearance banned [key_name_admin(M)].") - to_chat(M, "You have been appearance banned by [usr.client.key].") - to_chat(M, "The reason is: [reason]") - to_chat(M, "Appearance ban can be lifted only upon request.") - var/bran = CONFIG_GET(string/banappeals) - if(bran) - to_chat(M, "To try to resolve this matter head to [bran]") - else - to_chat(M, "No ban appeals URL has been set.") - if("No") - return - - else if(href_list["jobban2"]) - if(!check_rights(R_BAN)) - return - var/mob/M = locate(href_list["jobban2"]) - if(!ismob(M)) - to_chat(usr, "This can only be used on instances of type /mob.") - return - - if(!M.ckey) //sanity - to_chat(usr, "This mob has no ckey.") - return - - var/dat = "Job-Ban Panel: [key_name(M)]" - - /***********************************WARNING!************************************ - The jobban stuff looks mangled and disgusting - But it looks beautiful in-game - -Nodrak - ************************************WARNING!***********************************/ - var/counter = 0 -//Regular jobs - //Command (Blue) - dat += "
[J_title]: [J_opPos]/[job.total_positions < 0 ? " (unlimited)" : J_totPos]" + + dat += "" + if(job.total_positions >= 0) + dat += "Custom | " + dat += "Add 1 | " + if(job.total_positions > job.current_positions) + dat += "Remove | " + else + dat += "Remove | " + dat += "Unlimit
" - dat += "" - for(var/jobPos in GLOB.command_positions) - if(!jobPos) - continue - if(jobban_isbanned(M, jobPos)) - dat += "" - counter++ - else - dat += "" - counter++ - - if(counter >= 6) //So things dont get squiiiiished! - dat += "" - counter = 0 - dat += "
Command Positions
[jobPos][jobPos]
" - - //Security (Red) - counter = 0 - dat += "" - dat += "" - for(var/jobPos in GLOB.security_positions) - if(!jobPos) - continue - if(jobban_isbanned(M, jobPos)) - dat += "" - counter++ - else - dat += "" - counter++ - - if(counter >= 5) //So things dont get squiiiiished! - dat += "" - counter = 0 - dat += "
Security Positions
[jobPos][jobPos]
" - - //Engineering (Yellow) - counter = 0 - dat += "" - dat += "" - for(var/jobPos in GLOB.engineering_positions) - if(!jobPos) - continue - if(jobban_isbanned(M, jobPos)) - dat += "" - counter++ - else - dat += "" - counter++ - - if(counter >= 5) //So things dont get squiiiiished! - dat += "" - counter = 0 - dat += "
Engineering Positions
[jobPos][jobPos]
" - - //Medical (White) - counter = 0 - dat += "" - dat += "" - for(var/jobPos in GLOB.medical_positions) - if(!jobPos) - continue - if(jobban_isbanned(M, jobPos)) - dat += "" - counter++ - else - dat += "" - counter++ - - if(counter >= 5) //So things dont get squiiiiished! - dat += "" - counter = 0 - dat += "
Medical Positions
[jobPos][jobPos]
" - - //Science (Purple) - counter = 0 - dat += "" - dat += "" - for(var/jobPos in GLOB.science_positions) - if(!jobPos) - continue - if(jobban_isbanned(M, jobPos)) - dat += "" - counter++ - else - dat += "" - counter++ - - if(counter >= 5) //So things dont get squiiiiished! - dat += "" - counter = 0 - dat += "
Science Positions
[jobPos][jobPos]
" - - //Supply (Brown) - counter = 0 - dat += "" - dat += "" - for(var/jobPos in GLOB.supply_positions) - if(!jobPos) - continue - if(jobban_isbanned(M, jobPos)) - dat += "" - counter++ - else - dat += "" - counter++ - - if(counter >= 5) //So things dont get COPYPASTE! - dat += "" - counter = 0 - dat += "
Supply Positions
[jobPos][jobPos]
" - - //Civilian (Grey) - counter = 0 - dat += "" - dat += "" - for(var/jobPos in GLOB.civilian_positions) - if(!jobPos) - continue - if(jobban_isbanned(M, jobPos)) - dat += "" - counter++ - else - dat += "" - counter++ - - if(counter >= 5) //So things dont get squiiiiished! - dat += "" - counter = 0 - dat += "
Civilian Positions
[jobPos][jobPos]
" - - //Non-Human (Green) - counter = 0 - dat += "" - dat += "" - for(var/jobPos in GLOB.nonhuman_positions) - if(!jobPos) - continue - if(jobban_isbanned(M, jobPos)) - dat += "" - counter++ - else - dat += "" - counter++ - - if(counter >= 5) //So things dont get squiiiiished! - dat += "" - counter = 0 - - dat += "
Non-human Positions
[jobPos][jobPos]
" - - //Ghost Roles (light light gray) - dat += "" - dat += "" - - //pAI - if(jobban_isbanned(M, ROLE_PAI)) - dat += "" - else - dat += "" - - - //Drones - if(jobban_isbanned(M, ROLE_DRONE)) - dat += "" - else - dat += "" - - - //Positronic Brains - if(jobban_isbanned(M, ROLE_POSIBRAIN)) - dat += "" - else - dat += "" - - //Sentience Potion Spawn - if(jobban_isbanned(M, ROLE_SENTIENCE)) - dat += "" - else - dat += "" - - //Deathsquad - if(jobban_isbanned(M, ROLE_DEATHSQUAD)) - dat += "" - else - dat += "" - - //Lavaland roles - if(jobban_isbanned(M, ROLE_LAVALAND)) - dat += "" - else - dat += "" - - dat += "
Ghost Roles
pAIpAIDroneDronePosibrainPosibrainSentience Potion SpawnSentience Potion SpawnDeathsquadDeathsquadLavalandLavaland
" - - //Antagonist (Orange) - var/isbanned_dept = jobban_isbanned(M, ROLE_SYNDICATE) - dat += "" - dat += "" - - //Traitor - if(jobban_isbanned(M, ROLE_TRAITOR) || isbanned_dept) - dat += "" - else - dat += "" - - //Changeling - if(jobban_isbanned(M, ROLE_CHANGELING) || isbanned_dept) - dat += "" - else - dat += "" - - //Nuke Operative - if(jobban_isbanned(M, ROLE_OPERATIVE) || isbanned_dept) - dat += "" - else - dat += "" - - //Revolutionary - if(jobban_isbanned(M, ROLE_REV) || isbanned_dept) - dat += "" - else - dat += "" - - //Cultist - if(jobban_isbanned(M, ROLE_CULTIST) || isbanned_dept) - dat += "" - else - dat += "" - - dat += "" //So things dont get squished. - - //Servant of Ratvar - if(jobban_isbanned(M, ROLE_SERVANT_OF_RATVAR) || isbanned_dept) - dat += "" - else - dat += "" - - //Wizard - if(jobban_isbanned(M, ROLE_WIZARD) || isbanned_dept) - dat += "" - else - dat += "" - - //Abductor - if(jobban_isbanned(M, ROLE_ABDUCTOR) || isbanned_dept) - dat += "" - else - dat += "" - - //Alien - if(jobban_isbanned(M, ROLE_ALIEN) || isbanned_dept) - dat += "" - else - dat += "" - - //Gang - if(jobban_isbanned(M, ROLE_GANG) || isbanned_dept) - dat += "" - else - dat += "" - - - //Other Roles (black) - dat += "
Antagonist Positions | " - dat += "Team Antagonists | " - dat += "Conversion Antagonists
TraitorTraitorChangelingChangelingNuke OperativeNuke OperativeRevolutionaryRevolutionaryCultistCultist
ServantServantWizardWizardAbductorAbductorAlienAlienGangGang
" - dat += "" - - //Mind Transfer Potion - if(jobban_isbanned(M, ROLE_MIND_TRANSFER)) - dat += "" - else - dat += "" - - dat += "
Other Roles
Mind Transfer PotionMind Transfer Potion
" - usr << browse(dat, "window=jobban2;size=800x450") - return - - //JOBBAN'S INNARDS - else if(href_list["jobban3"]) - if(!check_rights(R_BAN)) - return - var/mob/M = locate(href_list["jobban4"]) - if(!ismob(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - if(!SSjob) - to_chat(usr, "Jobs subsystem not initialized yet!") - return - //get jobs for department if specified, otherwise just return the one job in a list. - var/list/joblist = list() - switch(href_list["jobban3"]) - if("commanddept") - for(var/jobPos in GLOB.command_positions) - if(!jobPos) - continue - joblist += jobPos - if("securitydept") - for(var/jobPos in GLOB.security_positions) - if(!jobPos) - continue - joblist += jobPos - if("engineeringdept") - for(var/jobPos in GLOB.engineering_positions) - if(!jobPos) - continue - joblist += jobPos - if("medicaldept") - for(var/jobPos in GLOB.medical_positions) - if(!jobPos) - continue - joblist += jobPos - if("sciencedept") - for(var/jobPos in GLOB.science_positions) - if(!jobPos) - continue - joblist += jobPos - if("supplydept") - for(var/jobPos in GLOB.supply_positions) - if(!jobPos) - continue - joblist += jobPos - if("civiliandept") - for(var/jobPos in GLOB.civilian_positions) - if(!jobPos) - continue - joblist += jobPos - if("nonhumandept") - for(var/jobPos in GLOB.nonhuman_positions) - if(!jobPos) - continue - joblist += jobPos - if("ghostroles") - joblist += list(ROLE_PAI, ROLE_POSIBRAIN, ROLE_DRONE , ROLE_DEATHSQUAD, ROLE_LAVALAND, ROLE_SENTIENCE) - if("teamantags") - joblist += list(ROLE_OPERATIVE, ROLE_REV, ROLE_CULTIST, ROLE_SERVANT_OF_RATVAR, ROLE_ABDUCTOR, ROLE_ALIEN, ROLE_GANG) - if("convertantags") - joblist += list(ROLE_REV, ROLE_CULTIST, ROLE_SERVANT_OF_RATVAR, ROLE_ALIEN) - if("otherroles") - joblist += list(ROLE_MIND_TRANSFER) - else - joblist += href_list["jobban3"] - - //Create a list of unbanned jobs within joblist - var/list/notbannedlist = list() - for(var/job in joblist) - if(!jobban_isbanned(M, job)) - notbannedlist += job - - //Banning comes first - if(notbannedlist.len) //at least 1 unbanned job exists in joblist so we have stuff to ban. - var/severity = null - switch(alert("Temporary Ban for [M.key]?",,"Yes","No", "Cancel")) - if("Yes") - var/mins = input(usr,"How long (in minutes)?","Ban time",1440) as num|null - if(mins <= 0) - to_chat(usr, "[mins] is not a valid duration.") - return - var/reason = input(usr,"Please State Reason For Banning [M.key].","Reason") as message|null - if(!reason) - return - severity = input("Set the severity of the note/ban.", "Severity", null, null) as null|anything in list("High", "Medium", "Minor", "None") - if(!severity) - return - var/msg - for(var/job in notbannedlist) - if(!DB_ban_record(BANTYPE_JOB_TEMP, M, mins, reason, job)) - to_chat(usr, "Failed to apply ban.") - return - if(M.client) - jobban_buildcache(M.client) - ban_unban_log_save("[key_name(usr)] temp-jobbanned [key_name(M)] from [job] for [mins] minutes. reason: [reason]") - log_admin_private("[key_name(usr)] temp-jobbanned [key_name(M)] from [job] for [mins] minutes.") - if(!msg) - msg = job - else - msg += ", [job]" - create_message("note", M.key, null, "Banned from [msg] - [reason]", null, null, 0, 0, null, 0, severity) - message_admins("[key_name_admin(usr)] banned [key_name_admin(M)] from [msg] for [mins] minutes.") - to_chat(M, "You have been [(msg == ("ooc" || "appearance")) ? "banned" : "jobbanned"] by [usr.client.key] from: [msg].") - to_chat(M, "The reason is: [reason]") - to_chat(M, "This jobban will be lifted in [mins] minutes.") - href_list["jobban2"] = 1 // lets it fall through and refresh - return 1 - if("No") - var/reason = input(usr,"Please State Reason For Banning [M.key].","Reason") as message|null - severity = input("Set the severity of the note/ban.", "Severity", null, null) as null|anything in list("High", "Medium", "Minor", "None") - if(!severity) - return - if(reason) - var/msg - for(var/job in notbannedlist) - if(!DB_ban_record(BANTYPE_JOB_PERMA, M, -1, reason, job)) - to_chat(usr, "Failed to apply ban.") - return - if(M.client) - jobban_buildcache(M.client) - ban_unban_log_save("[key_name(usr)] perma-jobbanned [key_name(M)] from [job]. reason: [reason]") - log_admin_private("[key_name(usr)] perma-banned [key_name(M)] from [job]") - if(!msg) - msg = job - else - msg += ", [job]" - create_message("note", M.key, null, "Banned from [msg] - [reason]", null, null, 0, 0, null, 0, severity) - message_admins("[key_name_admin(usr)] banned [key_name_admin(M)] from [msg].") - to_chat(M, "You have been [(msg == ("ooc" || "appearance")) ? "banned" : "jobbanned"] by [usr.client.key] from: [msg].") - to_chat(M, "The reason is: [reason]") - to_chat(M, "Jobban can be lifted only upon request.") - href_list["jobban2"] = 1 // lets it fall through and refresh - return 1 - if("Cancel") - return - - //Unbanning joblist - //all jobs in joblist are banned already OR we didn't give a reason (implying they shouldn't be banned) - if(joblist.len) //at least 1 banned job exists in joblist so we have stuff to unban. - var/msg - for(var/job in joblist) - var/reason = jobban_isbanned(M, job) - if(!reason) - continue //skip if it isn't jobbanned anyway - switch(alert("Job: '[job]' Reason: '[reason]' Un-jobban?","Please Confirm","Yes","No")) - if("Yes") - ban_unban_log_save("[key_name(usr)] unjobbanned [key_name(M)] from [job]") - log_admin_private("[key_name(usr)] unbanned [key_name(M)] from [job]") - DB_ban_unban(M.ckey, BANTYPE_ANY_JOB, job) - if(M.client) - jobban_buildcache(M.client) - if(!msg) - msg = job - else - msg += ", [job]" - else - continue - if(msg) - message_admins("[key_name_admin(usr)] unbanned [key_name_admin(M)] from [msg].") - to_chat(M, "You have been un-jobbanned by [usr.client.key] from [msg].") - href_list["jobban2"] = 1 // lets it fall through and refresh - return 1 - return 0 //we didn't do anything! - - else if(href_list["boot2"]) - if(!check_rights(R_ADMIN)) - return - var/mob/M = locate(href_list["boot2"]) - if(ismob(M)) - if(!check_if_greater_rights_than(M.client)) - to_chat(usr, "Error: They have more rights than you do.") - return - if(alert(usr, "Kick [key_name(M)]?", "Confirm", "Yes", "No") != "Yes") - return - if(!M) - to_chat(usr, "Error: [M] no longer exists!") - return - if(!M.client) - to_chat(usr, "Error: [M] no longer has a client!") - return - to_chat(M, "You have been kicked from the server by [usr.client.holder.fakekey ? "an Administrator" : "[usr.client.key]"].") - log_admin("[key_name(usr)] kicked [key_name(M)].") - message_admins("[key_name_admin(usr)] kicked [key_name_admin(M)].") - qdel(M.client) - - else if(href_list["addmessage"]) - if(!check_rights(R_ADMIN)) - return - var/target_key = href_list["addmessage"] - create_message("message", target_key, secret = 0) - - else if(href_list["addnote"]) - if(!check_rights(R_ADMIN)) - return - var/target_key = href_list["addnote"] - create_message("note", target_key) - - else if(href_list["addwatch"]) - if(!check_rights(R_ADMIN)) - return - var/target_key = href_list["addwatch"] - create_message("watchlist entry", target_key, secret = 1) - - else if(href_list["addmemo"]) - if(!check_rights(R_ADMIN)) - return - create_message("memo", secret = 0, browse = 1) - - else if(href_list["addmessageempty"]) - if(!check_rights(R_ADMIN)) - return - create_message("message", secret = 0) - - else if(href_list["addnoteempty"]) - if(!check_rights(R_ADMIN)) - return - create_message("note") - - else if(href_list["addwatchempty"]) - if(!check_rights(R_ADMIN)) - return - create_message("watchlist entry", secret = 1) - - else if(href_list["deletemessage"]) - if(!check_rights(R_ADMIN)) - return - var/safety = alert("Delete message/note?",,"Yes","No"); - if (safety == "Yes") - var/message_id = href_list["deletemessage"] - delete_message(message_id) - - else if(href_list["deletemessageempty"]) - if(!check_rights(R_ADMIN)) - return - var/safety = alert("Delete message/note?",,"Yes","No"); - if (safety == "Yes") - var/message_id = href_list["deletemessageempty"] - delete_message(message_id, browse = TRUE) - - else if(href_list["editmessage"]) - if(!check_rights(R_ADMIN)) - return - var/message_id = href_list["editmessage"] - edit_message(message_id) - - else if(href_list["editmessageempty"]) - if(!check_rights(R_ADMIN)) - return - var/message_id = href_list["editmessageempty"] - edit_message(message_id, browse = 1) - - else if(href_list["editmessageexpiry"]) - if(!check_rights(R_ADMIN)) - return - var/message_id = href_list["editmessageexpiry"] - edit_message_expiry(message_id) - - else if(href_list["editmessageexpiryempty"]) - if(!check_rights(R_ADMIN)) - return - var/message_id = href_list["editmessageexpiryempty"] - edit_message_expiry(message_id, browse = 1) - - else if(href_list["editmessageseverity"]) - if(!check_rights(R_ADMIN)) - return - var/message_id = href_list["editmessageseverity"] - edit_message_severity(message_id) - - else if(href_list["secretmessage"]) - if(!check_rights(R_ADMIN)) - return - var/message_id = href_list["secretmessage"] - toggle_message_secrecy(message_id) - - else if(href_list["searchmessages"]) - if(!check_rights(R_ADMIN)) - return - var/target = href_list["searchmessages"] - browse_messages(index = target) - - else if(href_list["nonalpha"]) - if(!check_rights(R_ADMIN)) - return - var/target = href_list["nonalpha"] - target = text2num(target) - browse_messages(index = target) - - else if(href_list["showmessages"]) - if(!check_rights(R_ADMIN)) - return - var/target = href_list["showmessages"] - browse_messages(index = target) - - else if(href_list["showmemo"]) - if(!check_rights(R_ADMIN)) - return - browse_messages("memo") - - else if(href_list["showwatch"]) - if(!check_rights(R_ADMIN)) - return - browse_messages("watchlist entry") - - else if(href_list["showwatchfilter"]) - if(!check_rights(R_ADMIN)) - return - browse_messages("watchlist entry", filter = 1) - - else if(href_list["showmessageckey"]) - if(!check_rights(R_ADMIN)) - return - var/target = href_list["showmessageckey"] - var/agegate = TRUE - if (href_list["showall"]) - agegate = FALSE - browse_messages(target_ckey = target, agegate = agegate) - - else if(href_list["showmessageckeylinkless"]) - var/target = href_list["showmessageckeylinkless"] - browse_messages(target_ckey = target, linkless = 1) - - else if(href_list["messageedits"]) - if(!check_rights(R_ADMIN)) - return - var/message_id = sanitizeSQL("[href_list["messageedits"]]") - var/datum/DBQuery/query_get_message_edits = SSdbcore.NewQuery("SELECT edits FROM [format_table_name("messages")] WHERE id = '[message_id]'") - if(!query_get_message_edits.warn_execute()) - qdel(query_get_message_edits) - return - if(query_get_message_edits.NextRow()) - var/edit_log = query_get_message_edits.item[1] - if(!QDELETED(usr)) - var/datum/browser/browser = new(usr, "Note edits", "Note edits") - browser.set_content(jointext(edit_log, "")) - browser.open() - qdel(query_get_message_edits) - - else if(href_list["newban"]) - if(!check_rights(R_BAN)) - return - - var/mob/M = locate(href_list["newban"]) - if(!ismob(M)) - return - - if(M.client && M.client.holder) - return //admins cannot be banned. Even if they could, the ban doesn't affect them anyway - - switch(alert("Temporary Ban for [M.key]?",,"Yes","No", "Cancel")) - if("Yes") - var/mins = input(usr,"How long (in minutes)?","Ban time",1440) as num|null - if(mins <= 0) - to_chat(usr, "[mins] is not a valid duration.") - return - var/reason = input(usr,"Please State Reason For Banning [M.key].","Reason") as message|null - if(!reason) - return - if(!DB_ban_record(BANTYPE_TEMP, M, mins, reason)) - to_chat(usr, "Failed to apply ban.") - return - AddBan(M.ckey, M.computer_id, reason, usr.ckey, 1, mins) - ban_unban_log_save("[key_name(usr)] has banned [key_name(M)]. - Reason: [reason] - This will be removed in [mins] minutes.") - to_chat(M, "You have been banned by [usr.client.key].\nReason: [reason]") - to_chat(M, "This is a temporary ban, it will be removed in [mins] minutes. The round ID is [GLOB.round_id].") - var/bran = CONFIG_GET(string/banappeals) - if(bran) - to_chat(M, "To try to resolve this matter head to [bran]") - else - to_chat(M, "No ban appeals URL has been set.") - log_admin_private("[key_name(usr)] has banned [key_name(M)].\nReason: [key_name(M)]\nThis will be removed in [mins] minutes.") - var/msg = "[key_name_admin(usr)] has banned [key_name_admin(M)].\nReason: [reason]\nThis will be removed in [mins] minutes." - message_admins(msg) - var/datum/admin_help/AH = M.client ? M.client.current_ticket : null - if(AH) - AH.Resolve() - qdel(M.client) - if("No") - var/reason = input(usr,"Please State Reason For Banning [M.key].","Reason") as message|null - if(!reason) - return - switch(alert(usr,"IP ban?",,"Yes","No","Cancel")) - if("Cancel") - return - if("Yes") - AddBan(M.ckey, M.computer_id, reason, usr.ckey, 0, 0, M.lastKnownIP) - if("No") - AddBan(M.ckey, M.computer_id, reason, usr.ckey, 0, 0) - to_chat(M, "You have been banned by [usr.client.key].\nReason: [reason]") - to_chat(M, "This is a permanent ban. The round ID is [GLOB.round_id].") - var/bran = CONFIG_GET(string/banappeals) - if(bran) - to_chat(M, "To try to resolve this matter head to [bran]") - else - to_chat(M, "No ban appeals URL has been set.") - if(!DB_ban_record(BANTYPE_PERMA, M, -1, reason)) - to_chat(usr, "Failed to apply ban.") - return - ban_unban_log_save("[key_name(usr)] has permabanned [key_name(M)]. - Reason: [reason] - This is a permanent ban.") - log_admin_private("[key_name(usr)] has banned [key_name(M)].\nReason: [reason]\nThis is a permanent ban.") - var/msg = "[key_name_admin(usr)] has banned [key_name_admin(M)].\nReason: [reason]\nThis is a permanent ban." - message_admins(msg) - var/datum/admin_help/AH = M.client ? M.client.current_ticket : null - if(AH) - AH.Resolve() - qdel(M.client) - if("Cancel") - return - - else if(href_list["mute"]) - if(!check_rights(R_ADMIN)) - return - cmd_admin_mute(href_list["mute"], text2num(href_list["mute_type"])) - - else if(href_list["c_mode"]) - return HandleCMode() - - else if(href_list["f_secret"]) - return HandleFSecret() - -//Dynamic mode - else if(href_list["f_dynamic_roundstart"]) - if(!check_rights(R_ADMIN)) - return - if(SSticker && SSticker.mode) - return alert(usr, "The game has already started.", null, null, null, null) - if(GLOB.master_mode != "dynamic") - return alert(usr, "The game mode has to be dynamic mode.", null, null, null, null) - var/roundstart_rules = list() - for (var/rule in subtypesof(/datum/dynamic_ruleset/roundstart)) - var/datum/dynamic_ruleset/roundstart/newrule = new rule() - roundstart_rules[newrule.name] = newrule - var/added_rule = input(usr,"What ruleset do you want to force? This will bypass threat level and population restrictions.", "Rigging Roundstart", null) as null|anything in roundstart_rules - if (added_rule) - GLOB.dynamic_forced_roundstart_ruleset += roundstart_rules[added_rule] - log_admin("[key_name(usr)] set [added_rule] to be a forced roundstart ruleset.") - message_admins("[key_name(usr)] set [added_rule] to be a forced roundstart ruleset.", 1) - Game() - - else if(href_list["f_dynamic_roundstart_clear"]) - if(!check_rights(R_ADMIN)) - return - GLOB.dynamic_forced_roundstart_ruleset = list() - Game() - log_admin("[key_name(usr)] cleared the rigged roundstart rulesets. The mode will pick them as normal.") - message_admins("[key_name(usr)] cleared the rigged roundstart rulesets. The mode will pick them as normal.", 1) - - else if(href_list["f_dynamic_roundstart_remove"]) - if(!check_rights(R_ADMIN)) - return - var/datum/dynamic_ruleset/roundstart/rule = locate(href_list["f_dynamic_roundstart_remove"]) - GLOB.dynamic_forced_roundstart_ruleset -= rule - Game() - log_admin("[key_name(usr)] removed [rule] from the forced roundstart rulesets.") - message_admins("[key_name(usr)] removed [rule] from the forced roundstart rulesets.", 1) - - else if(href_list["f_dynamic_latejoin"]) - if(!check_rights(R_ADMIN)) - return - if(!SSticker || !SSticker.mode) - return alert(usr, "The game must start first.", null, null, null, null) - if(GLOB.master_mode != "dynamic") - return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - var/latejoin_rules = list() - for (var/rule in subtypesof(/datum/dynamic_ruleset/latejoin)) - var/datum/dynamic_ruleset/latejoin/newrule = new rule() - latejoin_rules[newrule.name] = newrule - var/added_rule = input(usr,"What ruleset do you want to force upon the next latejoiner? This will bypass threat level and population restrictions.", "Rigging Latejoin", null) as null|anything in latejoin_rules - if (added_rule) - var/datum/game_mode/dynamic/mode = SSticker.mode - mode.forced_latejoin_rule = latejoin_rules[added_rule] - log_admin("[key_name(usr)] set [added_rule] to proc on the next latejoin.") - message_admins("[key_name(usr)] set [added_rule] to proc on the next latejoin.", 1) - Game() - - else if(href_list["f_dynamic_latejoin_clear"]) - if(!check_rights(R_ADMIN)) - return - if (SSticker && SSticker.mode && istype(SSticker.mode,/datum/game_mode/dynamic)) - var/datum/game_mode/dynamic/mode = SSticker.mode - mode.forced_latejoin_rule = null - Game() - log_admin("[key_name(usr)] cleared the forced latejoin ruleset.") - message_admins("[key_name(usr)] cleared the forced latejoin ruleset.", 1) - - else if(href_list["f_dynamic_midround"]) - if(!check_rights(R_ADMIN)) - return - if(!SSticker || !SSticker.mode) - return alert(usr, "The game must start first.", null, null, null, null) - if(GLOB.master_mode != "dynamic") - return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - var/midround_rules = list() - for (var/rule in subtypesof(/datum/dynamic_ruleset/midround)) - var/datum/dynamic_ruleset/midround/newrule = new rule() - midround_rules[newrule.name] = rule - var/added_rule = input(usr,"What ruleset do you want to force right now? This will bypass threat level and population restrictions.", "Execute Ruleset", null) as null|anything in midround_rules - if (added_rule) - var/datum/game_mode/dynamic/mode = SSticker.mode - log_admin("[key_name(usr)] executed the [added_rule] ruleset.") - message_admins("[key_name(usr)] executed the [added_rule] ruleset.", 1) - mode.picking_specific_rule(midround_rules[added_rule],1) - - else if (href_list["f_dynamic_options"]) - if(!check_rights(R_ADMIN)) - return - - if(SSticker && SSticker.mode) - return alert(usr, "The game has already started.", null, null, null, null) - if(GLOB.master_mode != "dynamic") - return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_roundstart_centre"]) - if(!check_rights(R_ADMIN)) - return - if(SSticker && SSticker.mode) - return alert(usr, "The game has already started.", null, null, null, null) - if(GLOB.master_mode != "dynamic") - return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - - var/new_centre = input(usr,"Change the centre of the dynamic mode threat curve. A negative value will give a more peaceful round ; a positive value, a round with higher threat. Any number between -5 and +5 is allowed.", "Change curve centre", null) as num - if (new_centre < -5 || new_centre > 5) - return alert(usr, "Only values between -5 and +5 are allowed.", null, null, null, null) - - log_admin("[key_name(usr)] changed the distribution curve center to [new_centre].") - message_admins("[key_name(usr)] changed the distribution curve center to [new_centre]", 1) - GLOB.dynamic_curve_centre = new_centre - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_roundstart_width"]) - if(!check_rights(R_ADMIN)) - return - if(SSticker && SSticker.mode) - return alert(usr, "The game has already started.", null, null, null, null) - if(GLOB.master_mode != "dynamic") - return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - - var/new_width = input(usr,"Change the width of the dynamic mode threat curve. A higher value will favour extreme rounds ; a lower value, a round closer to the average. Any Number between 0.5 and 4 are allowed.", "Change curve width", null) as num - if (new_width < 0.5 || new_width > 4) - return alert(usr, "Only values between 0.5 and +2.5 are allowed.", null, null, null, null) - - log_admin("[key_name(usr)] changed the distribution curve width to [new_width].") - message_admins("[key_name(usr)] changed the distribution curve width to [new_width]", 1) - GLOB.dynamic_curve_width = new_width - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_roundstart_latejoin_min"]) - if(!check_rights(R_ADMIN)) - return - if(SSticker && SSticker.mode) - return alert(usr, "The game has already started.", null, null, null, null) - if(GLOB.master_mode != "dynamic") - return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - var/new_min = input(usr,"Change the minimum delay of latejoin injection in minutes.", "Change latejoin injection delay minimum", null) as num - if(new_min <= 0) - return alert(usr, "The minimum can't be zero or lower.", null, null, null, null) - if((new_min MINUTES) > GLOB.dynamic_latejoin_delay_max) - return alert(usr, "The minimum must be lower than the maximum.", null, null, null, null) - - log_admin("[key_name(usr)] changed the latejoin injection minimum delay to [new_min] minutes.") - message_admins("[key_name(usr)] changed the latejoin injection minimum delay to [new_min] minutes", 1) - GLOB.dynamic_latejoin_delay_min = (new_min MINUTES) - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_roundstart_latejoin_max"]) - if(!check_rights(R_ADMIN)) - return - if(SSticker && SSticker.mode) - return alert(usr, "The game has already started.", null, null, null, null) - if(GLOB.master_mode != "dynamic") - return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - var/new_max = input(usr,"Change the maximum delay of latejoin injection in minutes.", "Change latejoin injection delay maximum", null) as num - if(new_max <= 0) - return alert(usr, "The maximum can't be zero or lower.", null, null, null, null) - if((new_max MINUTES) < GLOB.dynamic_latejoin_delay_min) - return alert(usr, "The maximum must be higher than the minimum.", null, null, null, null) - - log_admin("[key_name(usr)] changed the latejoin injection maximum delay to [new_max] minutes.") - message_admins("[key_name(usr)] changed the latejoin injection maximum delay to [new_max] minutes", 1) - GLOB.dynamic_latejoin_delay_max = (new_max MINUTES) - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_roundstart_midround_min"]) - if(!check_rights(R_ADMIN)) - return - if(SSticker && SSticker.mode) - return alert(usr, "The game has already started.", null, null, null, null) - if(GLOB.master_mode != "dynamic") - return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - var/new_min = input(usr,"Change the minimum delay of midround injection in minutes.", "Change midround injection delay minimum", null) as num - if(new_min <= 0) - return alert(usr, "The minimum can't be zero or lower.", null, null, null, null) - if((new_min MINUTES) > GLOB.dynamic_midround_delay_max) - return alert(usr, "The minimum must be lower than the maximum.", null, null, null, null) - - log_admin("[key_name(usr)] changed the midround injection minimum delay to [new_min] minutes.") - message_admins("[key_name(usr)] changed the midround injection minimum delay to [new_min] minutes", 1) - GLOB.dynamic_midround_delay_min = (new_min MINUTES) - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_roundstart_midround_max"]) - if(!check_rights(R_ADMIN)) - return - if(SSticker && SSticker.mode) - return alert(usr, "The game has already started.", null, null, null, null) - if(GLOB.master_mode != "dynamic") - return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - var/new_max = input(usr,"Change the maximum delay of midround injection in minutes.", "Change midround injection delay maximum", null) as num - if(new_max <= 0) - return alert(usr, "The maximum can't be zero or lower.", null, null, null, null) - if((new_max MINUTES) > GLOB.dynamic_midround_delay_max) - return alert(usr, "The maximum must be higher than the minimum.", null, null, null, null) - - log_admin("[key_name(usr)] changed the midround injection maximum delay to [new_max] minutes.") - message_admins("[key_name(usr)] changed the midround injection maximum delay to [new_max] minutes", 1) - GLOB.dynamic_midround_delay_max = (new_max MINUTES) - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_force_extended"]) - if(!check_rights(R_ADMIN)) - return - - if(GLOB.master_mode != "dynamic") - return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - - GLOB.dynamic_forced_extended = !GLOB.dynamic_forced_extended - log_admin("[key_name(usr)] set 'forced_extended' to [GLOB.dynamic_forced_extended].") - message_admins("[key_name(usr)] set 'forced_extended' to [GLOB.dynamic_forced_extended].") - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_no_stacking"]) - if(!check_rights(R_ADMIN)) - return - - if(GLOB.master_mode != "dynamic") - return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - - GLOB.dynamic_no_stacking = !GLOB.dynamic_no_stacking - log_admin("[key_name(usr)] set 'no_stacking' to [GLOB.dynamic_no_stacking].") - message_admins("[key_name(usr)] set 'no_stacking' to [GLOB.dynamic_no_stacking].") - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_classic_secret"]) - if(!check_rights(R_ADMIN)) - return - - if(GLOB.master_mode != "dynamic") - return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - - GLOB.dynamic_classic_secret = !GLOB.dynamic_classic_secret - log_admin("[key_name(usr)] set 'classic_secret' to [GLOB.dynamic_classic_secret].") - message_admins("[key_name(usr)] set 'classic_secret' to [GLOB.dynamic_classic_secret].") - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_stacking_limit"]) - if(!check_rights(R_ADMIN)) - return - - if(GLOB.master_mode != "dynamic") - return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - - GLOB.dynamic_stacking_limit = input(usr,"Change the threat limit at which round-endings rulesets will start to stack.", "Change stacking limit", null) as num - log_admin("[key_name(usr)] set 'stacking_limit' to [GLOB.dynamic_stacking_limit].") - message_admins("[key_name(usr)] set 'stacking_limit' to [GLOB.dynamic_stacking_limit].") - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_high_pop_limit"]) - if(!check_rights(R_ADMIN)) - return - - if(SSticker && SSticker.mode) - return alert(usr, "The game has already started.", null, null, null, null) - - if(GLOB.master_mode != "dynamic") - return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - - var/new_value = input(usr, "Enter the high-pop override threshold for dynamic mode.", "High pop override") as num - if (new_value < 0) - return alert(usr, "Only positive values allowed!", null, null, null, null) - GLOB.dynamic_high_pop_limit = new_value - - log_admin("[key_name(usr)] set 'high_pop_limit' to [GLOB.dynamic_high_pop_limit].") - message_admins("[key_name(usr)] set 'high_pop_limit' to [GLOB.dynamic_high_pop_limit].") - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_forced_threat"]) - if(!check_rights(R_ADMIN)) - return - - if(SSticker && SSticker.mode) - return alert(usr, "The game has already started.", null, null, null, null) - - if(GLOB.master_mode != "dynamic") - return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - - var/new_value = input(usr, "Enter the forced threat level for dynamic mode.", "Forced threat level") as num - if (new_value > 100) - return alert(usr, "The value must be be under 100.", null, null, null, null) - GLOB.dynamic_forced_threat_level = new_value - - log_admin("[key_name(usr)] set 'forced_threat_level' to [GLOB.dynamic_forced_threat_level].") - message_admins("[key_name(usr)] set 'forced_threat_level' to [GLOB.dynamic_forced_threat_level].") - dynamic_mode_options(usr) - - else if(href_list["f_dynamic_chaos_level"]) - if(!check_rights(R_ADMIN)) - return - - if(SSticker && SSticker.mode) - return alert(usr, "The game has already started.", null, null, null, null) - - if(GLOB.master_mode != "dynamic") - return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) - - var/new_value = input(usr, "Enter the chaos level for dynamic mode.", "Chaos level") as num - if (new_value > 5 || new_value < 0) - return alert(usr, "The value must be between 0 and 5.", null, null, null, null) - GLOB.dynamic_chaos_level = new_value - - log_admin("[key_name(usr)] set 'dynamic_chaos_level' to [GLOB.dynamic_chaos_level].") - message_admins("[key_name(usr)] set 'dynamic_chaos_level' to [GLOB.dynamic_chaos_level].") - dynamic_mode_options(usr) -//End Dynamic mode - - else if(href_list["c_mode2"]) - if(!check_rights(R_ADMIN|R_SERVER)) - return - - if (SSticker.HasRoundStarted()) - return alert(usr, "The game has already started.", null, null, null, null) - GLOB.master_mode = href_list["c_mode2"] - log_admin("[key_name(usr)] set the mode as [GLOB.master_mode].") - message_admins("[key_name_admin(usr)] set the mode as [GLOB.master_mode].") - to_chat(world, "The mode is now: [GLOB.master_mode]") - Game() // updates the main game menu - SSticker.save_mode(GLOB.master_mode) - HandleCMode() - - else if(href_list["f_secret2"]) - if(!check_rights(R_ADMIN|R_SERVER)) - return - - if(SSticker.HasRoundStarted()) - return alert(usr, "The game has already started.", null, null, null, null) - if(GLOB.master_mode != "secret") - return alert(usr, "The game mode has to be secret!", null, null, null, null) - GLOB.secret_force_mode = href_list["f_secret2"] - log_admin("[key_name(usr)] set the forced secret mode as [GLOB.secret_force_mode].") - message_admins("[key_name_admin(usr)] set the forced secret mode as [GLOB.secret_force_mode].") - Game() // updates the main game menu - HandleFSecret() - - else if(href_list["monkeyone"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/living/carbon/human/H = locate(href_list["monkeyone"]) - if(!istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.") - return - - log_admin("[key_name(usr)] attempting to monkeyize [key_name(H)].") - message_admins("[key_name_admin(usr)] attempting to monkeyize [key_name_admin(H)].") - H.monkeyize() - - else if(href_list["humanone"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/living/carbon/monkey/Mo = locate(href_list["humanone"]) - if(!istype(Mo)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/monkey.") - return - - log_admin("[key_name(usr)] attempting to humanize [key_name(Mo)].") - message_admins("[key_name_admin(usr)] attempting to humanize [key_name_admin(Mo)].") - Mo.humanize() - - else if(href_list["corgione"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/living/carbon/human/H = locate(href_list["corgione"]) - if(!istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.") - return - - log_admin("[key_name(usr)] attempting to corgize [key_name(H)].") - message_admins("[key_name_admin(usr)] attempting to corgize [key_name_admin(H)].") - H.corgize() - - - else if(href_list["forcespeech"]) - if(!check_rights(R_FUN)) - return - - var/mob/M = locate(href_list["forcespeech"]) - if(!ismob(M)) - to_chat(usr, "this can only be used on instances of type /mob.") - - var/speech = input("What will [key_name(M)] say?", "Force speech", "")// Don't need to sanitize, since it does that in say(), we also trust our admins. - if(!speech) - return - M.say(speech, forced = "admin speech") - speech = sanitize(speech) // Nah, we don't trust them - log_admin("[key_name(usr)] forced [key_name(M)] to say: [speech]") - message_admins("[key_name_admin(usr)] forced [key_name_admin(M)] to say: [speech]") - - else if(href_list["makeeligible"]) - if(!check_rights(R_ADMIN)) - return - var/mob/M = locate(href_list["makeeligible"]) - if(!ismob(M)) - to_chat(usr, "this can only be used on instances of type /mob.") - if(M.ckey in GLOB.client_ghost_timeouts) - GLOB.client_ghost_timeouts -= M.ckey - - else if(href_list["sendtoprison"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["sendtoprison"]) - if(!ismob(M)) - to_chat(usr, "This can only be used on instances of type /mob.") - return - if(isAI(M)) - to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai.") - return - - if(alert(usr, "Send [key_name(M)] to Prison?", "Message", "Yes", "No") != "Yes") - return - - M.forceMove(pick(GLOB.prisonwarp)) - to_chat(M, "You have been sent to Prison!") - - log_admin("[key_name(usr)] has sent [key_name(M)] to Prison!") - message_admins("[key_name_admin(usr)] has sent [key_name_admin(M)] to Prison!") - - else if(href_list["sendbacktolobby"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["sendbacktolobby"]) - - if(!isobserver(M)) - to_chat(usr, "You can only send ghost players back to the Lobby.") - return - - if(!M.client) - to_chat(usr, "[M] doesn't seem to have an active client.") - return - - if(alert(usr, "Send [key_name(M)] back to Lobby?", "Message", "Yes", "No") != "Yes") - return - - log_admin("[key_name(usr)] has sent [key_name(M)] back to the Lobby.") - message_admins("[key_name(usr)] has sent [key_name(M)] back to the Lobby.") - - var/mob/dead/new_player/NP = new() - NP.ckey = M.ckey - qdel(M) - - else if(href_list["tdome1"]) - if(!check_rights(R_FUN)) - return - - if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") - return - - var/mob/M = locate(href_list["tdome1"]) - if(!isliving(M)) - to_chat(usr, "This can only be used on instances of type /mob/living.") - return - if(isAI(M)) - to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai.") - return - var/mob/living/L = M - - for(var/obj/item/I in L) - L.dropItemToGround(I, TRUE) - - L.Unconscious(100) - sleep(5) - L.forceMove(pick(GLOB.tdome1)) - spawn(50) - to_chat(L, "You have been sent to the Thunderdome.") - log_admin("[key_name(usr)] has sent [key_name(L)] to the thunderdome. (Team 1)") - message_admins("[key_name_admin(usr)] has sent [key_name_admin(L)] to the thunderdome. (Team 1)") - - else if(href_list["tdome2"]) - if(!check_rights(R_FUN)) - return - - if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") - return - - var/mob/M = locate(href_list["tdome2"]) - if(!isliving(M)) - to_chat(usr, "This can only be used on instances of type /mob/living.") - return - if(isAI(M)) - to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai.") - return - var/mob/living/L = M - - for(var/obj/item/I in L) - L.dropItemToGround(I, TRUE) - - L.Unconscious(100) - sleep(5) - L.forceMove(pick(GLOB.tdome2)) - spawn(50) - to_chat(L, "You have been sent to the Thunderdome.") - log_admin("[key_name(usr)] has sent [key_name(L)] to the thunderdome. (Team 2)") - message_admins("[key_name_admin(usr)] has sent [key_name_admin(L)] to the thunderdome. (Team 2)") - - else if(href_list["tdomeadmin"]) - if(!check_rights(R_FUN)) - return - - if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") - return - - var/mob/M = locate(href_list["tdomeadmin"]) - if(!isliving(M)) - to_chat(usr, "This can only be used on instances of type /mob/living.") - return - if(isAI(M)) - to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai.") - return - var/mob/living/L = M - - L.Unconscious(100) - sleep(5) - L.forceMove(pick(GLOB.tdomeadmin)) - spawn(50) - to_chat(L, "You have been sent to the Thunderdome.") - log_admin("[key_name(usr)] has sent [key_name(L)] to the thunderdome. (Admin.)") - message_admins("[key_name_admin(usr)] has sent [key_name_admin(L)] to the thunderdome. (Admin.)") - - else if(href_list["tdomeobserve"]) - if(!check_rights(R_FUN)) - return - - if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") - return - - var/mob/M = locate(href_list["tdomeobserve"]) - if(!isliving(M)) - to_chat(usr, "This can only be used on instances of type /mob/living.") - return - if(isAI(M)) - to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai.") - return - var/mob/living/L = M - - for(var/obj/item/I in L) - L.dropItemToGround(I, TRUE) - - if(ishuman(L)) - var/mob/living/carbon/human/observer = L - observer.equip_to_slot_or_del(new /obj/item/clothing/under/suit_jacket(observer), SLOT_W_UNIFORM) - observer.equip_to_slot_or_del(new /obj/item/clothing/shoes/sneakers/black(observer), SLOT_SHOES) - L.Unconscious(100) - sleep(5) - L.forceMove(pick(GLOB.tdomeobserve)) - spawn(50) - to_chat(L, "You have been sent to the Thunderdome.") - log_admin("[key_name(usr)] has sent [key_name(L)] to the thunderdome. (Observer.)") - message_admins("[key_name_admin(usr)] has sent [key_name_admin(L)] to the thunderdome. (Observer.)") - - else if(href_list["revive"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/living/L = locate(href_list["revive"]) - if(!istype(L)) - to_chat(usr, "This can only be used on instances of type /mob/living.") - return - - L.revive(full_heal = 1, admin_revive = 1) - message_admins("Admin [key_name_admin(usr)] healed / revived [key_name_admin(L)]!") - log_admin("[key_name(usr)] healed / Revived [key_name(L)].") - - else if(href_list["makeai"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/living/carbon/human/H = locate(href_list["makeai"]) - if(!istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.") - return - - message_admins("Admin [key_name_admin(usr)] AIized [key_name_admin(H)]!") - log_admin("[key_name(usr)] AIized [key_name(H)].") - H.AIize() - - else if(href_list["makealien"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/living/carbon/human/H = locate(href_list["makealien"]) - if(!istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.") - return - - usr.client.cmd_admin_alienize(H) - - else if(href_list["makeslime"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/living/carbon/human/H = locate(href_list["makeslime"]) - if(!istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.") - return - - usr.client.cmd_admin_slimeize(H) - - else if(href_list["makeblob"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/living/carbon/human/H = locate(href_list["makeblob"]) - if(!istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.") - return - - usr.client.cmd_admin_blobize(H) - - - else if(href_list["makerobot"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/living/carbon/human/H = locate(href_list["makerobot"]) - if(!istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.") - return - - usr.client.cmd_admin_robotize(H) - - else if(href_list["makeanimal"]) - if(!check_rights(R_SPAWN)) - return - - var/mob/M = locate(href_list["makeanimal"]) - if(isnewplayer(M)) - to_chat(usr, "This cannot be used on instances of type /mob/dead/new_player.") - return - - usr.client.cmd_admin_animalize(M) - - else if(href_list["adminplayeropts"]) - var/mob/M = locate(href_list["adminplayeropts"]) - show_player_panel(M) - - else if(href_list["adminplayerobservefollow"]) - if(!isobserver(usr) && !check_rights(R_ADMIN)) - return - - var/atom/movable/AM = locate(href_list["adminplayerobservefollow"]) - - var/client/C = usr.client - if(!isobserver(usr)) - C.admin_ghost() - var/mob/dead/observer/A = C.mob - A.ManualFollow(AM) - - else if(href_list["admingetmovable"]) - if(!check_rights(R_ADMIN)) - return - - var/atom/movable/AM = locate(href_list["admingetmovable"]) - if(QDELETED(AM)) - return - AM.forceMove(get_turf(usr)) - - else if(href_list["adminplayerobservecoodjump"]) - if(!isobserver(usr) && !check_rights(R_ADMIN)) - return - - var/x = text2num(href_list["X"]) - var/y = text2num(href_list["Y"]) - var/z = text2num(href_list["Z"]) - - var/client/C = usr.client - if(!isobserver(usr)) - C.admin_ghost() - sleep(2) - C.jumptocoord(x,y,z) - - else if(href_list["adminchecklaws"]) - if(!check_rights(R_ADMIN)) - return - output_ai_laws() - - else if(href_list["admincheckdevilinfo"]) - if(!check_rights(R_ADMIN)) - return - var/mob/M = locate(href_list["admincheckdevilinfo"]) - output_devil_info(M) - - else if(href_list["adminmoreinfo"]) - var/mob/M = locate(href_list["adminmoreinfo"]) in GLOB.mob_list - if(!ismob(M)) - to_chat(usr, "This can only be used on instances of type /mob.") - return - - var/location_description = "" - var/special_role_description = "" - var/health_description = "" - var/gender_description = "" - var/turf/T = get_turf(M) - - //Location - if(isturf(T)) - if(isarea(T.loc)) - location_description = "([M.loc == T ? "at coordinates " : "in [M.loc] at coordinates "] [T.x], [T.y], [T.z] in area [T.loc])" - else - location_description = "([M.loc == T ? "at coordinates " : "in [M.loc] at coordinates "] [T.x], [T.y], [T.z])" - - //Job + antagonist - if(M.mind) - special_role_description = "Role: [M.mind.assigned_role]; Antagonist: [M.mind.special_role]" - else - special_role_description = "Role: Mind datum missing Antagonist: Mind datum missing" - - //Health - if(isliving(M)) - var/mob/living/L = M - var/status - switch (M.stat) - if(CONSCIOUS) - status = "Alive" - if(SOFT_CRIT) - status = "Dying" - if(UNCONSCIOUS) - status = "[L.InCritical() ? "Unconscious and Dying" : "Unconscious"]" - if(DEAD) - status = "Dead" - health_description = "Status = [status]" - health_description += "
Oxy: [L.getOxyLoss()] - Tox: [L.getToxLoss()] - Fire: [L.getFireLoss()] - Brute: [L.getBruteLoss()] - Clone: [L.getCloneLoss()] - Brain: [L.getOrganLoss(ORGAN_SLOT_BRAIN)] - Stamina: [L.getStaminaLoss()]" - else - health_description = "This mob type has no health to speak of." - - //Gender - switch(M.gender) - if(MALE,FEMALE) - gender_description = "[M.gender]" - else - gender_description = "[M.gender]" - - to_chat(src.owner, "Info about [M.name]: ") - to_chat(src.owner, "Mob type = [M.type]; Gender = [gender_description] Damage = [health_description]") - to_chat(src.owner, "Name = [M.name]; Real_name = [M.real_name]; Mind_name = [M.mind?"[M.mind.name]":""]; Key = [M.key];") - to_chat(src.owner, "Location = [location_description];") - to_chat(src.owner, "[special_role_description]") - to_chat(src.owner, ADMIN_FULLMONTY_NONAME(M)) - - else if(href_list["addjobslot"]) - if(!check_rights(R_ADMIN)) - return - - var/Add = href_list["addjobslot"] - - for(var/datum/job/job in SSjob.occupations) - if(job.title == Add) - job.total_positions += 1 - break - - src.manage_free_slots() - - - else if(href_list["customjobslot"]) - if(!check_rights(R_ADMIN)) - return - - var/Add = href_list["customjobslot"] - - for(var/datum/job/job in SSjob.occupations) - if(job.title == Add) - var/newtime = null - newtime = input(usr, "How many jebs do you want?", "Add wanted posters", "[newtime]") as num|null - if(!newtime) - to_chat(src.owner, "Setting to amount of positions filled for the job") - job.total_positions = job.current_positions - break - job.total_positions = newtime - - src.manage_free_slots() - - else if(href_list["removejobslot"]) - if(!check_rights(R_ADMIN)) - return - - var/Remove = href_list["removejobslot"] - - for(var/datum/job/job in SSjob.occupations) - if(job.title == Remove && job.total_positions - job.current_positions > 0) - job.total_positions -= 1 - break - - src.manage_free_slots() - - else if(href_list["unlimitjobslot"]) - if(!check_rights(R_ADMIN)) - return - - var/Unlimit = href_list["unlimitjobslot"] - - for(var/datum/job/job in SSjob.occupations) - if(job.title == Unlimit) - job.total_positions = -1 - break - - src.manage_free_slots() - - else if(href_list["limitjobslot"]) - if(!check_rights(R_ADMIN)) - return - - var/Limit = href_list["limitjobslot"] - - for(var/datum/job/job in SSjob.occupations) - if(job.title == Limit) - job.total_positions = job.current_positions - break - - src.manage_free_slots() - - - else if(href_list["adminspawncookie"]) - if(!check_rights(R_ADMIN|R_FUN)) - return - - var/mob/living/carbon/human/H = locate(href_list["adminspawncookie"]) - if(!ishuman(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.") - return - - var/obj/item/reagent_containers/food/snacks/cookie/cookie = new(H) - if(H.put_in_hands(cookie)) - H.update_inv_hands() - else - qdel(cookie) - log_admin("[key_name(H)] has their hands full, so they did not receive their cookie, spawned by [key_name(src.owner)].") - message_admins("[key_name(H)] has their hands full, so they did not receive their cookie, spawned by [key_name(src.owner)].") - return - - log_admin("[key_name(H)] got their cookie, spawned by [key_name(src.owner)].") - message_admins("[key_name(H)] got their cookie, spawned by [key_name(src.owner)].") - SSblackbox.record_feedback("amount", "admin_cookies_spawned", 1) - to_chat(H, "Your prayers have been answered!! You received the best cookie!") - SEND_SOUND(H, sound('sound/effects/pray_chaplain.ogg')) - - else if(href_list["adminsmite"]) - if(!check_rights(R_ADMIN|R_FUN)) - return - - var/mob/living/carbon/human/H = locate(href_list["adminsmite"]) in GLOB.mob_list - if(!H || !istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") - return - - usr.client.smite(H) - - else if(href_list["CentComReply"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["CentComReply"]) - usr.client.admin_headset_message(M, RADIO_CHANNEL_CENTCOM) - - else if(href_list["SyndicateReply"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["SyndicateReply"]) - usr.client.admin_headset_message(M, RADIO_CHANNEL_SYNDICATE) - - else if(href_list["HeadsetMessage"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["HeadsetMessage"]) - usr.client.admin_headset_message(M) - - else if(href_list["reject_custom_name"]) - if(!check_rights(R_ADMIN)) - return - var/obj/item/station_charter/charter = locate(href_list["reject_custom_name"]) - if(istype(charter)) - charter.reject_proposed(usr) - else if(href_list["jumpto"]) - if(!isobserver(usr) && !check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["jumpto"]) - usr.client.jumptomob(M) - - else if(href_list["getmob"]) - if(!check_rights(R_ADMIN)) - return - - if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") - return - var/mob/M = locate(href_list["getmob"]) - usr.client.Getmob(M) - - else if(href_list["sendmob"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["sendmob"]) - usr.client.sendmob(M) - - else if(href_list["narrateto"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["narrateto"]) - usr.client.cmd_admin_direct_narrate(M) - - else if(href_list["subtlemessage"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["subtlemessage"]) - usr.client.cmd_admin_subtle_message(M) - - else if(href_list["individuallog"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["individuallog"]) in GLOB.mob_list - if(!ismob(M)) - to_chat(usr, "This can only be used on instances of type /mob.") - return - - show_individual_logging_panel(M, href_list["log_src"], href_list["log_type"]) - else if(href_list["languagemenu"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["languagemenu"]) in GLOB.mob_list - if(!ismob(M)) - to_chat(usr, "This can only be used on instances of type /mob.") - return - var/datum/language_holder/H = M.get_language_holder() - H.open_language_menu(usr) - - else if(href_list["traitor"]) - if(!check_rights(R_ADMIN)) - return - - if(!SSticker.HasRoundStarted()) - alert("The game hasn't started yet!") - return - - var/mob/M = locate(href_list["traitor"]) - if(!ismob(M)) - var/datum/mind/D = M - if(!istype(D)) - to_chat(usr, "This can only be used on instances of type /mob and /mind") - return - else - D.traitor_panel() - else - show_traitor_panel(M) - - else if(href_list["borgpanel"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["borgpanel"]) - if(!iscyborg(M)) - to_chat(usr, "This can only be used on cyborgs") - else - open_borgopanel(M) - - else if(href_list["initmind"]) - if(!check_rights(R_ADMIN)) - return - var/mob/M = locate(href_list["initmind"]) - if(!ismob(M) || M.mind) - to_chat(usr, "This can only be used on instances on mindless mobs") - return - M.mind_initialize() - - else if(href_list["create_object"]) - if(!check_rights(R_SPAWN)) - return - return create_object(usr) - - else if(href_list["quick_create_object"]) - if(!check_rights(R_SPAWN)) - return - return quick_create_object(usr) - - else if(href_list["create_turf"]) - if(!check_rights(R_SPAWN)) - return - return create_turf(usr) - - else if(href_list["create_mob"]) - if(!check_rights(R_SPAWN)) - return - return create_mob(usr) - - else if(href_list["dupe_marked_datum"]) - if(!check_rights(R_SPAWN)) - return - return DuplicateObject(marked_datum, perfectcopy=1, newloc=get_turf(usr)) - - else if(href_list["object_list"]) //this is the laggiest thing ever - if(!check_rights(R_SPAWN)) - return - - var/atom/loc = usr.loc - - var/dirty_paths - if (istext(href_list["object_list"])) - dirty_paths = list(href_list["object_list"]) - else if (istype(href_list["object_list"], /list)) - dirty_paths = href_list["object_list"] - - var/paths = list() - - for(var/dirty_path in dirty_paths) - var/path = text2path(dirty_path) - if(!path) - continue - else if(!ispath(path, /obj) && !ispath(path, /turf) && !ispath(path, /mob)) - continue - paths += path - - if(!paths) - alert("The path list you sent is empty.") - return - if(length(paths) > 5) - alert("Select fewer object types, (max 5).") - return - - var/list/offset = splittext(href_list["offset"],",") - var/number = CLAMP(text2num(href_list["object_count"]), 1, 100) - var/X = offset.len > 0 ? text2num(offset[1]) : 0 - var/Y = offset.len > 1 ? text2num(offset[2]) : 0 - var/Z = offset.len > 2 ? text2num(offset[3]) : 0 - var/obj_dir = text2num(href_list["object_dir"]) - if(obj_dir && !(obj_dir in list(1,2,4,8,5,6,9,10))) - obj_dir = null - var/obj_name = sanitize(href_list["object_name"]) - - - var/atom/target //Where the object will be spawned - var/where = href_list["object_where"] - if (!( where in list("onfloor","inhand","inmarked") )) - where = "onfloor" - - - switch(where) - if("inhand") - if (!iscarbon(usr) && !iscyborg(usr)) - to_chat(usr, "Can only spawn in hand when you're a carbon mob or cyborg.") - where = "onfloor" - target = usr - - if("onfloor") - switch(href_list["offset_type"]) - if ("absolute") - target = locate(0 + X,0 + Y,0 + Z) - if ("relative") - target = locate(loc.x + X,loc.y + Y,loc.z + Z) - if("inmarked") - if(!marked_datum) - to_chat(usr, "You don't have any object marked. Abandoning spawn.") - return - else if(!istype(marked_datum, /atom)) - to_chat(usr, "The object you have marked cannot be used as a target. Target must be of type /atom. Abandoning spawn.") - return - else - target = marked_datum - - if(target) - for (var/path in paths) - for (var/i = 0; i < number; i++) - if(path in typesof(/turf)) - var/turf/O = target - var/turf/N = O.ChangeTurf(path) - if(N && obj_name) - N.name = obj_name - else - var/atom/O = new path(target) - if(!QDELETED(O)) - O.flags_1 |= ADMIN_SPAWNED_1 - if(obj_dir) - O.setDir(obj_dir) - if(obj_name) - O.name = obj_name - if(ismob(O)) - var/mob/M = O - M.real_name = obj_name - if(where == "inhand" && isliving(usr) && isitem(O)) - var/mob/living/L = usr - var/obj/item/I = O - L.put_in_hands(I) - if(iscyborg(L)) - var/mob/living/silicon/robot/R = L - if(R.module) - R.module.add_module(I, TRUE, TRUE) - R.activate_module(I) - - - if (number == 1) - log_admin("[key_name(usr)] created a [english_list(paths)]") - for(var/path in paths) - if(ispath(path, /mob)) - message_admins("[key_name_admin(usr)] created a [english_list(paths)]") - break - else - log_admin("[key_name(usr)] created [number]ea [english_list(paths)]") - for(var/path in paths) - if(ispath(path, /mob)) - message_admins("[key_name_admin(usr)] created [number]ea [english_list(paths)]") - break - return - - else if(href_list["secrets"]) - Secrets_topic(href_list["secrets"],href_list) - - else if(href_list["ac_view_wanted"]) //Admin newscaster Topic() stuff be here - if(!check_rights(R_ADMIN)) - return - src.admincaster_screen = 18 //The ac_ prefix before the hrefs stands for AdminCaster. - src.access_news_network() - - else if(href_list["ac_set_channel_name"]) - if(!check_rights(R_ADMIN)) - return - src.admincaster_feed_channel.channel_name = stripped_input(usr, "Provide a Feed Channel Name.", "Network Channel Handler", "") - src.access_news_network() - - else if(href_list["ac_set_channel_lock"]) - if(!check_rights(R_ADMIN)) - return - src.admincaster_feed_channel.locked = !src.admincaster_feed_channel.locked - src.access_news_network() - - else if(href_list["ac_submit_new_channel"]) - if(!check_rights(R_ADMIN)) - return - var/check = 0 - for(var/datum/newscaster/feed_channel/FC in GLOB.news_network.network_channels) - if(FC.channel_name == src.admincaster_feed_channel.channel_name) - check = 1 - break - if(src.admincaster_feed_channel.channel_name == "" || src.admincaster_feed_channel.channel_name == "\[REDACTED\]" || check ) - src.admincaster_screen=7 - else - var/choice = alert("Please confirm Feed channel creation.","Network Channel Handler","Confirm","Cancel") - if(choice=="Confirm") - GLOB.news_network.CreateFeedChannel(src.admincaster_feed_channel.channel_name, src.admin_signature, src.admincaster_feed_channel.locked, 1) - SSblackbox.record_feedback("tally", "newscaster_channels", 1, src.admincaster_feed_channel.channel_name) - log_admin("[key_name(usr)] created command feed channel: [src.admincaster_feed_channel.channel_name]!") - src.admincaster_screen=5 - src.access_news_network() - - else if(href_list["ac_set_channel_receiving"]) - if(!check_rights(R_ADMIN)) - return - var/list/available_channels = list() - for(var/datum/newscaster/feed_channel/F in GLOB.news_network.network_channels) - available_channels += F.channel_name - src.admincaster_feed_channel.channel_name = adminscrub(input(usr, "Choose receiving Feed Channel.", "Network Channel Handler") in available_channels ) - src.access_news_network() - - else if(href_list["ac_set_new_message"]) - if(!check_rights(R_ADMIN)) - return - src.admincaster_feed_message.body = adminscrub(stripped_input(usr, "Write your Feed story.", "Network Channel Handler", "")) - src.access_news_network() - - else if(href_list["ac_submit_new_message"]) - if(!check_rights(R_ADMIN)) - return - if(src.admincaster_feed_message.returnBody(-1) =="" || src.admincaster_feed_message.returnBody(-1) =="\[REDACTED\]" || src.admincaster_feed_channel.channel_name == "" ) - src.admincaster_screen = 6 - else - GLOB.news_network.SubmitArticle(src.admincaster_feed_message.returnBody(-1), src.admin_signature, src.admincaster_feed_channel.channel_name, null, 1) - SSblackbox.record_feedback("amount", "newscaster_stories", 1) - src.admincaster_screen=4 - - for(var/obj/machinery/newscaster/NEWSCASTER in GLOB.allCasters) - NEWSCASTER.newsAlert(src.admincaster_feed_channel.channel_name) - - log_admin("[key_name(usr)] submitted a feed story to channel: [src.admincaster_feed_channel.channel_name]!") - src.access_news_network() - - else if(href_list["ac_create_channel"]) - if(!check_rights(R_ADMIN)) - return - src.admincaster_screen=2 - src.access_news_network() - - else if(href_list["ac_create_feed_story"]) - if(!check_rights(R_ADMIN)) - return - src.admincaster_screen=3 - src.access_news_network() - - else if(href_list["ac_menu_censor_story"]) - if(!check_rights(R_ADMIN)) - return - src.admincaster_screen=10 - src.access_news_network() - - else if(href_list["ac_menu_censor_channel"]) - if(!check_rights(R_ADMIN)) - return - src.admincaster_screen=11 - src.access_news_network() - - else if(href_list["ac_menu_wanted"]) - if(!check_rights(R_ADMIN)) - return - var/already_wanted = 0 - if(GLOB.news_network.wanted_issue.active) - already_wanted = 1 - - if(already_wanted) - src.admincaster_wanted_message.criminal = GLOB.news_network.wanted_issue.criminal - src.admincaster_wanted_message.body = GLOB.news_network.wanted_issue.body - src.admincaster_screen = 14 - src.access_news_network() - - else if(href_list["ac_set_wanted_name"]) - if(!check_rights(R_ADMIN)) - return - src.admincaster_wanted_message.criminal = adminscrub(stripped_input(usr, "Provide the name of the Wanted person.", "Network Security Handler", "")) - src.access_news_network() - - else if(href_list["ac_set_wanted_desc"]) - if(!check_rights(R_ADMIN)) - return - src.admincaster_wanted_message.body = adminscrub(stripped_input(usr, "Provide the a description of the Wanted person and any other details you deem important.", "Network Security Handler", "")) - src.access_news_network() - - else if(href_list["ac_submit_wanted"]) - if(!check_rights(R_ADMIN)) - return - var/input_param = text2num(href_list["ac_submit_wanted"]) - if(src.admincaster_wanted_message.criminal == "" || src.admincaster_wanted_message.body == "") - src.admincaster_screen = 16 - else - var/choice = alert("Please confirm Wanted Issue [(input_param==1) ? ("creation.") : ("edit.")]","Network Security Handler","Confirm","Cancel") - if(choice=="Confirm") - if(input_param==1) //If input_param == 1 we're submitting a new wanted issue. At 2 we're just editing an existing one. See the else below - GLOB.news_network.submitWanted(admincaster_wanted_message.criminal, admincaster_wanted_message.body, admin_signature, null, 1, 1) - src.admincaster_screen = 15 - else - GLOB.news_network.submitWanted(admincaster_wanted_message.criminal, admincaster_wanted_message.body, admin_signature) - src.admincaster_screen = 19 - log_admin("[key_name(usr)] issued a Station-wide Wanted Notification for [src.admincaster_wanted_message.criminal]!") - src.access_news_network() - - else if(href_list["ac_cancel_wanted"]) - if(!check_rights(R_ADMIN)) - return - var/choice = alert("Please confirm Wanted Issue removal.","Network Security Handler","Confirm","Cancel") - if(choice=="Confirm") - GLOB.news_network.deleteWanted() - src.admincaster_screen=17 - src.access_news_network() - - else if(href_list["ac_censor_channel_author"]) - if(!check_rights(R_ADMIN)) - return - var/datum/newscaster/feed_channel/FC = locate(href_list["ac_censor_channel_author"]) - FC.toggleCensorAuthor() - src.access_news_network() - - else if(href_list["ac_censor_channel_story_author"]) - if(!check_rights(R_ADMIN)) - return - var/datum/newscaster/feed_message/MSG = locate(href_list["ac_censor_channel_story_author"]) - MSG.toggleCensorAuthor() - src.access_news_network() - - else if(href_list["ac_censor_channel_story_body"]) - if(!check_rights(R_ADMIN)) - return - var/datum/newscaster/feed_message/MSG = locate(href_list["ac_censor_channel_story_body"]) - MSG.toggleCensorBody() - src.access_news_network() - - else if(href_list["ac_pick_d_notice"]) - if(!check_rights(R_ADMIN)) - return - var/datum/newscaster/feed_channel/FC = locate(href_list["ac_pick_d_notice"]) - src.admincaster_feed_channel = FC - src.admincaster_screen=13 - src.access_news_network() - - else if(href_list["ac_toggle_d_notice"]) - if(!check_rights(R_ADMIN)) - return - var/datum/newscaster/feed_channel/FC = locate(href_list["ac_toggle_d_notice"]) - FC.toggleCensorDclass() - src.access_news_network() - - else if(href_list["ac_view"]) - if(!check_rights(R_ADMIN)) - return - src.admincaster_screen=1 - src.access_news_network() - - else if(href_list["ac_setScreen"]) //Brings us to the main menu and resets all fields~ - if(!check_rights(R_ADMIN)) - return - src.admincaster_screen = text2num(href_list["ac_setScreen"]) - if (src.admincaster_screen == 0) - if(src.admincaster_feed_channel) - src.admincaster_feed_channel = new /datum/newscaster/feed_channel - if(src.admincaster_feed_message) - src.admincaster_feed_message = new /datum/newscaster/feed_message - if(admincaster_wanted_message) - admincaster_wanted_message = new /datum/newscaster/wanted_message - src.access_news_network() - - else if(href_list["ac_show_channel"]) - if(!check_rights(R_ADMIN)) - return - var/datum/newscaster/feed_channel/FC = locate(href_list["ac_show_channel"]) - src.admincaster_feed_channel = FC - src.admincaster_screen = 9 - src.access_news_network() - - else if(href_list["ac_pick_censor_channel"]) - if(!check_rights(R_ADMIN)) - return - var/datum/newscaster/feed_channel/FC = locate(href_list["ac_pick_censor_channel"]) - src.admincaster_feed_channel = FC - src.admincaster_screen = 12 - src.access_news_network() - - else if(href_list["ac_refresh"]) - if(!check_rights(R_ADMIN)) - return - src.access_news_network() - - else if(href_list["ac_set_signature"]) - if(!check_rights(R_ADMIN)) - return - src.admin_signature = adminscrub(input(usr, "Provide your desired signature.", "Network Identity Handler", "")) - src.access_news_network() - - else if(href_list["ac_del_comment"]) - if(!check_rights(R_ADMIN)) - return - var/datum/newscaster/feed_comment/FC = locate(href_list["ac_del_comment"]) - var/datum/newscaster/feed_message/FM = locate(href_list["ac_del_comment_msg"]) - FM.comments -= FC - qdel(FC) - src.access_news_network() - - else if(href_list["ac_lock_comment"]) - if(!check_rights(R_ADMIN)) - return - var/datum/newscaster/feed_message/FM = locate(href_list["ac_lock_comment"]) - FM.locked ^= 1 - src.access_news_network() - - else if(href_list["check_antagonist"]) - if(!check_rights(R_ADMIN)) - return - usr.client.check_antagonists() - - else if(href_list["kick_all_from_lobby"]) - if(!check_rights(R_ADMIN)) - return - if(SSticker.IsRoundInProgress()) - var/afkonly = text2num(href_list["afkonly"]) - if(alert("Are you sure you want to kick all [afkonly ? "AFK" : ""] clients from the lobby??","Message","Yes","Cancel") != "Yes") - to_chat(usr, "Kick clients from lobby aborted") - return - var/list/listkicked = kick_clients_in_lobby("You were kicked from the lobby by [usr.client.holder.fakekey ? "an Administrator" : "[usr.client.key]"].", afkonly) - - var/strkicked = "" - for(var/name in listkicked) - strkicked += "[name], " - message_admins("[key_name_admin(usr)] has kicked [afkonly ? "all AFK" : "all"] clients from the lobby. [length(listkicked)] clients kicked: [strkicked ? strkicked : "--"]") - log_admin("[key_name(usr)] has kicked [afkonly ? "all AFK" : "all"] clients from the lobby. [length(listkicked)] clients kicked: [strkicked ? strkicked : "--"]") - else - to_chat(usr, "You may only use this when the game is running.") - - else if(href_list["create_outfit"]) - if(!check_rights(R_ADMIN)) - return - - var/datum/outfit/O = new /datum/outfit - //swap this for js dropdowns sometime - O.name = href_list["outfit_name"] - O.uniform = text2path(href_list["outfit_uniform"]) - O.shoes = text2path(href_list["outfit_shoes"]) - O.gloves = text2path(href_list["outfit_gloves"]) - O.suit = text2path(href_list["outfit_suit"]) - O.head = text2path(href_list["outfit_head"]) - O.back = text2path(href_list["outfit_back"]) - O.mask = text2path(href_list["outfit_mask"]) - O.glasses = text2path(href_list["outfit_glasses"]) - O.r_hand = text2path(href_list["outfit_r_hand"]) - O.l_hand = text2path(href_list["outfit_l_hand"]) - O.suit_store = text2path(href_list["outfit_s_store"]) - O.l_pocket = text2path(href_list["outfit_l_pocket"]) - O.r_pocket = text2path(href_list["outfit_r_pocket"]) - O.id = text2path(href_list["outfit_id"]) - O.belt = text2path(href_list["outfit_belt"]) - O.ears = text2path(href_list["outfit_ears"]) - - GLOB.custom_outfits.Add(O) - message_admins("[key_name(usr)] created \"[O.name]\" outfit!") - - else if(href_list["set_selfdestruct_code"]) - if(!check_rights(R_ADMIN)) - return - var/code = random_nukecode() - for(var/obj/machinery/nuclearbomb/selfdestruct/SD in GLOB.nuke_list) - SD.r_code = code - message_admins("[key_name_admin(usr)] has set the self-destruct \ - code to \"[code]\".") - - else if(href_list["add_station_goal"]) - if(!check_rights(R_ADMIN)) - return - var/list/type_choices = typesof(/datum/station_goal) - var/picked = input("Choose goal type") in type_choices|null - if(!picked) - return - var/datum/station_goal/G = new picked() - if(picked == /datum/station_goal) - var/newname = input("Enter goal name:") as text|null - if(!newname) - return - G.name = newname - var/description = input("Enter CentCom message contents:") as message|null - if(!description) - return - G.report_message = description - message_admins("[key_name(usr)] created \"[G.name]\" station goal.") - SSticker.mode.station_goals += G - modify_goals() - - else if(href_list["viewruntime"]) - var/datum/error_viewer/error_viewer = locate(href_list["viewruntime"]) - if(!istype(error_viewer)) - to_chat(usr, "That runtime viewer no longer exists.") - return - - if(href_list["viewruntime_backto"]) - error_viewer.show_to(owner, locate(href_list["viewruntime_backto"]), href_list["viewruntime_linear"]) - else - error_viewer.show_to(owner, null, href_list["viewruntime_linear"]) - - else if(href_list["showrelatedacc"]) - if(!check_rights(R_ADMIN)) - return - var/client/C = locate(href_list["client"]) in GLOB.clients - var/thing_to_check - if(href_list["showrelatedacc"] == "cid") - thing_to_check = C.related_accounts_cid - else - thing_to_check = C.related_accounts_ip - thing_to_check = splittext(thing_to_check, ", ") - - - var/list/dat = list("Related accounts by [uppertext(href_list["showrelatedacc"])]:") - dat += thing_to_check - - usr << browse(dat.Join("
"), "window=related_[C];size=420x300") - else if(href_list["centcomlookup"]) - if(!check_rights(R_ADMIN)) - return - - if(!CONFIG_GET(string/centcom_ban_db)) - to_chat(usr, "Centcom Galactic Ban DB is disabled!") - return - - var/ckey = href_list["centcomlookup"] - - // Make the request - var/datum/http_request/request = new() - request.prepare(RUSTG_HTTP_METHOD_GET, "[CONFIG_GET(string/centcom_ban_db)]/[ckey]", "", "") - request.begin_async() - UNTIL(request.is_complete() || !usr) - if (!usr) - return - var/datum/http_response/response = request.into_response() - - var/list/bans - - var/list/dat = list("") - - if(response.errored) - dat += "
Failed to connect to CentCom." - else if(response.status_code != 200) - dat += "
Failed to connect to CentCom. Status code: [response.status_code]" - else - if(response.body == "[]") - dat += "
0 bans detected for [ckey]
" - else - bans = json_decode(response["body"]) - dat += "
[bans.len] ban\s detected for [ckey]
" - for(var/list/ban in bans) - dat += "Server: [sanitize(ban["sourceName"])]
" - dat += "RP Level: [sanitize(ban["sourceRoleplayLevel"])]
" - dat += "Type: [sanitize(ban["type"])]
" - dat += "Banned By: [sanitize(ban["bannedBy"])]
" - dat += "Reason: [sanitize(ban["reason"])]
" - dat += "Datetime: [sanitize(ban["bannedOn"])]
" - var/expiration = ban["expires"] - dat += "Expires: [expiration ? "[sanitize(expiration)]" : "Permanent"]
" - if(ban["type"] == "job") - dat += "Jobs: " - var/list/jobs = ban["jobs"] - dat += sanitize(jobs.Join(", ")) - dat += "
" - dat += "
" - - dat += "
" - var/datum/browser/popup = new(usr, "centcomlookup-[ckey]", "
Central Command Galactic Ban Database
", 700, 600) - popup.set_content(dat.Join()) - popup.open(0) - - - else if(href_list["modantagrep"]) - if(!check_rights(R_ADMIN)) - return - - var/mob/M = locate(href_list["mob"]) in GLOB.mob_list - var/client/C = M.client - usr.client.cmd_admin_mod_antag_rep(C, href_list["modantagrep"]) - show_player_panel(M) - - else if(href_list["slowquery"]) - if(!check_rights(R_ADMIN)) - return - var/answer = href_list["slowquery"] - if(answer == "yes") - log_query_debug("[usr.key] | Reported a server hang") - if(alert(usr, "Had you just press any admin buttons?", "Query server hang report", "Yes", "No") == "Yes") - var/response = input(usr,"What were you just doing?","Query server hang report") as null|text - if(response) - log_query_debug("[usr.key] | [response]") - else if(answer == "no") - log_query_debug("[usr.key] | Reported no server hang") - -/datum/admins/proc/HandleCMode() - if(!check_rights(R_ADMIN)) - return - - if(SSticker.HasRoundStarted()) - return alert(usr, "The game has already started.", null, null, null, null) - var/dat = {"What mode do you wish to play?
"} - for(var/mode in config.modes) - dat += {"[config.mode_names[mode]]
"} - dat += {"Secret
"} - dat += {"Random
"} - dat += {"Now: [GLOB.master_mode]"} - usr << browse(dat, "window=c_mode") - -/datum/admins/proc/HandleFSecret() - if(!check_rights(R_ADMIN)) - return - - if(SSticker.HasRoundStarted()) - return alert(usr, "The game has already started.", null, null, null, null) - if(GLOB.master_mode != "secret") - return alert(usr, "The game mode has to be secret!", null, null, null, null) - var/dat = {"What game mode do you want to force secret to be? Use this if you want to change the game mode, but want the players to believe it's secret. This will only work if the current game mode is secret.
"} - for(var/mode in config.modes) - dat += {"[config.mode_names[mode]]
"} - dat += {"Random (default)
"} - dat += {"Now: [GLOB.secret_force_mode]"} - usr << browse(dat, "window=f_secret") - -/datum/admins/proc/makeMentor(ckey) - if(!usr.client) - return - if (!check_rights(0)) - return - if(!ckey) - return - var/client/C = GLOB.directory[ckey] - if(C) - if(check_rights_for(C, R_ADMIN,0)) - to_chat(usr, "The client chosen is an admin! Cannot mentorize.") - return - if(SSdbcore.Connect()) - var/datum/DBQuery/query_get_mentor = SSdbcore.NewQuery("SELECT id FROM [format_table_name("mentor")] WHERE ckey = '[ckey]'") - if(query_get_mentor.NextRow()) - to_chat(usr, "[ckey] is already a mentor.") - return - var/datum/DBQuery/query_add_mentor = SSdbcore.NewQuery("INSERT INTO `[format_table_name("mentor")]` (`id`, `ckey`) VALUES (null, '[ckey]')") - if(!query_add_mentor.warn_execute()) - return - var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO `[format_table_name("admin_log")]` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added new mentor [ckey]');") - if(!query_add_admin_log.warn_execute()) - return - else - to_chat(usr, "Failed to establish database connection. The changes will last only for the current round.") - new /datum/mentors(ckey) - to_chat(usr, "New mentor added.") - -/datum/admins/proc/removeMentor(ckey) - if(!usr.client) - return - if (!check_rights(0)) - return - if(!ckey) - return - var/client/C = GLOB.directory[ckey] - if(C) - if(check_rights_for(C, R_ADMIN,0)) - to_chat(usr, "The client chosen is an admin, not a mentor! Cannot de-mentorize.") - return - C.remove_mentor_verbs() - C.mentor_datum = null - GLOB.mentors -= C - if(SSdbcore.Connect()) - var/datum/DBQuery/query_remove_mentor = SSdbcore.NewQuery("DELETE FROM [format_table_name("mentor")] WHERE ckey = '[ckey]'") - if(!query_remove_mentor.warn_execute()) - return - var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO `[format_table_name("admin_log")]` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Removed mentor [ckey]');") - if(!query_add_admin_log.warn_execute()) - return - else - to_chat(usr, "Failed to establish database connection. The changes will last only for the current round.") - to_chat(usr, "Mentor removed.") +/datum/admins/proc/CheckAdminHref(href, href_list) + var/auth = href_list["admin_token"] + . = auth && (auth == href_token || auth == GLOB.href_token) + if(.) + return + var/msg = !auth ? "no" : "a bad" + message_admins("[key_name_admin(usr)] clicked an href with [msg] authorization key!") + if(CONFIG_GET(flag/debug_admin_hrefs)) + message_admins("Debug mode enabled, call not blocked. Please ask your coders to review this round's logs.") + log_world("UAH: [href]") + return TRUE + log_admin_private("[key_name(usr)] clicked an href with [msg] authorization key! [href]") + +/datum/admins/Topic(href, href_list) + ..() + + if(usr.client != src.owner || !check_rights(0)) + message_admins("[usr.key] tried to use the admin panel without authorization.") + log_admin("[key_name(usr)] tried to use the admin panel without authorization.") + return + + if(!CheckAdminHref(href, href_list)) + return + + if(href_list["makementor"]) + makeMentor(href_list["makementor"]) + else if(href_list["removementor"]) + removeMentor(href_list["removementor"]) + + if(href_list["ahelp"]) + if(!check_rights(R_ADMIN, TRUE)) + return + + var/ahelp_ref = href_list["ahelp"] + var/datum/admin_help/AH = locate(ahelp_ref) + if(AH) + AH.Action(href_list["ahelp_action"]) + else + to_chat(usr, "Ticket [ahelp_ref] has been deleted!") + + else if(href_list["ahelp_tickets"]) + GLOB.ahelp_tickets.BrowseTickets(text2num(href_list["ahelp_tickets"])) + + else if(href_list["stickyban"]) + stickyban(href_list["stickyban"],href_list) + + else if(href_list["getplaytimewindow"]) + if(!check_rights(R_ADMIN)) + return + var/mob/M = locate(href_list["getplaytimewindow"]) in GLOB.mob_list + if(!M) + to_chat(usr, "ERROR: Mob not found.") + return + cmd_show_exp_panel(M.client) + + else if(href_list["toggleexempt"]) + if(!check_rights(R_ADMIN)) + return + var/client/C = locate(href_list["toggleexempt"]) in GLOB.clients + if(!C) + to_chat(usr, "ERROR: Client not found.") + return + toggle_exempt_status(C) + + else if(href_list["makeAntag"]) + if(!check_rights(R_ADMIN)) + return + if (!SSticker.mode) + to_chat(usr, "Not until the round starts!") + return + switch(href_list["makeAntag"]) + if("traitors") + if(src.makeTraitors()) + message_admins("[key_name_admin(usr)] created traitors.") + log_admin("[key_name(usr)] created traitors.") + else + message_admins("[key_name_admin(usr)] tried to create traitors. Unfortunately, there were no candidates available.") + log_admin("[key_name(usr)] failed to create traitors.") + if("changelings") + if(src.makeChangelings()) + message_admins("[key_name(usr)] created changelings.") + log_admin("[key_name(usr)] created changelings.") + else + message_admins("[key_name_admin(usr)] tried to create changelings. Unfortunately, there were no candidates available.") + log_admin("[key_name(usr)] failed to create changelings.") + if("revs") + if(src.makeRevs()) + message_admins("[key_name(usr)] started a revolution.") + log_admin("[key_name(usr)] started a revolution.") + else + message_admins("[key_name_admin(usr)] tried to start a revolution. Unfortunately, there were no candidates available.") + log_admin("[key_name(usr)] failed to start a revolution.") + if("cult") + if(src.makeCult()) + message_admins("[key_name(usr)] started a cult.") + log_admin("[key_name(usr)] started a cult.") + else + message_admins("[key_name_admin(usr)] tried to start a cult. Unfortunately, there were no candidates available.") + log_admin("[key_name(usr)] failed to start a cult.") + if("wizard") + message_admins("[key_name(usr)] is creating a wizard...") + if(src.makeWizard()) + message_admins("[key_name(usr)] created a wizard.") + log_admin("[key_name(usr)] created a wizard.") + else + message_admins("[key_name_admin(usr)] tried to create a wizard. Unfortunately, there were no candidates available.") + log_admin("[key_name(usr)] failed to create a wizard.") + if("nukeops") + message_admins("[key_name(usr)] is creating a nuke team...") + if(src.makeNukeTeam()) + message_admins("[key_name(usr)] created a nuke team.") + log_admin("[key_name(usr)] created a nuke team.") + 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("ninja") + message_admins("[key_name(usr)] spawned a ninja.") + log_admin("[key_name(usr)] spawned a ninja.") + src.makeSpaceNinja() + if("aliens") + message_admins("[key_name(usr)] started an alien infestation.") + log_admin("[key_name(usr)] started an alien infestation.") + src.makeAliens() + if("deathsquad") + message_admins("[key_name(usr)] is creating a death squad...") + if(src.makeDeathsquad()) + message_admins("[key_name(usr)] created a death squad.") + log_admin("[key_name(usr)] created a death squad.") + else + message_admins("[key_name_admin(usr)] tried to create a death squad. Unfortunately, there were not enough candidates available.") + log_admin("[key_name(usr)] failed to create a death squad.") + if("blob") + var/strength = input("Set Blob Resource Gain Rate","Set Resource Rate",1) as num|null + if(!strength) + return + message_admins("[key_name(usr)] spawned a blob with base resource gain [strength].") + log_admin("[key_name(usr)] spawned a blob with base resource gain [strength].") + new/datum/round_event/ghost_role/blob(TRUE, strength) + if("centcom") + message_admins("[key_name(usr)] is creating a CentCom response team...") + if(src.makeEmergencyresponseteam()) + message_admins("[key_name(usr)] created a CentCom response team.") + log_admin("[key_name(usr)] created a CentCom response team.") + else + message_admins("[key_name_admin(usr)] tried to create a CentCom response team. Unfortunately, there were not enough candidates available.") + log_admin("[key_name(usr)] failed to create a CentCom response team.") + if("abductors") + message_admins("[key_name(usr)] is creating an abductor team...") + if(src.makeAbductorTeam()) + message_admins("[key_name(usr)] created an abductor team.") + log_admin("[key_name(usr)] created an abductor team.") + else + message_admins("[key_name_admin(usr)] tried to create an abductor team. Unfortunatly there were not enough candidates available.") + log_admin("[key_name(usr)] failed to create an abductor team.") + if("clockcult") + if(src.makeClockCult()) + message_admins("[key_name(usr)] started a clockwork cult.") + log_admin("[key_name(usr)] started a clockwork cult.") + else + message_admins("[key_name_admin(usr)] tried to start a clockwork cult. Unfortunately, there were no candidates available.") + log_admin("[key_name(usr)] failed to start a clockwork cult.") + if("revenant") + if(src.makeRevenant()) + message_admins("[key_name(usr)] created a revenant.") + log_admin("[key_name(usr)] created a revenant.") + else + message_admins("[key_name_admin(usr)] tried to create a revenant. Unfortunately, there were no candidates available.") + log_admin("[key_name(usr)] failed to create a revenant.") + //Hyper + if("lewdtraitors") + if(src.makeLewdtraitors()) + message_admins("[key_name(usr)] created a lewd traitor.") + log_admin("[key_name(usr)] created a lewd traitor.") + else + message_admins("[key_name_admin(usr)] tried to create a lewd traitor. Unfortunately, there were no candidates available.") + log_admin("[key_name(usr)] failed to create a lewd traitor.") + + else if(href_list["forceevent"]) + if(!check_rights(R_FUN)) + return + var/datum/round_event_control/E = locate(href_list["forceevent"]) in SSevents.control + if(E) + E.admin_setup(usr) + var/datum/round_event/event = E.runEvent() + if(event.announceWhen>0) + event.processing = FALSE + var/prompt = alert(usr, "Would you like to alert the crew?", "Alert", "Yes", "No", "Cancel") + switch(prompt) + if("Cancel") + event.kill() + return + if("No") + event.announceWhen = -1 + event.processing = TRUE + message_admins("[key_name_admin(usr)] has triggered an event. ([E.name])") + log_admin("[key_name(usr)] has triggered an event. ([E.name])") + return + + else if(href_list["dbsearchckey"] || href_list["dbsearchadmin"] || href_list["dbsearchip"] || href_list["dbsearchcid"]) + var/adminckey = href_list["dbsearchadmin"] + var/playerckey = href_list["dbsearchckey"] + var/ip = href_list["dbsearchip"] + var/cid = href_list["dbsearchcid"] + var/page = href_list["dbsearchpage"] + + DB_ban_panel(playerckey, adminckey, ip, cid, page) + return + + else if(href_list["dbbanedit"]) + var/banedit = href_list["dbbanedit"] + var/banid = text2num(href_list["dbbanid"]) + if(!banedit || !banid) + return + + DB_ban_edit(banid, banedit) + return + + else if(href_list["dbbanaddtype"]) + if(!check_rights(R_BAN)) + return + var/bantype = text2num(href_list["dbbanaddtype"]) + var/bankey = href_list["dbbanaddkey"] + var/banckey = ckey(bankey) + var/banip = href_list["dbbanaddip"] + var/bancid = href_list["dbbanaddcid"] + var/banduration = text2num(href_list["dbbaddduration"]) + var/banjob = href_list["dbbanaddjob"] + var/banreason = href_list["dbbanreason"] + var/banseverity = href_list["dbbanaddseverity"] + + switch(bantype) + if(BANTYPE_PERMA) + if(!banckey || !banreason || !banseverity) + to_chat(usr, "Not enough parameters (Requires ckey, severity, and reason).") + return + banduration = null + banjob = null + if(BANTYPE_TEMP) + if(!banckey || !banreason || !banduration || !banseverity) + to_chat(usr, "Not enough parameters (Requires ckey, reason, severity and duration).") + return + banjob = null + if(BANTYPE_JOB_PERMA) + if(!banckey || !banreason || !banjob || !banseverity) + to_chat(usr, "Not enough parameters (Requires ckey, severity, reason and job).") + return + banduration = null + if(BANTYPE_JOB_TEMP) + if(!banckey || !banreason || !banjob || !banduration || !banseverity) + to_chat(usr, "Not enough parameters (Requires ckey, severity, reason and job).") + return + if(BANTYPE_ADMIN_PERMA) + if(!banckey || !banreason || !banseverity) + to_chat(usr, "Not enough parameters (Requires ckey, severity and reason).") + return + banduration = null + banjob = null + if(BANTYPE_ADMIN_TEMP) + if(!banckey || !banreason || !banduration || !banseverity) + to_chat(usr, "Not enough parameters (Requires ckey, severity, reason and duration).") + return + banjob = null + + var/mob/playermob + + for(var/mob/M in GLOB.player_list) + if(M.ckey == banckey) + playermob = M + break + + + banreason = "(MANUAL BAN) "+banreason + + if(!playermob) + if(banip) + banreason = "[banreason] (CUSTOM IP)" + if(bancid) + banreason = "[banreason] (CUSTOM CID)" + else + message_admins("Ban process: A mob matching [playermob.key] was found at location [playermob.x], [playermob.y], [playermob.z]. Custom ip and computer id fields replaced with the ip and computer id from the located mob.") + + if(!DB_ban_record(bantype, playermob, banduration, banreason, banjob, bankey, banip, bancid )) + to_chat(usr, "Failed to apply ban.") + return + create_message("note", bankey, null, banreason, null, null, 0, 0, null, 0, banseverity) + + else if(href_list["editrightsbrowser"]) + edit_admin_permissions(0) + + else if(href_list["editrightsbrowserlog"]) + edit_admin_permissions(1, href_list["editrightstarget"], href_list["editrightsoperation"], href_list["editrightspage"]) + + if(href_list["editrightsbrowsermanage"]) + if(href_list["editrightschange"]) + change_admin_rank(ckey(href_list["editrightschange"]), href_list["editrightschange"], TRUE) + else if(href_list["editrightsremove"]) + remove_admin(ckey(href_list["editrightsremove"]), href_list["editrightsremove"], TRUE) + else if(href_list["editrightsremoverank"]) + remove_rank(href_list["editrightsremoverank"]) + edit_admin_permissions(2) + + else if(href_list["editrights"]) + edit_rights_topic(href_list) + + else if(href_list["gamemode_panel"]) + if(!check_rights(R_ADMIN)) + return + SSticker.mode.admin_panel() + + + else if(href_list["call_shuttle"]) + if(!check_rights(R_ADMIN)) + return + + + switch(href_list["call_shuttle"]) + if("1") + if(EMERGENCY_AT_LEAST_DOCKED) + return + SSshuttle.emergency.request() + log_admin("[key_name(usr)] called the Emergency Shuttle.") + message_admins("[key_name_admin(usr)] called the Emergency Shuttle to the station.") + + if("2") + if(EMERGENCY_AT_LEAST_DOCKED) + return + switch(SSshuttle.emergency.mode) + if(SHUTTLE_CALL) + SSshuttle.emergency.cancel() + log_admin("[key_name(usr)] sent the Emergency Shuttle back.") + message_admins("[key_name_admin(usr)] sent the Emergency Shuttle back.") + else + SSshuttle.emergency.cancel() + log_admin("[key_name(usr)] called the Emergency Shuttle.") + message_admins("[key_name_admin(usr)] called the Emergency Shuttle to the station.") + + + href_list["secrets"] = "check_antagonist" + + else if(href_list["edit_shuttle_time"]) + if(!check_rights(R_SERVER)) + return + + var/timer = input("Enter new shuttle duration (seconds):","Edit Shuttle Timeleft", SSshuttle.emergency.timeLeft() ) as num|null + if(!timer) + return + SSshuttle.emergency.setTimer(timer*10) + log_admin("[key_name(usr)] edited the Emergency Shuttle's timeleft to [timer] seconds.") + minor_announce("The emergency shuttle will reach its destination in [round(SSshuttle.emergency.timeLeft(600))] minutes.") + message_admins("[key_name_admin(usr)] edited the Emergency Shuttle's timeleft to [timer] seconds.") + href_list["secrets"] = "check_antagonist" + else if(href_list["trigger_centcom_recall"]) + if(!check_rights(R_ADMIN)) + return + + usr.client.trigger_centcom_recall() + + else if(href_list["toggle_continuous"]) + if(!check_rights(R_ADMIN)) + return + var/list/continuous = CONFIG_GET(keyed_list/continuous) + if(!continuous[SSticker.mode.config_tag]) + continuous[SSticker.mode.config_tag] = TRUE + else + continuous[SSticker.mode.config_tag] = FALSE + + message_admins("[key_name_admin(usr)] toggled the round to [continuous[SSticker.mode.config_tag] ? "continue if all antagonists die" : "end with the antagonists"].") + check_antagonists() + + else if(href_list["toggle_midround_antag"]) + if(!check_rights(R_ADMIN)) + return + + var/list/midround_antag = CONFIG_GET(keyed_list/midround_antag) + if(!midround_antag[SSticker.mode.config_tag]) + midround_antag[SSticker.mode.config_tag] = TRUE + else + midround_antag[SSticker.mode.config_tag] = FALSE + + message_admins("[key_name_admin(usr)] toggled the round to [midround_antag[SSticker.mode.config_tag] ? "use" : "skip"] the midround antag system.") + check_antagonists() + + else if(href_list["alter_midround_time_limit"]) + if(!check_rights(R_ADMIN)) + return + + var/timer = input("Enter new maximum time",, CONFIG_GET(number/midround_antag_time_check)) as num|null + if(!timer) + return + CONFIG_SET(number/midround_antag_time_check, timer) + message_admins("[key_name_admin(usr)] edited the maximum midround antagonist time to [timer] minutes.") + check_antagonists() + + else if(href_list["alter_midround_life_limit"]) + if(!check_rights(R_ADMIN)) + return + + var/ratio = input("Enter new life ratio",, CONFIG_GET(number/midround_antag_life_check) * 100) as num + if(!ratio) + return + CONFIG_SET(number/midround_antag_life_check, ratio / 100) + + message_admins("[key_name_admin(usr)] edited the midround antagonist living crew ratio to [ratio]% alive.") + check_antagonists() + + else if(href_list["toggle_noncontinuous_behavior"]) + if(!check_rights(R_ADMIN)) + return + + if(!SSticker.mode.round_ends_with_antag_death) + SSticker.mode.round_ends_with_antag_death = 1 + else + SSticker.mode.round_ends_with_antag_death = 0 + + message_admins("[key_name_admin(usr)] edited the midround antagonist system to [SSticker.mode.round_ends_with_antag_death ? "end the round" : "continue as extended"] upon failure.") + check_antagonists() + + else if(href_list["delay_round_end"]) + if(!check_rights(R_SERVER)) + return + if(!SSticker.delay_end) + SSticker.admin_delay_notice = input(usr, "Enter a reason for delaying the round end", "Round Delay Reason") as null|text + if(isnull(SSticker.admin_delay_notice)) + return + else + SSticker.admin_delay_notice = null + SSticker.delay_end = !SSticker.delay_end + var/reason = SSticker.delay_end ? "for reason: [SSticker.admin_delay_notice]" : "."//laziness + var/msg = "[SSticker.delay_end ? "delayed" : "undelayed"] the round end [reason]" + log_admin("[key_name(usr)] [msg]") + message_admins("[key_name_admin(usr)] [msg]") + href_list["secrets"] = "check_antagonist" + if(SSticker.ready_for_reboot && !SSticker.delay_end) //we undelayed after standard reboot would occur + SSticker.standard_reboot() + + else if(href_list["end_round"]) + if(!check_rights(R_ADMIN)) + return + + message_admins("[key_name_admin(usr)] is considering ending the round.") + if(alert(usr, "This will end the round, are you SURE you want to do this?", "Confirmation", "Yes", "No") == "Yes") + if(alert(usr, "Final Confirmation: End the round NOW?", "Confirmation", "Yes", "No") == "Yes") + message_admins("[key_name_admin(usr)] has ended the round.") + SSticker.force_ending = 1 //Yeah there we go APC destroyed mission accomplished + return + else + message_admins("[key_name_admin(usr)] decided against ending the round.") + else + message_admins("[key_name_admin(usr)] decided against ending the round.") + + else if(href_list["simplemake"]) + if(!check_rights(R_SPAWN)) + return + + var/mob/M = locate(href_list["mob"]) + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob.") + return + + var/delmob = 0 + switch(alert("Delete old mob?","Message","Yes","No","Cancel")) + if("Cancel") + return + if("Yes") + delmob = 1 + + log_admin("[key_name(usr)] has used rudimentary transformation on [key_name(M)]. Transforming to [href_list["simplemake"]].; deletemob=[delmob]") + message_admins("[key_name_admin(usr)] has used rudimentary transformation on [key_name_admin(M)]. Transforming to [href_list["simplemake"]].; deletemob=[delmob]") + switch(href_list["simplemake"]) + if("observer") + M.change_mob_type( /mob/dead/observer , null, null, delmob ) + if("drone") + M.change_mob_type( /mob/living/carbon/alien/humanoid/drone , null, null, delmob ) + if("hunter") + M.change_mob_type( /mob/living/carbon/alien/humanoid/hunter , null, null, delmob ) + if("queen") + M.change_mob_type( /mob/living/carbon/alien/humanoid/royal/queen , null, null, delmob ) + if("praetorian") + M.change_mob_type( /mob/living/carbon/alien/humanoid/royal/praetorian , null, null, delmob ) + if("sentinel") + M.change_mob_type( /mob/living/carbon/alien/humanoid/sentinel , null, null, delmob ) + if("larva") + M.change_mob_type( /mob/living/carbon/alien/larva , null, null, delmob ) + if("human") + var/posttransformoutfit = usr.client.robust_dress_shop() + var/mob/living/carbon/human/newmob = M.change_mob_type( /mob/living/carbon/human , null, null, delmob ) + if(posttransformoutfit && istype(newmob)) + newmob.equipOutfit(posttransformoutfit) + if("slime") + M.change_mob_type( /mob/living/simple_animal/slime , null, null, delmob ) + if("monkey") + M.change_mob_type( /mob/living/carbon/monkey , null, null, delmob ) + if("robot") + M.change_mob_type( /mob/living/silicon/robot , null, null, delmob ) + if("cat") + M.change_mob_type( /mob/living/simple_animal/pet/cat , null, null, delmob ) + if("runtime") + M.change_mob_type( /mob/living/simple_animal/pet/cat/Runtime , null, null, delmob ) + if("corgi") + M.change_mob_type( /mob/living/simple_animal/pet/dog/corgi , null, null, delmob ) + if("ian") + M.change_mob_type( /mob/living/simple_animal/pet/dog/corgi/Ian , null, null, delmob ) + if("pug") + M.change_mob_type( /mob/living/simple_animal/pet/dog/pug , null, null, delmob ) + if("crab") + M.change_mob_type( /mob/living/simple_animal/crab , null, null, delmob ) + if("coffee") + M.change_mob_type( /mob/living/simple_animal/crab/Coffee , null, null, delmob ) + if("parrot") + M.change_mob_type( /mob/living/simple_animal/parrot , null, null, delmob ) + if("polyparrot") + M.change_mob_type( /mob/living/simple_animal/parrot/Poly , null, null, delmob ) + if("constructarmored") + M.change_mob_type( /mob/living/simple_animal/hostile/construct/armored , null, null, delmob ) + if("constructbuilder") + M.change_mob_type( /mob/living/simple_animal/hostile/construct/builder , null, null, delmob ) + if("constructwraith") + M.change_mob_type( /mob/living/simple_animal/hostile/construct/wraith , null, null, delmob ) + if("shade") + M.change_mob_type( /mob/living/simple_animal/shade , null, null, delmob ) + + + /////////////////////////////////////new ban stuff + else if(href_list["unbanf"]) + if(!check_rights(R_BAN)) + return + + var/banfolder = href_list["unbanf"] + GLOB.Banlist.cd = "/base/[banfolder]" + var/key = GLOB.Banlist["key"] + if(alert(usr, "Are you sure you want to unban [key]?", "Confirmation", "Yes", "No") == "Yes") + if(RemoveBan(banfolder)) + unbanpanel() + else + alert(usr, "This ban has already been lifted / does not exist.", "Error", "Ok") + unbanpanel() + + else if(href_list["unbane"]) + if(!check_rights(R_BAN)) + return + + UpdateTime() + var/reason + + var/banfolder = href_list["unbane"] + GLOB.Banlist.cd = "/base/[banfolder]" + var/reason2 = GLOB.Banlist["reason"] + var/temp = GLOB.Banlist["temp"] + + var/minutes = GLOB.Banlist["minutes"] + + var/banned_key = GLOB.Banlist["key"] + GLOB.Banlist.cd = "/base" + + var/duration + + switch(alert("Temporary Ban for [banned_key]?",,"Yes","No")) + if("Yes") + temp = 1 + var/mins = 0 + if(minutes > GLOB.CMinutes) + mins = minutes - GLOB.CMinutes + mins = input(usr,"How long (in minutes)? (Default: 1440)","Ban time",mins ? mins : 1440) as num|null + if(mins <= 0) + to_chat(usr, "[mins] is not a valid duration.") + return + minutes = GLOB.CMinutes + mins + duration = GetExp(minutes) + reason = input(usr,"Please State Reason For Banning [banned_key].","Reason",reason2) as message|null + if(!reason) + return + if("No") + temp = 0 + duration = "Perma" + reason = input(usr,"Please State Reason For Banning [banned_key].","Reason",reason2) as message|null + if(!reason) + return + + log_admin_private("[key_name(usr)] edited [banned_key]'s ban. Reason: [reason] Duration: [duration]") + ban_unban_log_save("[key_name(usr)] edited [banned_key]'s ban. Reason: [reason] Duration: [duration]") + message_admins("[key_name_admin(usr)] edited [banned_key]'s ban. Reason: [reason] Duration: [duration]") + GLOB.Banlist.cd = "/base/[banfolder]" + WRITE_FILE(GLOB.Banlist["reason"], reason) + WRITE_FILE(GLOB.Banlist["temp"], temp) + WRITE_FILE(GLOB.Banlist["minutes"], minutes) + WRITE_FILE(GLOB.Banlist["bannedby"], usr.ckey) + GLOB.Banlist.cd = "/base" + unbanpanel() + + /////////////////////////////////////new ban stuff + + else if(href_list["appearanceban"]) + if(!check_rights(R_BAN)) + return + var/mob/M = locate(href_list["appearanceban"]) + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + if(!M.ckey) //sanity + to_chat(usr, "This mob has no ckey") + return + + + if(jobban_isbanned(M, "appearance")) + switch(alert("Remove appearance ban?","Please Confirm","Yes","No")) + if("Yes") + ban_unban_log_save("[key_name(usr)] removed [key_name(M)]'s appearance ban.") + log_admin_private("[key_name(usr)] removed [key_name(M)]'s appearance ban.") + DB_ban_unban(M.ckey, BANTYPE_ANY_JOB, "appearance") + if(M.client) + jobban_buildcache(M.client) + message_admins("[key_name_admin(usr)] removed [key_name_admin(M)]'s appearance ban.") + to_chat(M, "[usr.client.key] has removed your appearance ban.") + + else switch(alert("Appearance ban [M.key]?",,"Yes","No", "Cancel")) + if("Yes") + var/reason = input(usr,"Please State Reason.","Reason") as message|null + if(!reason) + return + var/severity = input("Set the severity of the note/ban.", "Severity", null, null) as null|anything in list("High", "Medium", "Minor", "None") + if(!severity) + return + if(!DB_ban_record(BANTYPE_JOB_PERMA, M, -1, reason, "appearance")) + to_chat(usr, "Failed to apply ban.") + return + if(M.client) + jobban_buildcache(M.client) + ban_unban_log_save("[key_name(usr)] appearance banned [key_name(M)]. reason: [reason]") + log_admin_private("[key_name(usr)] appearance banned [key_name(M)]. \nReason: [reason]") + create_message("note", M.key, null, "Appearance banned - [reason]", null, null, 0, 0, null, 0, severity) + message_admins("[key_name_admin(usr)] appearance banned [key_name_admin(M)].") + to_chat(M, "You have been appearance banned by [usr.client.key].") + to_chat(M, "The reason is: [reason]") + to_chat(M, "Appearance ban can be lifted only upon request.") + var/bran = CONFIG_GET(string/banappeals) + if(bran) + to_chat(M, "To try to resolve this matter head to [bran]") + else + to_chat(M, "No ban appeals URL has been set.") + if("No") + return + + else if(href_list["jobban2"]) + if(!check_rights(R_BAN)) + return + var/mob/M = locate(href_list["jobban2"]) + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob.") + return + + if(!M.ckey) //sanity + to_chat(usr, "This mob has no ckey.") + return + + var/dat = "Job-Ban Panel: [key_name(M)]" + + /***********************************WARNING!************************************ + The jobban stuff looks mangled and disgusting + But it looks beautiful in-game + -Nodrak + ************************************WARNING!***********************************/ + var/counter = 0 +//Regular jobs + //Command (Blue) + dat += "" + dat += "" + for(var/jobPos in GLOB.command_positions) + if(!jobPos) + continue + if(jobban_isbanned(M, jobPos)) + dat += "" + counter++ + else + dat += "" + counter++ + + if(counter >= 6) //So things dont get squiiiiished! + dat += "" + counter = 0 + dat += "
Command Positions
[jobPos][jobPos]
" + + //Security (Red) + counter = 0 + dat += "" + dat += "" + for(var/jobPos in GLOB.security_positions) + if(!jobPos) + continue + if(jobban_isbanned(M, jobPos)) + dat += "" + counter++ + else + dat += "" + counter++ + + if(counter >= 5) //So things dont get squiiiiished! + dat += "" + counter = 0 + dat += "
Security Positions
[jobPos][jobPos]
" + + //Engineering (Yellow) + counter = 0 + dat += "" + dat += "" + for(var/jobPos in GLOB.engineering_positions) + if(!jobPos) + continue + if(jobban_isbanned(M, jobPos)) + dat += "" + counter++ + else + dat += "" + counter++ + + if(counter >= 5) //So things dont get squiiiiished! + dat += "" + counter = 0 + dat += "
Engineering Positions
[jobPos][jobPos]
" + + //Medical (White) + counter = 0 + dat += "" + dat += "" + for(var/jobPos in GLOB.medical_positions) + if(!jobPos) + continue + if(jobban_isbanned(M, jobPos)) + dat += "" + counter++ + else + dat += "" + counter++ + + if(counter >= 5) //So things dont get squiiiiished! + dat += "" + counter = 0 + dat += "
Medical Positions
[jobPos][jobPos]
" + + //Science (Purple) + counter = 0 + dat += "" + dat += "" + for(var/jobPos in GLOB.science_positions) + if(!jobPos) + continue + if(jobban_isbanned(M, jobPos)) + dat += "" + counter++ + else + dat += "" + counter++ + + if(counter >= 5) //So things dont get squiiiiished! + dat += "" + counter = 0 + dat += "
Science Positions
[jobPos][jobPos]
" + + //Supply (Brown) + counter = 0 + dat += "" + dat += "" + for(var/jobPos in GLOB.supply_positions) + if(!jobPos) + continue + if(jobban_isbanned(M, jobPos)) + dat += "" + counter++ + else + dat += "" + counter++ + + if(counter >= 5) //So things dont get COPYPASTE! + dat += "" + counter = 0 + dat += "
Supply Positions
[jobPos][jobPos]
" + + //Civilian (Grey) + counter = 0 + dat += "" + dat += "" + for(var/jobPos in GLOB.civilian_positions) + if(!jobPos) + continue + if(jobban_isbanned(M, jobPos)) + dat += "" + counter++ + else + dat += "" + counter++ + + if(counter >= 5) //So things dont get squiiiiished! + dat += "" + counter = 0 + dat += "
Civilian Positions
[jobPos][jobPos]
" + + //Non-Human (Green) + counter = 0 + dat += "" + dat += "" + for(var/jobPos in GLOB.nonhuman_positions) + if(!jobPos) + continue + if(jobban_isbanned(M, jobPos)) + dat += "" + counter++ + else + dat += "" + counter++ + + if(counter >= 5) //So things dont get squiiiiished! + dat += "" + counter = 0 + + dat += "
Non-human Positions
[jobPos][jobPos]
" + + //Ghost Roles (light light gray) + dat += "" + dat += "" + + //pAI + if(jobban_isbanned(M, ROLE_PAI)) + dat += "" + else + dat += "" + + + //Drones + if(jobban_isbanned(M, ROLE_DRONE)) + dat += "" + else + dat += "" + + + //Positronic Brains + if(jobban_isbanned(M, ROLE_POSIBRAIN)) + dat += "" + else + dat += "" + + //Sentience Potion Spawn + if(jobban_isbanned(M, ROLE_SENTIENCE)) + dat += "" + else + dat += "" + + //Deathsquad + if(jobban_isbanned(M, ROLE_DEATHSQUAD)) + dat += "" + else + dat += "" + + //Lavaland roles + if(jobban_isbanned(M, ROLE_LAVALAND)) + dat += "" + else + dat += "" + + dat += "
Ghost Roles
pAIpAIDroneDronePosibrainPosibrainSentience Potion SpawnSentience Potion SpawnDeathsquadDeathsquadLavalandLavaland
" + + //Antagonist (Orange) + var/isbanned_dept = jobban_isbanned(M, ROLE_SYNDICATE) + dat += "" + dat += "" + + //Traitor + if(jobban_isbanned(M, ROLE_TRAITOR) || isbanned_dept) + dat += "" + else + dat += "" + + //Changeling + if(jobban_isbanned(M, ROLE_CHANGELING) || isbanned_dept) + dat += "" + else + dat += "" + + //Nuke Operative + if(jobban_isbanned(M, ROLE_OPERATIVE) || isbanned_dept) + dat += "" + else + dat += "" + + //Revolutionary + if(jobban_isbanned(M, ROLE_REV) || isbanned_dept) + dat += "" + else + dat += "" + + //Cultist + if(jobban_isbanned(M, ROLE_CULTIST) || isbanned_dept) + dat += "" + else + dat += "" + + dat += "" //So things dont get squished. + + //Servant of Ratvar + if(jobban_isbanned(M, ROLE_SERVANT_OF_RATVAR) || isbanned_dept) + dat += "" + else + dat += "" + + //Wizard + if(jobban_isbanned(M, ROLE_WIZARD) || isbanned_dept) + dat += "" + else + dat += "" + + //Abductor + if(jobban_isbanned(M, ROLE_ABDUCTOR) || isbanned_dept) + dat += "" + else + dat += "" + + //Alien + if(jobban_isbanned(M, ROLE_ALIEN) || isbanned_dept) + dat += "" + else + dat += "" + + //Gang + if(jobban_isbanned(M, ROLE_GANG) || isbanned_dept) + dat += "" + else + dat += "" + + + //Other Roles (black) + dat += "
Antagonist Positions | " + dat += "Team Antagonists | " + dat += "Conversion Antagonists
TraitorTraitorChangelingChangelingNuke OperativeNuke OperativeRevolutionaryRevolutionaryCultistCultist
ServantServantWizardWizardAbductorAbductorAlienAlienGangGang
" + dat += "" + + //Mind Transfer Potion + if(jobban_isbanned(M, ROLE_MIND_TRANSFER)) + dat += "" + else + dat += "" + + dat += "
Other Roles
Mind Transfer PotionMind Transfer Potion
" + usr << browse(dat, "window=jobban2;size=800x450") + return + + //JOBBAN'S INNARDS + else if(href_list["jobban3"]) + if(!check_rights(R_BAN)) + return + var/mob/M = locate(href_list["jobban4"]) + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + if(!SSjob) + to_chat(usr, "Jobs subsystem not initialized yet!") + return + //get jobs for department if specified, otherwise just return the one job in a list. + var/list/joblist = list() + switch(href_list["jobban3"]) + if("commanddept") + for(var/jobPos in GLOB.command_positions) + if(!jobPos) + continue + joblist += jobPos + if("securitydept") + for(var/jobPos in GLOB.security_positions) + if(!jobPos) + continue + joblist += jobPos + if("engineeringdept") + for(var/jobPos in GLOB.engineering_positions) + if(!jobPos) + continue + joblist += jobPos + if("medicaldept") + for(var/jobPos in GLOB.medical_positions) + if(!jobPos) + continue + joblist += jobPos + if("sciencedept") + for(var/jobPos in GLOB.science_positions) + if(!jobPos) + continue + joblist += jobPos + if("supplydept") + for(var/jobPos in GLOB.supply_positions) + if(!jobPos) + continue + joblist += jobPos + if("civiliandept") + for(var/jobPos in GLOB.civilian_positions) + if(!jobPos) + continue + joblist += jobPos + if("nonhumandept") + for(var/jobPos in GLOB.nonhuman_positions) + if(!jobPos) + continue + joblist += jobPos + if("ghostroles") + joblist += list(ROLE_PAI, ROLE_POSIBRAIN, ROLE_DRONE , ROLE_DEATHSQUAD, ROLE_LAVALAND, ROLE_SENTIENCE) + if("teamantags") + joblist += list(ROLE_OPERATIVE, ROLE_REV, ROLE_CULTIST, ROLE_SERVANT_OF_RATVAR, ROLE_ABDUCTOR, ROLE_ALIEN, ROLE_GANG) + if("convertantags") + joblist += list(ROLE_REV, ROLE_CULTIST, ROLE_SERVANT_OF_RATVAR, ROLE_ALIEN) + if("otherroles") + joblist += list(ROLE_MIND_TRANSFER) + else + joblist += href_list["jobban3"] + + //Create a list of unbanned jobs within joblist + var/list/notbannedlist = list() + for(var/job in joblist) + if(!jobban_isbanned(M, job)) + notbannedlist += job + + //Banning comes first + if(notbannedlist.len) //at least 1 unbanned job exists in joblist so we have stuff to ban. + var/severity = null + switch(alert("Temporary Ban for [M.key]?",,"Yes","No", "Cancel")) + if("Yes") + var/mins = input(usr,"How long (in minutes)?","Ban time",1440) as num|null + if(mins <= 0) + to_chat(usr, "[mins] is not a valid duration.") + return + var/reason = input(usr,"Please State Reason For Banning [M.key].","Reason") as message|null + if(!reason) + return + severity = input("Set the severity of the note/ban.", "Severity", null, null) as null|anything in list("High", "Medium", "Minor", "None") + if(!severity) + return + var/msg + for(var/job in notbannedlist) + if(!DB_ban_record(BANTYPE_JOB_TEMP, M, mins, reason, job)) + to_chat(usr, "Failed to apply ban.") + return + if(M.client) + jobban_buildcache(M.client) + ban_unban_log_save("[key_name(usr)] temp-jobbanned [key_name(M)] from [job] for [mins] minutes. reason: [reason]") + log_admin_private("[key_name(usr)] temp-jobbanned [key_name(M)] from [job] for [mins] minutes.") + if(!msg) + msg = job + else + msg += ", [job]" + create_message("note", M.key, null, "Banned from [msg] - [reason]", null, null, 0, 0, null, 0, severity) + message_admins("[key_name_admin(usr)] banned [key_name_admin(M)] from [msg] for [mins] minutes.") + to_chat(M, "You have been [(msg == ("ooc" || "appearance")) ? "banned" : "jobbanned"] by [usr.client.key] from: [msg].") + to_chat(M, "The reason is: [reason]") + to_chat(M, "This jobban will be lifted in [mins] minutes.") + href_list["jobban2"] = 1 // lets it fall through and refresh + return 1 + if("No") + var/reason = input(usr,"Please State Reason For Banning [M.key].","Reason") as message|null + severity = input("Set the severity of the note/ban.", "Severity", null, null) as null|anything in list("High", "Medium", "Minor", "None") + if(!severity) + return + if(reason) + var/msg + for(var/job in notbannedlist) + if(!DB_ban_record(BANTYPE_JOB_PERMA, M, -1, reason, job)) + to_chat(usr, "Failed to apply ban.") + return + if(M.client) + jobban_buildcache(M.client) + ban_unban_log_save("[key_name(usr)] perma-jobbanned [key_name(M)] from [job]. reason: [reason]") + log_admin_private("[key_name(usr)] perma-banned [key_name(M)] from [job]") + if(!msg) + msg = job + else + msg += ", [job]" + create_message("note", M.key, null, "Banned from [msg] - [reason]", null, null, 0, 0, null, 0, severity) + message_admins("[key_name_admin(usr)] banned [key_name_admin(M)] from [msg].") + to_chat(M, "You have been [(msg == ("ooc" || "appearance")) ? "banned" : "jobbanned"] by [usr.client.key] from: [msg].") + to_chat(M, "The reason is: [reason]") + to_chat(M, "Jobban can be lifted only upon request.") + href_list["jobban2"] = 1 // lets it fall through and refresh + return 1 + if("Cancel") + return + + //Unbanning joblist + //all jobs in joblist are banned already OR we didn't give a reason (implying they shouldn't be banned) + if(joblist.len) //at least 1 banned job exists in joblist so we have stuff to unban. + var/msg + for(var/job in joblist) + var/reason = jobban_isbanned(M, job) + if(!reason) + continue //skip if it isn't jobbanned anyway + switch(alert("Job: '[job]' Reason: '[reason]' Un-jobban?","Please Confirm","Yes","No")) + if("Yes") + ban_unban_log_save("[key_name(usr)] unjobbanned [key_name(M)] from [job]") + log_admin_private("[key_name(usr)] unbanned [key_name(M)] from [job]") + DB_ban_unban(M.ckey, BANTYPE_ANY_JOB, job) + if(M.client) + jobban_buildcache(M.client) + if(!msg) + msg = job + else + msg += ", [job]" + else + continue + if(msg) + message_admins("[key_name_admin(usr)] unbanned [key_name_admin(M)] from [msg].") + to_chat(M, "You have been un-jobbanned by [usr.client.key] from [msg].") + href_list["jobban2"] = 1 // lets it fall through and refresh + return 1 + return 0 //we didn't do anything! + + else if(href_list["boot2"]) + if(!check_rights(R_ADMIN)) + return + var/mob/M = locate(href_list["boot2"]) + if(ismob(M)) + if(!check_if_greater_rights_than(M.client)) + to_chat(usr, "Error: They have more rights than you do.") + return + if(alert(usr, "Kick [key_name(M)]?", "Confirm", "Yes", "No") != "Yes") + return + if(!M) + to_chat(usr, "Error: [M] no longer exists!") + return + if(!M.client) + to_chat(usr, "Error: [M] no longer has a client!") + return + to_chat(M, "You have been kicked from the server by [usr.client.holder.fakekey ? "an Administrator" : "[usr.client.key]"].") + log_admin("[key_name(usr)] kicked [key_name(M)].") + message_admins("[key_name_admin(usr)] kicked [key_name_admin(M)].") + qdel(M.client) + + else if(href_list["addmessage"]) + if(!check_rights(R_ADMIN)) + return + var/target_key = href_list["addmessage"] + create_message("message", target_key, secret = 0) + + else if(href_list["addnote"]) + if(!check_rights(R_ADMIN)) + return + var/target_key = href_list["addnote"] + create_message("note", target_key) + + else if(href_list["addwatch"]) + if(!check_rights(R_ADMIN)) + return + var/target_key = href_list["addwatch"] + create_message("watchlist entry", target_key, secret = 1) + + else if(href_list["addmemo"]) + if(!check_rights(R_ADMIN)) + return + create_message("memo", secret = 0, browse = 1) + + else if(href_list["addmessageempty"]) + if(!check_rights(R_ADMIN)) + return + create_message("message", secret = 0) + + else if(href_list["addnoteempty"]) + if(!check_rights(R_ADMIN)) + return + create_message("note") + + else if(href_list["addwatchempty"]) + if(!check_rights(R_ADMIN)) + return + create_message("watchlist entry", secret = 1) + + else if(href_list["deletemessage"]) + if(!check_rights(R_ADMIN)) + return + var/safety = alert("Delete message/note?",,"Yes","No"); + if (safety == "Yes") + var/message_id = href_list["deletemessage"] + delete_message(message_id) + + else if(href_list["deletemessageempty"]) + if(!check_rights(R_ADMIN)) + return + var/safety = alert("Delete message/note?",,"Yes","No"); + if (safety == "Yes") + var/message_id = href_list["deletemessageempty"] + delete_message(message_id, browse = TRUE) + + else if(href_list["editmessage"]) + if(!check_rights(R_ADMIN)) + return + var/message_id = href_list["editmessage"] + edit_message(message_id) + + else if(href_list["editmessageempty"]) + if(!check_rights(R_ADMIN)) + return + var/message_id = href_list["editmessageempty"] + edit_message(message_id, browse = 1) + + else if(href_list["editmessageexpiry"]) + if(!check_rights(R_ADMIN)) + return + var/message_id = href_list["editmessageexpiry"] + edit_message_expiry(message_id) + + else if(href_list["editmessageexpiryempty"]) + if(!check_rights(R_ADMIN)) + return + var/message_id = href_list["editmessageexpiryempty"] + edit_message_expiry(message_id, browse = 1) + + else if(href_list["editmessageseverity"]) + if(!check_rights(R_ADMIN)) + return + var/message_id = href_list["editmessageseverity"] + edit_message_severity(message_id) + + else if(href_list["secretmessage"]) + if(!check_rights(R_ADMIN)) + return + var/message_id = href_list["secretmessage"] + toggle_message_secrecy(message_id) + + else if(href_list["searchmessages"]) + if(!check_rights(R_ADMIN)) + return + var/target = href_list["searchmessages"] + browse_messages(index = target) + + else if(href_list["nonalpha"]) + if(!check_rights(R_ADMIN)) + return + var/target = href_list["nonalpha"] + target = text2num(target) + browse_messages(index = target) + + else if(href_list["showmessages"]) + if(!check_rights(R_ADMIN)) + return + var/target = href_list["showmessages"] + browse_messages(index = target) + + else if(href_list["showmemo"]) + if(!check_rights(R_ADMIN)) + return + browse_messages("memo") + + else if(href_list["showwatch"]) + if(!check_rights(R_ADMIN)) + return + browse_messages("watchlist entry") + + else if(href_list["showwatchfilter"]) + if(!check_rights(R_ADMIN)) + return + browse_messages("watchlist entry", filter = 1) + + else if(href_list["showmessageckey"]) + if(!check_rights(R_ADMIN)) + return + var/target = href_list["showmessageckey"] + var/agegate = TRUE + if (href_list["showall"]) + agegate = FALSE + browse_messages(target_ckey = target, agegate = agegate) + + else if(href_list["showmessageckeylinkless"]) + var/target = href_list["showmessageckeylinkless"] + browse_messages(target_ckey = target, linkless = 1) + + else if(href_list["messageedits"]) + if(!check_rights(R_ADMIN)) + return + var/message_id = sanitizeSQL("[href_list["messageedits"]]") + var/datum/DBQuery/query_get_message_edits = SSdbcore.NewQuery("SELECT edits FROM [format_table_name("messages")] WHERE id = '[message_id]'") + if(!query_get_message_edits.warn_execute()) + qdel(query_get_message_edits) + return + if(query_get_message_edits.NextRow()) + var/edit_log = query_get_message_edits.item[1] + if(!QDELETED(usr)) + var/datum/browser/browser = new(usr, "Note edits", "Note edits") + browser.set_content(jointext(edit_log, "")) + browser.open() + qdel(query_get_message_edits) + + else if(href_list["newban"]) + if(!check_rights(R_BAN)) + return + + var/mob/M = locate(href_list["newban"]) + if(!ismob(M)) + return + + if(M.client && M.client.holder) + return //admins cannot be banned. Even if they could, the ban doesn't affect them anyway + + switch(alert("Temporary Ban for [M.key]?",,"Yes","No", "Cancel")) + if("Yes") + var/mins = input(usr,"How long (in minutes)?","Ban time",1440) as num|null + if(mins <= 0) + to_chat(usr, "[mins] is not a valid duration.") + return + var/reason = input(usr,"Please State Reason For Banning [M.key].","Reason") as message|null + if(!reason) + return + if(!DB_ban_record(BANTYPE_TEMP, M, mins, reason)) + to_chat(usr, "Failed to apply ban.") + return + AddBan(M.ckey, M.computer_id, reason, usr.ckey, 1, mins) + ban_unban_log_save("[key_name(usr)] has banned [key_name(M)]. - Reason: [reason] - This will be removed in [mins] minutes.") + to_chat(M, "You have been banned by [usr.client.key].\nReason: [reason]") + to_chat(M, "This is a temporary ban, it will be removed in [mins] minutes. The round ID is [GLOB.round_id].") + var/bran = CONFIG_GET(string/banappeals) + if(bran) + to_chat(M, "To try to resolve this matter head to [bran]") + else + to_chat(M, "No ban appeals URL has been set.") + log_admin_private("[key_name(usr)] has banned [key_name(M)].\nReason: [key_name(M)]\nThis will be removed in [mins] minutes.") + var/msg = "[key_name_admin(usr)] has banned [key_name_admin(M)].\nReason: [reason]\nThis will be removed in [mins] minutes." + message_admins(msg) + var/datum/admin_help/AH = M.client ? M.client.current_ticket : null + if(AH) + AH.Resolve() + qdel(M.client) + if("No") + var/reason = input(usr,"Please State Reason For Banning [M.key].","Reason") as message|null + if(!reason) + return + switch(alert(usr,"IP ban?",,"Yes","No","Cancel")) + if("Cancel") + return + if("Yes") + AddBan(M.ckey, M.computer_id, reason, usr.ckey, 0, 0, M.lastKnownIP) + if("No") + AddBan(M.ckey, M.computer_id, reason, usr.ckey, 0, 0) + to_chat(M, "You have been banned by [usr.client.key].\nReason: [reason]") + to_chat(M, "This is a permanent ban. The round ID is [GLOB.round_id].") + var/bran = CONFIG_GET(string/banappeals) + if(bran) + to_chat(M, "To try to resolve this matter head to [bran]") + else + to_chat(M, "No ban appeals URL has been set.") + if(!DB_ban_record(BANTYPE_PERMA, M, -1, reason)) + to_chat(usr, "Failed to apply ban.") + return + ban_unban_log_save("[key_name(usr)] has permabanned [key_name(M)]. - Reason: [reason] - This is a permanent ban.") + log_admin_private("[key_name(usr)] has banned [key_name(M)].\nReason: [reason]\nThis is a permanent ban.") + var/msg = "[key_name_admin(usr)] has banned [key_name_admin(M)].\nReason: [reason]\nThis is a permanent ban." + message_admins(msg) + var/datum/admin_help/AH = M.client ? M.client.current_ticket : null + if(AH) + AH.Resolve() + qdel(M.client) + if("Cancel") + return + + else if(href_list["mute"]) + if(!check_rights(R_ADMIN)) + return + cmd_admin_mute(href_list["mute"], text2num(href_list["mute_type"])) + + else if(href_list["c_mode"]) + return HandleCMode() + + else if(href_list["f_secret"]) + return HandleFSecret() + +//Dynamic mode + else if(href_list["f_dynamic_roundstart"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode.", null, null, null, null) + var/roundstart_rules = list() + for (var/rule in subtypesof(/datum/dynamic_ruleset/roundstart)) + var/datum/dynamic_ruleset/roundstart/newrule = new rule() + roundstart_rules[newrule.name] = newrule + var/added_rule = input(usr,"What ruleset do you want to force? This will bypass threat level and population restrictions.", "Rigging Roundstart", null) as null|anything in roundstart_rules + if (added_rule) + GLOB.dynamic_forced_roundstart_ruleset += roundstart_rules[added_rule] + log_admin("[key_name(usr)] set [added_rule] to be a forced roundstart ruleset.") + message_admins("[key_name(usr)] set [added_rule] to be a forced roundstart ruleset.", 1) + Game() + + else if(href_list["f_dynamic_roundstart_clear"]) + if(!check_rights(R_ADMIN)) + return + GLOB.dynamic_forced_roundstart_ruleset = list() + Game() + log_admin("[key_name(usr)] cleared the rigged roundstart rulesets. The mode will pick them as normal.") + message_admins("[key_name(usr)] cleared the rigged roundstart rulesets. The mode will pick them as normal.", 1) + + else if(href_list["f_dynamic_roundstart_remove"]) + if(!check_rights(R_ADMIN)) + return + var/datum/dynamic_ruleset/roundstart/rule = locate(href_list["f_dynamic_roundstart_remove"]) + GLOB.dynamic_forced_roundstart_ruleset -= rule + Game() + log_admin("[key_name(usr)] removed [rule] from the forced roundstart rulesets.") + message_admins("[key_name(usr)] removed [rule] from the forced roundstart rulesets.", 1) + + else if(href_list["f_dynamic_latejoin"]) + if(!check_rights(R_ADMIN)) + return + if(!SSticker || !SSticker.mode) + return alert(usr, "The game must start first.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + var/latejoin_rules = list() + for (var/rule in subtypesof(/datum/dynamic_ruleset/latejoin)) + var/datum/dynamic_ruleset/latejoin/newrule = new rule() + latejoin_rules[newrule.name] = newrule + var/added_rule = input(usr,"What ruleset do you want to force upon the next latejoiner? This will bypass threat level and population restrictions.", "Rigging Latejoin", null) as null|anything in latejoin_rules + if (added_rule) + var/datum/game_mode/dynamic/mode = SSticker.mode + mode.forced_latejoin_rule = latejoin_rules[added_rule] + log_admin("[key_name(usr)] set [added_rule] to proc on the next latejoin.") + message_admins("[key_name(usr)] set [added_rule] to proc on the next latejoin.", 1) + Game() + + else if(href_list["f_dynamic_latejoin_clear"]) + if(!check_rights(R_ADMIN)) + return + if (SSticker && SSticker.mode && istype(SSticker.mode,/datum/game_mode/dynamic)) + var/datum/game_mode/dynamic/mode = SSticker.mode + mode.forced_latejoin_rule = null + Game() + log_admin("[key_name(usr)] cleared the forced latejoin ruleset.") + message_admins("[key_name(usr)] cleared the forced latejoin ruleset.", 1) + + else if(href_list["f_dynamic_midround"]) + if(!check_rights(R_ADMIN)) + return + if(!SSticker || !SSticker.mode) + return alert(usr, "The game must start first.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + var/midround_rules = list() + for (var/rule in subtypesof(/datum/dynamic_ruleset/midround)) + var/datum/dynamic_ruleset/midround/newrule = new rule() + midround_rules[newrule.name] = rule + var/added_rule = input(usr,"What ruleset do you want to force right now? This will bypass threat level and population restrictions.", "Execute Ruleset", null) as null|anything in midround_rules + if (added_rule) + var/datum/game_mode/dynamic/mode = SSticker.mode + log_admin("[key_name(usr)] executed the [added_rule] ruleset.") + message_admins("[key_name(usr)] executed the [added_rule] ruleset.", 1) + mode.picking_specific_rule(midround_rules[added_rule],1) + + else if (href_list["f_dynamic_options"]) + if(!check_rights(R_ADMIN)) + return + + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_roundstart_centre"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + var/new_centre = input(usr,"Change the centre of the dynamic mode threat curve. A negative value will give a more peaceful round ; a positive value, a round with higher threat. Any number between -5 and +5 is allowed.", "Change curve centre", null) as num + if (new_centre < -5 || new_centre > 5) + return alert(usr, "Only values between -5 and +5 are allowed.", null, null, null, null) + + log_admin("[key_name(usr)] changed the distribution curve center to [new_centre].") + message_admins("[key_name(usr)] changed the distribution curve center to [new_centre]", 1) + GLOB.dynamic_curve_centre = new_centre + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_roundstart_width"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + var/new_width = input(usr,"Change the width of the dynamic mode threat curve. A higher value will favour extreme rounds ; a lower value, a round closer to the average. Any Number between 0.5 and 4 are allowed.", "Change curve width", null) as num + if (new_width < 0.5 || new_width > 4) + return alert(usr, "Only values between 0.5 and +2.5 are allowed.", null, null, null, null) + + log_admin("[key_name(usr)] changed the distribution curve width to [new_width].") + message_admins("[key_name(usr)] changed the distribution curve width to [new_width]", 1) + GLOB.dynamic_curve_width = new_width + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_roundstart_latejoin_min"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + var/new_min = input(usr,"Change the minimum delay of latejoin injection in minutes.", "Change latejoin injection delay minimum", null) as num + if(new_min <= 0) + return alert(usr, "The minimum can't be zero or lower.", null, null, null, null) + if((new_min MINUTES) > GLOB.dynamic_latejoin_delay_max) + return alert(usr, "The minimum must be lower than the maximum.", null, null, null, null) + + log_admin("[key_name(usr)] changed the latejoin injection minimum delay to [new_min] minutes.") + message_admins("[key_name(usr)] changed the latejoin injection minimum delay to [new_min] minutes", 1) + GLOB.dynamic_latejoin_delay_min = (new_min MINUTES) + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_roundstart_latejoin_max"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + var/new_max = input(usr,"Change the maximum delay of latejoin injection in minutes.", "Change latejoin injection delay maximum", null) as num + if(new_max <= 0) + return alert(usr, "The maximum can't be zero or lower.", null, null, null, null) + if((new_max MINUTES) < GLOB.dynamic_latejoin_delay_min) + return alert(usr, "The maximum must be higher than the minimum.", null, null, null, null) + + log_admin("[key_name(usr)] changed the latejoin injection maximum delay to [new_max] minutes.") + message_admins("[key_name(usr)] changed the latejoin injection maximum delay to [new_max] minutes", 1) + GLOB.dynamic_latejoin_delay_max = (new_max MINUTES) + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_roundstart_midround_min"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + var/new_min = input(usr,"Change the minimum delay of midround injection in minutes.", "Change midround injection delay minimum", null) as num + if(new_min <= 0) + return alert(usr, "The minimum can't be zero or lower.", null, null, null, null) + if((new_min MINUTES) > GLOB.dynamic_midround_delay_max) + return alert(usr, "The minimum must be lower than the maximum.", null, null, null, null) + + log_admin("[key_name(usr)] changed the midround injection minimum delay to [new_min] minutes.") + message_admins("[key_name(usr)] changed the midround injection minimum delay to [new_min] minutes", 1) + GLOB.dynamic_midround_delay_min = (new_min MINUTES) + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_roundstart_midround_max"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + var/new_max = input(usr,"Change the maximum delay of midround injection in minutes.", "Change midround injection delay maximum", null) as num + if(new_max <= 0) + return alert(usr, "The maximum can't be zero or lower.", null, null, null, null) + if((new_max MINUTES) > GLOB.dynamic_midround_delay_max) + return alert(usr, "The maximum must be higher than the minimum.", null, null, null, null) + + log_admin("[key_name(usr)] changed the midround injection maximum delay to [new_max] minutes.") + message_admins("[key_name(usr)] changed the midround injection maximum delay to [new_max] minutes", 1) + GLOB.dynamic_midround_delay_max = (new_max MINUTES) + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_force_extended"]) + if(!check_rights(R_ADMIN)) + return + + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + GLOB.dynamic_forced_extended = !GLOB.dynamic_forced_extended + log_admin("[key_name(usr)] set 'forced_extended' to [GLOB.dynamic_forced_extended].") + message_admins("[key_name(usr)] set 'forced_extended' to [GLOB.dynamic_forced_extended].") + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_no_stacking"]) + if(!check_rights(R_ADMIN)) + return + + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + GLOB.dynamic_no_stacking = !GLOB.dynamic_no_stacking + log_admin("[key_name(usr)] set 'no_stacking' to [GLOB.dynamic_no_stacking].") + message_admins("[key_name(usr)] set 'no_stacking' to [GLOB.dynamic_no_stacking].") + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_classic_secret"]) + if(!check_rights(R_ADMIN)) + return + + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + GLOB.dynamic_classic_secret = !GLOB.dynamic_classic_secret + log_admin("[key_name(usr)] set 'classic_secret' to [GLOB.dynamic_classic_secret].") + message_admins("[key_name(usr)] set 'classic_secret' to [GLOB.dynamic_classic_secret].") + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_stacking_limit"]) + if(!check_rights(R_ADMIN)) + return + + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + GLOB.dynamic_stacking_limit = input(usr,"Change the threat limit at which round-endings rulesets will start to stack.", "Change stacking limit", null) as num + log_admin("[key_name(usr)] set 'stacking_limit' to [GLOB.dynamic_stacking_limit].") + message_admins("[key_name(usr)] set 'stacking_limit' to [GLOB.dynamic_stacking_limit].") + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_high_pop_limit"]) + if(!check_rights(R_ADMIN)) + return + + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + var/new_value = input(usr, "Enter the high-pop override threshold for dynamic mode.", "High pop override") as num + if (new_value < 0) + return alert(usr, "Only positive values allowed!", null, null, null, null) + GLOB.dynamic_high_pop_limit = new_value + + log_admin("[key_name(usr)] set 'high_pop_limit' to [GLOB.dynamic_high_pop_limit].") + message_admins("[key_name(usr)] set 'high_pop_limit' to [GLOB.dynamic_high_pop_limit].") + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_forced_threat"]) + if(!check_rights(R_ADMIN)) + return + + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + var/new_value = input(usr, "Enter the forced threat level for dynamic mode.", "Forced threat level") as num + if (new_value > 100) + return alert(usr, "The value must be be under 100.", null, null, null, null) + GLOB.dynamic_forced_threat_level = new_value + + log_admin("[key_name(usr)] set 'forced_threat_level' to [GLOB.dynamic_forced_threat_level].") + message_admins("[key_name(usr)] set 'forced_threat_level' to [GLOB.dynamic_forced_threat_level].") + dynamic_mode_options(usr) + + else if(href_list["f_dynamic_chaos_level"]) + if(!check_rights(R_ADMIN)) + return + + if(SSticker && SSticker.mode) + return alert(usr, "The game has already started.", null, null, null, null) + + if(GLOB.master_mode != "dynamic") + return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null) + + var/new_value = input(usr, "Enter the chaos level for dynamic mode.", "Chaos level") as num + if (new_value > 5 || new_value < 0) + return alert(usr, "The value must be between 0 and 5.", null, null, null, null) + GLOB.dynamic_chaos_level = new_value + + log_admin("[key_name(usr)] set 'dynamic_chaos_level' to [GLOB.dynamic_chaos_level].") + message_admins("[key_name(usr)] set 'dynamic_chaos_level' to [GLOB.dynamic_chaos_level].") + dynamic_mode_options(usr) +//End Dynamic mode + + else if(href_list["c_mode2"]) + if(!check_rights(R_ADMIN|R_SERVER)) + return + + if (SSticker.HasRoundStarted()) + return alert(usr, "The game has already started.", null, null, null, null) + GLOB.master_mode = href_list["c_mode2"] + log_admin("[key_name(usr)] set the mode as [GLOB.master_mode].") + message_admins("[key_name_admin(usr)] set the mode as [GLOB.master_mode].") + to_chat(world, "The mode is now: [GLOB.master_mode]") + Game() // updates the main game menu + SSticker.save_mode(GLOB.master_mode) + HandleCMode() + + else if(href_list["f_secret2"]) + if(!check_rights(R_ADMIN|R_SERVER)) + return + + if(SSticker.HasRoundStarted()) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "secret") + return alert(usr, "The game mode has to be secret!", null, null, null, null) + GLOB.secret_force_mode = href_list["f_secret2"] + log_admin("[key_name(usr)] set the forced secret mode as [GLOB.secret_force_mode].") + message_admins("[key_name_admin(usr)] set the forced secret mode as [GLOB.secret_force_mode].") + Game() // updates the main game menu + HandleFSecret() + + else if(href_list["monkeyone"]) + if(!check_rights(R_SPAWN)) + return + + var/mob/living/carbon/human/H = locate(href_list["monkeyone"]) + if(!istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.") + return + + log_admin("[key_name(usr)] attempting to monkeyize [key_name(H)].") + message_admins("[key_name_admin(usr)] attempting to monkeyize [key_name_admin(H)].") + H.monkeyize() + + else if(href_list["humanone"]) + if(!check_rights(R_SPAWN)) + return + + var/mob/living/carbon/monkey/Mo = locate(href_list["humanone"]) + if(!istype(Mo)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/monkey.") + return + + log_admin("[key_name(usr)] attempting to humanize [key_name(Mo)].") + message_admins("[key_name_admin(usr)] attempting to humanize [key_name_admin(Mo)].") + Mo.humanize() + + else if(href_list["corgione"]) + if(!check_rights(R_SPAWN)) + return + + var/mob/living/carbon/human/H = locate(href_list["corgione"]) + if(!istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.") + return + + log_admin("[key_name(usr)] attempting to corgize [key_name(H)].") + message_admins("[key_name_admin(usr)] attempting to corgize [key_name_admin(H)].") + H.corgize() + + + else if(href_list["forcespeech"]) + if(!check_rights(R_FUN)) + return + + var/mob/M = locate(href_list["forcespeech"]) + if(!ismob(M)) + to_chat(usr, "this can only be used on instances of type /mob.") + + var/speech = input("What will [key_name(M)] say?", "Force speech", "")// Don't need to sanitize, since it does that in say(), we also trust our admins. + if(!speech) + return + M.say(speech, forced = "admin speech") + speech = sanitize(speech) // Nah, we don't trust them + log_admin("[key_name(usr)] forced [key_name(M)] to say: [speech]") + message_admins("[key_name_admin(usr)] forced [key_name_admin(M)] to say: [speech]") + + else if(href_list["makeeligible"]) + if(!check_rights(R_ADMIN)) + return + var/mob/M = locate(href_list["makeeligible"]) + if(!ismob(M)) + to_chat(usr, "this can only be used on instances of type /mob.") + if(M.ckey in GLOB.client_ghost_timeouts) + GLOB.client_ghost_timeouts -= M.ckey + + else if(href_list["sendtoprison"]) + if(!check_rights(R_ADMIN)) + return + + var/mob/M = locate(href_list["sendtoprison"]) + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob.") + return + if(isAI(M)) + to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai.") + return + + if(alert(usr, "Send [key_name(M)] to Prison?", "Message", "Yes", "No") != "Yes") + return + + M.forceMove(pick(GLOB.prisonwarp)) + to_chat(M, "You have been sent to Prison!") + + log_admin("[key_name(usr)] has sent [key_name(M)] to Prison!") + message_admins("[key_name_admin(usr)] has sent [key_name_admin(M)] to Prison!") + + else if(href_list["sendbacktolobby"]) + if(!check_rights(R_ADMIN)) + return + + var/mob/M = locate(href_list["sendbacktolobby"]) + + if(!isobserver(M)) + to_chat(usr, "You can only send ghost players back to the Lobby.") + return + + if(!M.client) + to_chat(usr, "[M] doesn't seem to have an active client.") + return + + if(alert(usr, "Send [key_name(M)] back to Lobby?", "Message", "Yes", "No") != "Yes") + return + + log_admin("[key_name(usr)] has sent [key_name(M)] back to the Lobby.") + message_admins("[key_name(usr)] has sent [key_name(M)] back to the Lobby.") + + var/mob/dead/new_player/NP = new() + NP.ckey = M.ckey + qdel(M) + + else if(href_list["tdome1"]) + if(!check_rights(R_FUN)) + return + + if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") + return + + var/mob/M = locate(href_list["tdome1"]) + if(!isliving(M)) + to_chat(usr, "This can only be used on instances of type /mob/living.") + return + if(isAI(M)) + to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai.") + return + var/mob/living/L = M + + for(var/obj/item/I in L) + L.dropItemToGround(I, TRUE) + + L.Unconscious(100) + sleep(5) + L.forceMove(pick(GLOB.tdome1)) + spawn(50) + to_chat(L, "You have been sent to the Thunderdome.") + log_admin("[key_name(usr)] has sent [key_name(L)] to the thunderdome. (Team 1)") + message_admins("[key_name_admin(usr)] has sent [key_name_admin(L)] to the thunderdome. (Team 1)") + + else if(href_list["tdome2"]) + if(!check_rights(R_FUN)) + return + + if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") + return + + var/mob/M = locate(href_list["tdome2"]) + if(!isliving(M)) + to_chat(usr, "This can only be used on instances of type /mob/living.") + return + if(isAI(M)) + to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai.") + return + var/mob/living/L = M + + for(var/obj/item/I in L) + L.dropItemToGround(I, TRUE) + + L.Unconscious(100) + sleep(5) + L.forceMove(pick(GLOB.tdome2)) + spawn(50) + to_chat(L, "You have been sent to the Thunderdome.") + log_admin("[key_name(usr)] has sent [key_name(L)] to the thunderdome. (Team 2)") + message_admins("[key_name_admin(usr)] has sent [key_name_admin(L)] to the thunderdome. (Team 2)") + + else if(href_list["tdomeadmin"]) + if(!check_rights(R_FUN)) + return + + if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") + return + + var/mob/M = locate(href_list["tdomeadmin"]) + if(!isliving(M)) + to_chat(usr, "This can only be used on instances of type /mob/living.") + return + if(isAI(M)) + to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai.") + return + var/mob/living/L = M + + L.Unconscious(100) + sleep(5) + L.forceMove(pick(GLOB.tdomeadmin)) + spawn(50) + to_chat(L, "You have been sent to the Thunderdome.") + log_admin("[key_name(usr)] has sent [key_name(L)] to the thunderdome. (Admin.)") + message_admins("[key_name_admin(usr)] has sent [key_name_admin(L)] to the thunderdome. (Admin.)") + + else if(href_list["tdomeobserve"]) + if(!check_rights(R_FUN)) + return + + if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") + return + + var/mob/M = locate(href_list["tdomeobserve"]) + if(!isliving(M)) + to_chat(usr, "This can only be used on instances of type /mob/living.") + return + if(isAI(M)) + to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai.") + return + var/mob/living/L = M + + for(var/obj/item/I in L) + L.dropItemToGround(I, TRUE) + + if(ishuman(L)) + var/mob/living/carbon/human/observer = L + observer.equip_to_slot_or_del(new /obj/item/clothing/under/suit_jacket(observer), SLOT_W_UNIFORM) + observer.equip_to_slot_or_del(new /obj/item/clothing/shoes/sneakers/black(observer), SLOT_SHOES) + L.Unconscious(100) + sleep(5) + L.forceMove(pick(GLOB.tdomeobserve)) + spawn(50) + to_chat(L, "You have been sent to the Thunderdome.") + log_admin("[key_name(usr)] has sent [key_name(L)] to the thunderdome. (Observer.)") + message_admins("[key_name_admin(usr)] has sent [key_name_admin(L)] to the thunderdome. (Observer.)") + + else if(href_list["revive"]) + if(!check_rights(R_ADMIN)) + return + + var/mob/living/L = locate(href_list["revive"]) + if(!istype(L)) + to_chat(usr, "This can only be used on instances of type /mob/living.") + return + + L.revive(full_heal = 1, admin_revive = 1) + message_admins("Admin [key_name_admin(usr)] healed / revived [key_name_admin(L)]!") + log_admin("[key_name(usr)] healed / Revived [key_name(L)].") + + else if(href_list["makeai"]) + if(!check_rights(R_SPAWN)) + return + + var/mob/living/carbon/human/H = locate(href_list["makeai"]) + if(!istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.") + return + + message_admins("Admin [key_name_admin(usr)] AIized [key_name_admin(H)]!") + log_admin("[key_name(usr)] AIized [key_name(H)].") + H.AIize() + + else if(href_list["makealien"]) + if(!check_rights(R_SPAWN)) + return + + var/mob/living/carbon/human/H = locate(href_list["makealien"]) + if(!istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.") + return + + usr.client.cmd_admin_alienize(H) + + else if(href_list["makeslime"]) + if(!check_rights(R_SPAWN)) + return + + var/mob/living/carbon/human/H = locate(href_list["makeslime"]) + if(!istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.") + return + + usr.client.cmd_admin_slimeize(H) + + else if(href_list["makeblob"]) + if(!check_rights(R_SPAWN)) + return + + var/mob/living/carbon/human/H = locate(href_list["makeblob"]) + if(!istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.") + return + + usr.client.cmd_admin_blobize(H) + + + else if(href_list["makerobot"]) + if(!check_rights(R_SPAWN)) + return + + var/mob/living/carbon/human/H = locate(href_list["makerobot"]) + if(!istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.") + return + + usr.client.cmd_admin_robotize(H) + + else if(href_list["makeanimal"]) + if(!check_rights(R_SPAWN)) + return + + var/mob/M = locate(href_list["makeanimal"]) + if(isnewplayer(M)) + to_chat(usr, "This cannot be used on instances of type /mob/dead/new_player.") + return + + usr.client.cmd_admin_animalize(M) + + else if(href_list["adminplayeropts"]) + var/mob/M = locate(href_list["adminplayeropts"]) + show_player_panel(M) + + else if(href_list["adminplayerobservefollow"]) + if(!isobserver(usr) && !check_rights(R_ADMIN)) + return + + var/atom/movable/AM = locate(href_list["adminplayerobservefollow"]) + + var/client/C = usr.client + if(!isobserver(usr)) + C.admin_ghost() + var/mob/dead/observer/A = C.mob + A.ManualFollow(AM) + + else if(href_list["admingetmovable"]) + if(!check_rights(R_ADMIN)) + return + + var/atom/movable/AM = locate(href_list["admingetmovable"]) + if(QDELETED(AM)) + return + AM.forceMove(get_turf(usr)) + + else if(href_list["adminplayerobservecoodjump"]) + if(!isobserver(usr) && !check_rights(R_ADMIN)) + return + + var/x = text2num(href_list["X"]) + var/y = text2num(href_list["Y"]) + var/z = text2num(href_list["Z"]) + + var/client/C = usr.client + if(!isobserver(usr)) + C.admin_ghost() + sleep(2) + C.jumptocoord(x,y,z) + + else if(href_list["adminchecklaws"]) + if(!check_rights(R_ADMIN)) + return + output_ai_laws() + + else if(href_list["admincheckdevilinfo"]) + if(!check_rights(R_ADMIN)) + return + var/mob/M = locate(href_list["admincheckdevilinfo"]) + output_devil_info(M) + + else if(href_list["adminmoreinfo"]) + var/mob/M = locate(href_list["adminmoreinfo"]) in GLOB.mob_list + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob.") + return + + var/location_description = "" + var/special_role_description = "" + var/health_description = "" + var/gender_description = "" + var/turf/T = get_turf(M) + + //Location + if(isturf(T)) + if(isarea(T.loc)) + location_description = "([M.loc == T ? "at coordinates " : "in [M.loc] at coordinates "] [T.x], [T.y], [T.z] in area [T.loc])" + else + location_description = "([M.loc == T ? "at coordinates " : "in [M.loc] at coordinates "] [T.x], [T.y], [T.z])" + + //Job + antagonist + if(M.mind) + special_role_description = "Role: [M.mind.assigned_role]; Antagonist: [M.mind.special_role]" + else + special_role_description = "Role: Mind datum missing Antagonist: Mind datum missing" + + //Health + if(isliving(M)) + var/mob/living/L = M + var/status + switch (M.stat) + if(CONSCIOUS) + status = "Alive" + if(SOFT_CRIT) + status = "Dying" + if(UNCONSCIOUS) + status = "[L.InCritical() ? "Unconscious and Dying" : "Unconscious"]" + if(DEAD) + status = "Dead" + health_description = "Status = [status]" + health_description += "
Oxy: [L.getOxyLoss()] - Tox: [L.getToxLoss()] - Fire: [L.getFireLoss()] - Brute: [L.getBruteLoss()] - Clone: [L.getCloneLoss()] - Brain: [L.getOrganLoss(ORGAN_SLOT_BRAIN)] - Stamina: [L.getStaminaLoss()]" + else + health_description = "This mob type has no health to speak of." + + //Gender + switch(M.gender) + if(MALE,FEMALE) + gender_description = "[M.gender]" + else + gender_description = "[M.gender]" + + to_chat(src.owner, "Info about [M.name]: ") + to_chat(src.owner, "Mob type = [M.type]; Gender = [gender_description] Damage = [health_description]") + to_chat(src.owner, "Name = [M.name]; Real_name = [M.real_name]; Mind_name = [M.mind?"[M.mind.name]":""]; Key = [M.key];") + to_chat(src.owner, "Location = [location_description];") + to_chat(src.owner, "[special_role_description]") + to_chat(src.owner, ADMIN_FULLMONTY_NONAME(M)) + + else if(href_list["addjobslot"]) + if(!check_rights(R_ADMIN)) + return + + var/Add = href_list["addjobslot"] + + for(var/datum/job/job in SSjob.occupations) + if(job.title == Add) + job.total_positions += 1 + break + + src.manage_free_slots() + + + else if(href_list["customjobslot"]) + if(!check_rights(R_ADMIN)) + return + + var/Add = href_list["customjobslot"] + + for(var/datum/job/job in SSjob.occupations) + if(job.title == Add) + var/newtime = null + newtime = input(usr, "How many jebs do you want?", "Add wanted posters", "[newtime]") as num|null + if(!newtime) + to_chat(src.owner, "Setting to amount of positions filled for the job") + job.total_positions = job.current_positions + break + job.total_positions = newtime + + src.manage_free_slots() + + else if(href_list["removejobslot"]) + if(!check_rights(R_ADMIN)) + return + + var/Remove = href_list["removejobslot"] + + for(var/datum/job/job in SSjob.occupations) + if(job.title == Remove && job.total_positions - job.current_positions > 0) + job.total_positions -= 1 + break + + src.manage_free_slots() + + else if(href_list["unlimitjobslot"]) + if(!check_rights(R_ADMIN)) + return + + var/Unlimit = href_list["unlimitjobslot"] + + for(var/datum/job/job in SSjob.occupations) + if(job.title == Unlimit) + job.total_positions = -1 + break + + src.manage_free_slots() + + else if(href_list["limitjobslot"]) + if(!check_rights(R_ADMIN)) + return + + var/Limit = href_list["limitjobslot"] + + for(var/datum/job/job in SSjob.occupations) + if(job.title == Limit) + job.total_positions = job.current_positions + break + + src.manage_free_slots() + + + else if(href_list["adminspawncookie"]) + if(!check_rights(R_ADMIN|R_FUN)) + return + + var/mob/living/carbon/human/H = locate(href_list["adminspawncookie"]) + if(!ishuman(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.") + return + + var/obj/item/reagent_containers/food/snacks/cookie/cookie = new(H) + if(H.put_in_hands(cookie)) + H.update_inv_hands() + else + qdel(cookie) + log_admin("[key_name(H)] has their hands full, so they did not receive their cookie, spawned by [key_name(src.owner)].") + message_admins("[key_name(H)] has their hands full, so they did not receive their cookie, spawned by [key_name(src.owner)].") + return + + log_admin("[key_name(H)] got their cookie, spawned by [key_name(src.owner)].") + message_admins("[key_name(H)] got their cookie, spawned by [key_name(src.owner)].") + SSblackbox.record_feedback("amount", "admin_cookies_spawned", 1) + to_chat(H, "Your prayers have been answered!! You received the best cookie!") + SEND_SOUND(H, sound('sound/effects/pray_chaplain.ogg')) + + else if(href_list["adminsmite"]) + if(!check_rights(R_ADMIN|R_FUN)) + return + + var/mob/living/carbon/human/H = locate(href_list["adminsmite"]) in GLOB.mob_list + if(!H || !istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + return + + usr.client.smite(H) + + else if(href_list["CentComReply"]) + if(!check_rights(R_ADMIN)) + return + + var/mob/M = locate(href_list["CentComReply"]) + usr.client.admin_headset_message(M, RADIO_CHANNEL_CENTCOM) + + else if(href_list["SyndicateReply"]) + if(!check_rights(R_ADMIN)) + return + + var/mob/M = locate(href_list["SyndicateReply"]) + usr.client.admin_headset_message(M, RADIO_CHANNEL_SYNDICATE) + + else if(href_list["HeadsetMessage"]) + if(!check_rights(R_ADMIN)) + return + + var/mob/M = locate(href_list["HeadsetMessage"]) + usr.client.admin_headset_message(M) + + else if(href_list["reject_custom_name"]) + if(!check_rights(R_ADMIN)) + return + var/obj/item/station_charter/charter = locate(href_list["reject_custom_name"]) + if(istype(charter)) + charter.reject_proposed(usr) + else if(href_list["jumpto"]) + if(!isobserver(usr) && !check_rights(R_ADMIN)) + return + + var/mob/M = locate(href_list["jumpto"]) + usr.client.jumptomob(M) + + else if(href_list["getmob"]) + if(!check_rights(R_ADMIN)) + return + + if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") + return + var/mob/M = locate(href_list["getmob"]) + usr.client.Getmob(M) + + else if(href_list["sendmob"]) + if(!check_rights(R_ADMIN)) + return + + var/mob/M = locate(href_list["sendmob"]) + usr.client.sendmob(M) + + else if(href_list["narrateto"]) + if(!check_rights(R_ADMIN)) + return + + var/mob/M = locate(href_list["narrateto"]) + usr.client.cmd_admin_direct_narrate(M) + + else if(href_list["subtlemessage"]) + if(!check_rights(R_ADMIN)) + return + + var/mob/M = locate(href_list["subtlemessage"]) + usr.client.cmd_admin_subtle_message(M) + + else if(href_list["individuallog"]) + if(!check_rights(R_ADMIN)) + return + + var/mob/M = locate(href_list["individuallog"]) in GLOB.mob_list + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob.") + return + + show_individual_logging_panel(M, href_list["log_src"], href_list["log_type"]) + else if(href_list["languagemenu"]) + if(!check_rights(R_ADMIN)) + return + + var/mob/M = locate(href_list["languagemenu"]) in GLOB.mob_list + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob.") + return + var/datum/language_holder/H = M.get_language_holder() + H.open_language_menu(usr) + + else if(href_list["traitor"]) + if(!check_rights(R_ADMIN)) + return + + if(!SSticker.HasRoundStarted()) + alert("The game hasn't started yet!") + return + + var/mob/M = locate(href_list["traitor"]) + if(!ismob(M)) + var/datum/mind/D = M + if(!istype(D)) + to_chat(usr, "This can only be used on instances of type /mob and /mind") + return + else + D.traitor_panel() + else + show_traitor_panel(M) + + else if(href_list["borgpanel"]) + if(!check_rights(R_ADMIN)) + return + + var/mob/M = locate(href_list["borgpanel"]) + if(!iscyborg(M)) + to_chat(usr, "This can only be used on cyborgs") + else + open_borgopanel(M) + + else if(href_list["initmind"]) + if(!check_rights(R_ADMIN)) + return + var/mob/M = locate(href_list["initmind"]) + if(!ismob(M) || M.mind) + to_chat(usr, "This can only be used on instances on mindless mobs") + return + M.mind_initialize() + + else if(href_list["create_object"]) + if(!check_rights(R_SPAWN)) + return + return create_object(usr) + + else if(href_list["quick_create_object"]) + if(!check_rights(R_SPAWN)) + return + return quick_create_object(usr) + + else if(href_list["create_turf"]) + if(!check_rights(R_SPAWN)) + return + return create_turf(usr) + + else if(href_list["create_mob"]) + if(!check_rights(R_SPAWN)) + return + return create_mob(usr) + + else if(href_list["dupe_marked_datum"]) + if(!check_rights(R_SPAWN)) + return + return DuplicateObject(marked_datum, perfectcopy=1, newloc=get_turf(usr)) + + else if(href_list["object_list"]) //this is the laggiest thing ever + if(!check_rights(R_SPAWN)) + return + + var/atom/loc = usr.loc + + var/dirty_paths + if (istext(href_list["object_list"])) + dirty_paths = list(href_list["object_list"]) + else if (istype(href_list["object_list"], /list)) + dirty_paths = href_list["object_list"] + + var/paths = list() + + for(var/dirty_path in dirty_paths) + var/path = text2path(dirty_path) + if(!path) + continue + else if(!ispath(path, /obj) && !ispath(path, /turf) && !ispath(path, /mob)) + continue + paths += path + + if(!paths) + alert("The path list you sent is empty.") + return + if(length(paths) > 5) + alert("Select fewer object types, (max 5).") + return + + var/list/offset = splittext(href_list["offset"],",") + var/number = CLAMP(text2num(href_list["object_count"]), 1, 100) + var/X = offset.len > 0 ? text2num(offset[1]) : 0 + var/Y = offset.len > 1 ? text2num(offset[2]) : 0 + var/Z = offset.len > 2 ? text2num(offset[3]) : 0 + var/obj_dir = text2num(href_list["object_dir"]) + if(obj_dir && !(obj_dir in list(1,2,4,8,5,6,9,10))) + obj_dir = null + var/obj_name = sanitize(href_list["object_name"]) + + + var/atom/target //Where the object will be spawned + var/where = href_list["object_where"] + if (!( where in list("onfloor","frompod","inhand","inmarked") )) + where = "onfloor" + + + switch(where) + if("inhand") + if (!iscarbon(usr) && !iscyborg(usr)) + to_chat(usr, "Can only spawn in hand when you're a carbon mob or cyborg.") + where = "onfloor" + target = usr + + if("onfloor", "frompod") + switch(href_list["offset_type"]) + if ("absolute") + target = locate(0 + X,0 + Y,0 + Z) + if ("relative") + target = locate(loc.x + X,loc.y + Y,loc.z + Z) + if("inmarked") + if(!marked_datum) + to_chat(usr, "You don't have any object marked. Abandoning spawn.") + return + else if(!istype(marked_datum, /atom)) + to_chat(usr, "The object you have marked cannot be used as a target. Target must be of type /atom. Abandoning spawn.") + return + else + target = marked_datum + + var/obj/structure/closet/supplypod/centcompod/pod + if(target) + if(where == "frompod") + pod = new() + for (var/path in paths) + for (var/i = 0; i < number; i++) + if(path in typesof(/turf)) + var/turf/O = target + var/turf/N = O.ChangeTurf(path) + if(N && obj_name) + N.name = obj_name + else + var/atom/O + if(where == "frompod") + O = new path(pod) + else + O = new path(target) + if(!QDELETED(O)) + O.flags_1 |= ADMIN_SPAWNED_1 + if(obj_dir) + O.setDir(obj_dir) + if(obj_name) + O.name = obj_name + if(ismob(O)) + var/mob/M = O + M.real_name = obj_name + if(where == "inhand" && isliving(usr) && isitem(O)) + var/mob/living/L = usr + var/obj/item/I = O + L.put_in_hands(I) + if(iscyborg(L)) + var/mob/living/silicon/robot/R = L + if(R.module) + R.module.add_module(I, TRUE, TRUE) + R.activate_module(I) + + if(pod) + new /obj/effect/abstract/DPtarget(target, pod) + + if (number == 1) + log_admin("[key_name(usr)] created a [english_list(paths)]") + for(var/path in paths) + if(ispath(path, /mob)) + message_admins("[key_name_admin(usr)] created a [english_list(paths)]") + break + else + log_admin("[key_name(usr)] created [number]ea [english_list(paths)]") + for(var/path in paths) + if(ispath(path, /mob)) + message_admins("[key_name_admin(usr)] created [number]ea [english_list(paths)]") + break + return + + else if(href_list["secrets"]) + Secrets_topic(href_list["secrets"],href_list) + + else if(href_list["ac_view_wanted"]) //Admin newscaster Topic() stuff be here + if(!check_rights(R_ADMIN)) + return + src.admincaster_screen = 18 //The ac_ prefix before the hrefs stands for AdminCaster. + src.access_news_network() + + else if(href_list["ac_set_channel_name"]) + if(!check_rights(R_ADMIN)) + return + src.admincaster_feed_channel.channel_name = stripped_input(usr, "Provide a Feed Channel Name.", "Network Channel Handler", "") + src.access_news_network() + + else if(href_list["ac_set_channel_lock"]) + if(!check_rights(R_ADMIN)) + return + src.admincaster_feed_channel.locked = !src.admincaster_feed_channel.locked + src.access_news_network() + + else if(href_list["ac_submit_new_channel"]) + if(!check_rights(R_ADMIN)) + return + var/check = 0 + for(var/datum/newscaster/feed_channel/FC in GLOB.news_network.network_channels) + if(FC.channel_name == src.admincaster_feed_channel.channel_name) + check = 1 + break + if(src.admincaster_feed_channel.channel_name == "" || src.admincaster_feed_channel.channel_name == "\[REDACTED\]" || check ) + src.admincaster_screen=7 + else + var/choice = alert("Please confirm Feed channel creation.","Network Channel Handler","Confirm","Cancel") + if(choice=="Confirm") + GLOB.news_network.CreateFeedChannel(src.admincaster_feed_channel.channel_name, src.admin_signature, src.admincaster_feed_channel.locked, 1) + SSblackbox.record_feedback("tally", "newscaster_channels", 1, src.admincaster_feed_channel.channel_name) + log_admin("[key_name(usr)] created command feed channel: [src.admincaster_feed_channel.channel_name]!") + src.admincaster_screen=5 + src.access_news_network() + + else if(href_list["ac_set_channel_receiving"]) + if(!check_rights(R_ADMIN)) + return + var/list/available_channels = list() + for(var/datum/newscaster/feed_channel/F in GLOB.news_network.network_channels) + available_channels += F.channel_name + src.admincaster_feed_channel.channel_name = adminscrub(input(usr, "Choose receiving Feed Channel.", "Network Channel Handler") in available_channels ) + src.access_news_network() + + else if(href_list["ac_set_new_message"]) + if(!check_rights(R_ADMIN)) + return + src.admincaster_feed_message.body = adminscrub(stripped_input(usr, "Write your Feed story.", "Network Channel Handler", "")) + src.access_news_network() + + else if(href_list["ac_submit_new_message"]) + if(!check_rights(R_ADMIN)) + return + if(src.admincaster_feed_message.returnBody(-1) =="" || src.admincaster_feed_message.returnBody(-1) =="\[REDACTED\]" || src.admincaster_feed_channel.channel_name == "" ) + src.admincaster_screen = 6 + else + GLOB.news_network.SubmitArticle(src.admincaster_feed_message.returnBody(-1), src.admin_signature, src.admincaster_feed_channel.channel_name, null, 1) + SSblackbox.record_feedback("amount", "newscaster_stories", 1) + src.admincaster_screen=4 + + for(var/obj/machinery/newscaster/NEWSCASTER in GLOB.allCasters) + NEWSCASTER.newsAlert(src.admincaster_feed_channel.channel_name) + + log_admin("[key_name(usr)] submitted a feed story to channel: [src.admincaster_feed_channel.channel_name]!") + src.access_news_network() + + else if(href_list["ac_create_channel"]) + if(!check_rights(R_ADMIN)) + return + src.admincaster_screen=2 + src.access_news_network() + + else if(href_list["ac_create_feed_story"]) + if(!check_rights(R_ADMIN)) + return + src.admincaster_screen=3 + src.access_news_network() + + else if(href_list["ac_menu_censor_story"]) + if(!check_rights(R_ADMIN)) + return + src.admincaster_screen=10 + src.access_news_network() + + else if(href_list["ac_menu_censor_channel"]) + if(!check_rights(R_ADMIN)) + return + src.admincaster_screen=11 + src.access_news_network() + + else if(href_list["ac_menu_wanted"]) + if(!check_rights(R_ADMIN)) + return + var/already_wanted = 0 + if(GLOB.news_network.wanted_issue.active) + already_wanted = 1 + + if(already_wanted) + src.admincaster_wanted_message.criminal = GLOB.news_network.wanted_issue.criminal + src.admincaster_wanted_message.body = GLOB.news_network.wanted_issue.body + src.admincaster_screen = 14 + src.access_news_network() + + else if(href_list["ac_set_wanted_name"]) + if(!check_rights(R_ADMIN)) + return + src.admincaster_wanted_message.criminal = adminscrub(stripped_input(usr, "Provide the name of the Wanted person.", "Network Security Handler", "")) + src.access_news_network() + + else if(href_list["ac_set_wanted_desc"]) + if(!check_rights(R_ADMIN)) + return + src.admincaster_wanted_message.body = adminscrub(stripped_input(usr, "Provide the a description of the Wanted person and any other details you deem important.", "Network Security Handler", "")) + src.access_news_network() + + else if(href_list["ac_submit_wanted"]) + if(!check_rights(R_ADMIN)) + return + var/input_param = text2num(href_list["ac_submit_wanted"]) + if(src.admincaster_wanted_message.criminal == "" || src.admincaster_wanted_message.body == "") + src.admincaster_screen = 16 + else + var/choice = alert("Please confirm Wanted Issue [(input_param==1) ? ("creation.") : ("edit.")]","Network Security Handler","Confirm","Cancel") + if(choice=="Confirm") + if(input_param==1) //If input_param == 1 we're submitting a new wanted issue. At 2 we're just editing an existing one. See the else below + GLOB.news_network.submitWanted(admincaster_wanted_message.criminal, admincaster_wanted_message.body, admin_signature, null, 1, 1) + src.admincaster_screen = 15 + else + GLOB.news_network.submitWanted(admincaster_wanted_message.criminal, admincaster_wanted_message.body, admin_signature) + src.admincaster_screen = 19 + log_admin("[key_name(usr)] issued a Station-wide Wanted Notification for [src.admincaster_wanted_message.criminal]!") + src.access_news_network() + + else if(href_list["ac_cancel_wanted"]) + if(!check_rights(R_ADMIN)) + return + var/choice = alert("Please confirm Wanted Issue removal.","Network Security Handler","Confirm","Cancel") + if(choice=="Confirm") + GLOB.news_network.deleteWanted() + src.admincaster_screen=17 + src.access_news_network() + + else if(href_list["ac_censor_channel_author"]) + if(!check_rights(R_ADMIN)) + return + var/datum/newscaster/feed_channel/FC = locate(href_list["ac_censor_channel_author"]) + FC.toggleCensorAuthor() + src.access_news_network() + + else if(href_list["ac_censor_channel_story_author"]) + if(!check_rights(R_ADMIN)) + return + var/datum/newscaster/feed_message/MSG = locate(href_list["ac_censor_channel_story_author"]) + MSG.toggleCensorAuthor() + src.access_news_network() + + else if(href_list["ac_censor_channel_story_body"]) + if(!check_rights(R_ADMIN)) + return + var/datum/newscaster/feed_message/MSG = locate(href_list["ac_censor_channel_story_body"]) + MSG.toggleCensorBody() + src.access_news_network() + + else if(href_list["ac_pick_d_notice"]) + if(!check_rights(R_ADMIN)) + return + var/datum/newscaster/feed_channel/FC = locate(href_list["ac_pick_d_notice"]) + src.admincaster_feed_channel = FC + src.admincaster_screen=13 + src.access_news_network() + + else if(href_list["ac_toggle_d_notice"]) + if(!check_rights(R_ADMIN)) + return + var/datum/newscaster/feed_channel/FC = locate(href_list["ac_toggle_d_notice"]) + FC.toggleCensorDclass() + src.access_news_network() + + else if(href_list["ac_view"]) + if(!check_rights(R_ADMIN)) + return + src.admincaster_screen=1 + src.access_news_network() + + else if(href_list["ac_setScreen"]) //Brings us to the main menu and resets all fields~ + if(!check_rights(R_ADMIN)) + return + src.admincaster_screen = text2num(href_list["ac_setScreen"]) + if (src.admincaster_screen == 0) + if(src.admincaster_feed_channel) + src.admincaster_feed_channel = new /datum/newscaster/feed_channel + if(src.admincaster_feed_message) + src.admincaster_feed_message = new /datum/newscaster/feed_message + if(admincaster_wanted_message) + admincaster_wanted_message = new /datum/newscaster/wanted_message + src.access_news_network() + + else if(href_list["ac_show_channel"]) + if(!check_rights(R_ADMIN)) + return + var/datum/newscaster/feed_channel/FC = locate(href_list["ac_show_channel"]) + src.admincaster_feed_channel = FC + src.admincaster_screen = 9 + src.access_news_network() + + else if(href_list["ac_pick_censor_channel"]) + if(!check_rights(R_ADMIN)) + return + var/datum/newscaster/feed_channel/FC = locate(href_list["ac_pick_censor_channel"]) + src.admincaster_feed_channel = FC + src.admincaster_screen = 12 + src.access_news_network() + + else if(href_list["ac_refresh"]) + if(!check_rights(R_ADMIN)) + return + src.access_news_network() + + else if(href_list["ac_set_signature"]) + if(!check_rights(R_ADMIN)) + return + src.admin_signature = adminscrub(input(usr, "Provide your desired signature.", "Network Identity Handler", "")) + src.access_news_network() + + else if(href_list["ac_del_comment"]) + if(!check_rights(R_ADMIN)) + return + var/datum/newscaster/feed_comment/FC = locate(href_list["ac_del_comment"]) + var/datum/newscaster/feed_message/FM = locate(href_list["ac_del_comment_msg"]) + FM.comments -= FC + qdel(FC) + src.access_news_network() + + else if(href_list["ac_lock_comment"]) + if(!check_rights(R_ADMIN)) + return + var/datum/newscaster/feed_message/FM = locate(href_list["ac_lock_comment"]) + FM.locked ^= 1 + src.access_news_network() + + else if(href_list["check_antagonist"]) + if(!check_rights(R_ADMIN)) + return + usr.client.check_antagonists() + + else if(href_list["kick_all_from_lobby"]) + if(!check_rights(R_ADMIN)) + return + if(SSticker.IsRoundInProgress()) + var/afkonly = text2num(href_list["afkonly"]) + if(alert("Are you sure you want to kick all [afkonly ? "AFK" : ""] clients from the lobby??","Message","Yes","Cancel") != "Yes") + to_chat(usr, "Kick clients from lobby aborted") + return + var/list/listkicked = kick_clients_in_lobby("You were kicked from the lobby by [usr.client.holder.fakekey ? "an Administrator" : "[usr.client.key]"].", afkonly) + + var/strkicked = "" + for(var/name in listkicked) + strkicked += "[name], " + message_admins("[key_name_admin(usr)] has kicked [afkonly ? "all AFK" : "all"] clients from the lobby. [length(listkicked)] clients kicked: [strkicked ? strkicked : "--"]") + log_admin("[key_name(usr)] has kicked [afkonly ? "all AFK" : "all"] clients from the lobby. [length(listkicked)] clients kicked: [strkicked ? strkicked : "--"]") + else + to_chat(usr, "You may only use this when the game is running.") + + else if(href_list["create_outfit"]) + if(!check_rights(R_ADMIN)) + return + + var/datum/outfit/O = new /datum/outfit + //swap this for js dropdowns sometime + O.name = href_list["outfit_name"] + O.uniform = text2path(href_list["outfit_uniform"]) + O.shoes = text2path(href_list["outfit_shoes"]) + O.gloves = text2path(href_list["outfit_gloves"]) + O.suit = text2path(href_list["outfit_suit"]) + O.head = text2path(href_list["outfit_head"]) + O.back = text2path(href_list["outfit_back"]) + O.mask = text2path(href_list["outfit_mask"]) + O.glasses = text2path(href_list["outfit_glasses"]) + O.r_hand = text2path(href_list["outfit_r_hand"]) + O.l_hand = text2path(href_list["outfit_l_hand"]) + O.suit_store = text2path(href_list["outfit_s_store"]) + O.l_pocket = text2path(href_list["outfit_l_pocket"]) + O.r_pocket = text2path(href_list["outfit_r_pocket"]) + O.id = text2path(href_list["outfit_id"]) + O.belt = text2path(href_list["outfit_belt"]) + O.ears = text2path(href_list["outfit_ears"]) + + GLOB.custom_outfits.Add(O) + message_admins("[key_name(usr)] created \"[O.name]\" outfit!") + + else if(href_list["set_selfdestruct_code"]) + if(!check_rights(R_ADMIN)) + return + var/code = random_nukecode() + for(var/obj/machinery/nuclearbomb/selfdestruct/SD in GLOB.nuke_list) + SD.r_code = code + message_admins("[key_name_admin(usr)] has set the self-destruct \ + code to \"[code]\".") + + else if(href_list["add_station_goal"]) + if(!check_rights(R_ADMIN)) + return + var/list/type_choices = typesof(/datum/station_goal) + var/picked = input("Choose goal type") in type_choices|null + if(!picked) + return + var/datum/station_goal/G = new picked() + if(picked == /datum/station_goal) + var/newname = input("Enter goal name:") as text|null + if(!newname) + return + G.name = newname + var/description = input("Enter CentCom message contents:") as message|null + if(!description) + return + G.report_message = description + message_admins("[key_name(usr)] created \"[G.name]\" station goal.") + SSticker.mode.station_goals += G + modify_goals() + + else if(href_list["viewruntime"]) + var/datum/error_viewer/error_viewer = locate(href_list["viewruntime"]) + if(!istype(error_viewer)) + to_chat(usr, "That runtime viewer no longer exists.") + return + + if(href_list["viewruntime_backto"]) + error_viewer.show_to(owner, locate(href_list["viewruntime_backto"]), href_list["viewruntime_linear"]) + else + error_viewer.show_to(owner, null, href_list["viewruntime_linear"]) + + else if(href_list["showrelatedacc"]) + if(!check_rights(R_ADMIN)) + return + var/client/C = locate(href_list["client"]) in GLOB.clients + var/thing_to_check + if(href_list["showrelatedacc"] == "cid") + thing_to_check = C.related_accounts_cid + else + thing_to_check = C.related_accounts_ip + thing_to_check = splittext(thing_to_check, ", ") + + + var/list/dat = list("Related accounts by [uppertext(href_list["showrelatedacc"])]:") + dat += thing_to_check + + usr << browse(dat.Join("
"), "window=related_[C];size=420x300") + else if(href_list["centcomlookup"]) + if(!check_rights(R_ADMIN)) + return + + if(!CONFIG_GET(string/centcom_ban_db)) + to_chat(usr, "Centcom Galactic Ban DB is disabled!") + return + + var/ckey = href_list["centcomlookup"] + + // Make the request + var/datum/http_request/request = new() + request.prepare(RUSTG_HTTP_METHOD_GET, "[CONFIG_GET(string/centcom_ban_db)]/[ckey]", "", "") + request.begin_async() + UNTIL(request.is_complete() || !usr) + if (!usr) + return + var/datum/http_response/response = request.into_response() + + var/list/bans + + var/list/dat = list("") + + if(response.errored) + dat += "
Failed to connect to CentCom." + else if(response.status_code != 200) + dat += "
Failed to connect to CentCom. Status code: [response.status_code]" + else + if(response.body == "[]") + dat += "
0 bans detected for [ckey]
" + else + bans = json_decode(response["body"]) + dat += "
[bans.len] ban\s detected for [ckey]
" + for(var/list/ban in bans) + dat += "Server: [sanitize(ban["sourceName"])]
" + dat += "RP Level: [sanitize(ban["sourceRoleplayLevel"])]
" + dat += "Type: [sanitize(ban["type"])]
" + dat += "Banned By: [sanitize(ban["bannedBy"])]
" + dat += "Reason: [sanitize(ban["reason"])]
" + dat += "Datetime: [sanitize(ban["bannedOn"])]
" + var/expiration = ban["expires"] + dat += "Expires: [expiration ? "[sanitize(expiration)]" : "Permanent"]
" + if(ban["type"] == "job") + dat += "Jobs: " + var/list/jobs = ban["jobs"] + dat += sanitize(jobs.Join(", ")) + dat += "
" + dat += "
" + + dat += "
" + var/datum/browser/popup = new(usr, "centcomlookup-[ckey]", "
Central Command Galactic Ban Database
", 700, 600) + popup.set_content(dat.Join()) + popup.open(0) + + + else if(href_list["modantagrep"]) + if(!check_rights(R_ADMIN)) + return + + var/mob/M = locate(href_list["mob"]) in GLOB.mob_list + var/client/C = M.client + usr.client.cmd_admin_mod_antag_rep(C, href_list["modantagrep"]) + show_player_panel(M) + + else if(href_list["slowquery"]) + if(!check_rights(R_ADMIN)) + return + var/answer = href_list["slowquery"] + if(answer == "yes") + log_query_debug("[usr.key] | Reported a server hang") + if(alert(usr, "Had you just press any admin buttons?", "Query server hang report", "Yes", "No") == "Yes") + var/response = input(usr,"What were you just doing?","Query server hang report") as null|text + if(response) + log_query_debug("[usr.key] | [response]") + else if(answer == "no") + log_query_debug("[usr.key] | Reported no server hang") + +/datum/admins/proc/HandleCMode() + if(!check_rights(R_ADMIN)) + return + + if(SSticker.HasRoundStarted()) + return alert(usr, "The game has already started.", null, null, null, null) + var/dat = {"What mode do you wish to play?
"} + for(var/mode in config.modes) + dat += {"[config.mode_names[mode]]
"} + dat += {"Secret
"} + dat += {"Random
"} + dat += {"Now: [GLOB.master_mode]"} + usr << browse(dat, "window=c_mode") + +/datum/admins/proc/HandleFSecret() + if(!check_rights(R_ADMIN)) + return + + if(SSticker.HasRoundStarted()) + return alert(usr, "The game has already started.", null, null, null, null) + if(GLOB.master_mode != "secret") + return alert(usr, "The game mode has to be secret!", null, null, null, null) + var/dat = {"What game mode do you want to force secret to be? Use this if you want to change the game mode, but want the players to believe it's secret. This will only work if the current game mode is secret.
"} + for(var/mode in config.modes) + dat += {"[config.mode_names[mode]]
"} + dat += {"Random (default)
"} + dat += {"Now: [GLOB.secret_force_mode]"} + usr << browse(dat, "window=f_secret") + +/datum/admins/proc/makeMentor(ckey) + if(!usr.client) + return + if (!check_rights(0)) + return + if(!ckey) + return + var/client/C = GLOB.directory[ckey] + if(C) + if(check_rights_for(C, R_ADMIN,0)) + to_chat(usr, "The client chosen is an admin! Cannot mentorize.") + return + if(SSdbcore.Connect()) + var/datum/DBQuery/query_get_mentor = SSdbcore.NewQuery("SELECT id FROM [format_table_name("mentor")] WHERE ckey = '[ckey]'") + if(query_get_mentor.NextRow()) + to_chat(usr, "[ckey] is already a mentor.") + return + var/datum/DBQuery/query_add_mentor = SSdbcore.NewQuery("INSERT INTO `[format_table_name("mentor")]` (`id`, `ckey`) VALUES (null, '[ckey]')") + if(!query_add_mentor.warn_execute()) + return + var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO `[format_table_name("admin_log")]` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added new mentor [ckey]');") + if(!query_add_admin_log.warn_execute()) + return + else + to_chat(usr, "Failed to establish database connection. The changes will last only for the current round.") + new /datum/mentors(ckey) + to_chat(usr, "New mentor added.") + +/datum/admins/proc/removeMentor(ckey) + if(!usr.client) + return + if (!check_rights(0)) + return + if(!ckey) + return + var/client/C = GLOB.directory[ckey] + if(C) + if(check_rights_for(C, R_ADMIN,0)) + to_chat(usr, "The client chosen is an admin, not a mentor! Cannot de-mentorize.") + return + C.remove_mentor_verbs() + C.mentor_datum = null + GLOB.mentors -= C + if(SSdbcore.Connect()) + var/datum/DBQuery/query_remove_mentor = SSdbcore.NewQuery("DELETE FROM [format_table_name("mentor")] WHERE ckey = '[ckey]'") + if(!query_remove_mentor.warn_execute()) + return + var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO `[format_table_name("admin_log")]` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Removed mentor [ckey]');") + if(!query_add_admin_log.warn_execute()) + return + else + to_chat(usr, "Failed to establish database connection. The changes will last only for the current round.") + to_chat(usr, "Mentor removed.") diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 7b736590..e4244cb9 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -1,1434 +1,1454 @@ -/client/proc/cmd_admin_drop_everything(mob/M in GLOB.mob_list) - set category = null - set name = "Drop Everything" - if(!check_rights(R_ADMIN)) - return - - var/confirm = alert(src, "Make [M] drop everything?", "Message", "Yes", "No") - if(confirm != "Yes") - return - - for(var/obj/item/W in M) - if(!M.dropItemToGround(W)) - qdel(W) - M.regenerate_icons() - - log_admin("[key_name(usr)] made [key_name(M)] drop everything!") - var/msg = "[key_name_admin(usr)] made [ADMIN_LOOKUPFLW(M)] drop everything!" - message_admins(msg) - admin_ticket_log(M, msg) - SSblackbox.record_feedback("tally", "admin_verb", 1, "Drop Everything") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/cmd_admin_subtle_message(mob/M in GLOB.mob_list) - set category = "Special Verbs" - set name = "Subtle Message" - - if(!ismob(M)) - return - if(!check_rights(R_ADMIN)) - return - - message_admins("[key_name_admin(src)] has started answering [ADMIN_LOOKUPFLW(M)]'s prayer.") - var/msg = input("Message:", text("Subtle PM to [M.key]")) as text|null - - if (!msg) - message_admins("[key_name_admin(src)] decided not to answer [ADMIN_LOOKUPFLW(M)]'s prayer") - return - if(usr) - if (usr.client) - if(usr.client.holder) - to_chat(M, "You hear a voice in your head... [msg]") - - log_admin("SubtlePM: [key_name(usr)] -> [key_name(M)] : [msg]") - msg = " SubtleMessage: [key_name_admin(usr)] -> [key_name_admin(M)] : [msg]" - message_admins(msg) - admin_ticket_log(M, msg) - SSblackbox.record_feedback("tally", "admin_verb", 1, "Subtle Message") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/cmd_admin_headset_message(mob/M in GLOB.mob_list) - set category = "Special Verbs" - set name = "Headset Message" - - admin_headset_message(M) - -/client/proc/admin_headset_message(mob/M in GLOB.mob_list, sender = null) - var/mob/living/carbon/human/H = M - - if(!check_rights(R_ADMIN)) - return - - if(!istype(H)) - to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") - return - if(!istype(H.ears, /obj/item/radio/headset)) - to_chat(usr, "The person you are trying to contact is not wearing a headset.") - return - - if (!sender) - sender = input("Who is the message from?", "Sender") as null|anything in list(RADIO_CHANNEL_CENTCOM,RADIO_CHANNEL_SYNDICATE) - if(!sender) - return - - message_admins("[key_name_admin(src)] has started answering [key_name_admin(H)]'s [sender] request.") - var/input = input("Please enter a message to reply to [key_name(H)] via their headset.","Outgoing message from [sender]", "") as text|null - if(!input) - message_admins("[key_name_admin(src)] decided not to answer [key_name_admin(H)]'s [sender] request.") - return - - log_directed_talk(src, H, input, LOG_ADMIN, "reply") - message_admins("[key_name_admin(src)] replied to [key_name_admin(H)]'s [sender] message with: \"[input]\"") - to_chat(H, "You hear something crackle in your ears for a moment before a voice speaks. \"Please stand by for a message from [sender == "Syndicate" ? "your benefactor" : "Central Command"]. Message as follows[sender == "Syndicate" ? ", agent." : ":"] [input]. Message ends.\"") - - SSblackbox.record_feedback("tally", "admin_verb", 1, "Headset Message") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/cmd_admin_mod_antag_rep(client/C in GLOB.clients, var/operation) - set category = "Special Verbs" - set name = "Modify Antagonist Reputation" - - if(!check_rights(R_ADMIN)) - return - - var/msg = "" - var/log_text = "" - - if(operation == "zero") - log_text = "Set to 0" - SSpersistence.antag_rep -= C.ckey - else - var/prompt = "Please enter the amount of reputation to [operation]:" - - if(operation == "set") - prompt = "Please enter the new reputation value:" - - msg = input("Message:", prompt) as num|null - - if (!msg) - return - - var/ANTAG_REP_MAXIMUM = CONFIG_GET(number/antag_rep_maximum) - - if(operation == "set") - log_text = "Set to [num2text(msg)]" - SSpersistence.antag_rep[C.ckey] = max(0, min(msg, ANTAG_REP_MAXIMUM)) - else if(operation == "add") - log_text = "Added [num2text(msg)]" - SSpersistence.antag_rep[C.ckey] = min(SSpersistence.antag_rep[C.ckey]+msg, ANTAG_REP_MAXIMUM) - else if(operation == "subtract") - log_text = "Subtracted [num2text(msg)]" - SSpersistence.antag_rep[C.ckey] = max(SSpersistence.antag_rep[C.ckey]-msg, 0) - else - to_chat(src, "Invalid operation for antag rep modification: [operation] by user [key_name(usr)]") - return - - if(SSpersistence.antag_rep[C.ckey] <= 0) - SSpersistence.antag_rep -= C.ckey - - log_admin("[key_name(usr)]: Modified [key_name(C)]'s antagonist reputation [log_text]") - message_admins("[key_name_admin(usr)]: Modified [key_name(C)]'s antagonist reputation ([log_text])") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Modify Antagonist Reputation") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/cmd_admin_world_narrate() - set category = "Special Verbs" - set name = "Global Narrate" - - if(!check_rights(R_ADMIN)) - return - - var/msg = input("Message:", text("Enter the text you wish to appear to everyone:")) as text|null - - if (!msg) - return - to_chat(world, "[msg]") - log_admin("GlobalNarrate: [key_name(usr)] : [msg]") - message_admins("[key_name_admin(usr)] Sent a global narrate") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Global Narrate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/cmd_admin_direct_narrate(mob/M) - set category = "Special Verbs" - set name = "Direct Narrate" - - if(!check_rights(R_ADMIN)) - return - - if(!M) - M = input("Direct narrate to whom?", "Active Players") as null|anything in GLOB.player_list - - if(!M) - return - - var/msg = input("Message:", text("Enter the text you wish to appear to your target:")) as text|null - - if( !msg ) - return - - to_chat(M, msg) - log_admin("DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]") - msg = " DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]
" - message_admins(msg) - admin_ticket_log(M, msg) - SSblackbox.record_feedback("tally", "admin_verb", 1, "Direct Narrate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/cmd_admin_local_narrate(atom/A) - set category = "Special Verbs" - set name = "Local Narrate" - - if(!check_rights(R_ADMIN)) - return - if(!A) - return - var/range = input("Range:", "Narrate to mobs within how many tiles:", 7) as num|null - if(!range) - return - var/msg = input("Message:", text("Enter the text you wish to appear to everyone within view:")) as text|null - if (!msg) - return - for(var/mob/M in view(range,A)) - to_chat(M, msg) - - log_admin("LocalNarrate: [key_name(usr)] at [AREACOORD(A)]: [msg]") - message_admins(" LocalNarrate: [key_name_admin(usr)] at [ADMIN_VERBOSEJMP(A)]: [msg]
") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Local Narrate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/cmd_admin_godmode(mob/M in GLOB.mob_list) - set category = "Special Verbs" - set name = "Godmode" - if(!check_rights(R_ADMIN)) - return - - M.status_flags ^= GODMODE - to_chat(usr, "Toggled [(M.status_flags & GODMODE) ? "ON" : "OFF"]") - - log_admin("[key_name(usr)] has toggled [key_name(M)]'s nodamage to [(M.status_flags & GODMODE) ? "On" : "Off"]") - var/msg = "[key_name_admin(usr)] has toggled [ADMIN_LOOKUPFLW(M)]'s nodamage to [(M.status_flags & GODMODE) ? "On" : "Off"]" - message_admins(msg) - admin_ticket_log(M, msg) - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Godmode", "[M.status_flags & GODMODE ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - - -/proc/cmd_admin_mute(whom, mute_type, automute = 0) - if(!whom) - return - - var/muteunmute - var/mute_string - var/feedback_string - switch(mute_type) - if(MUTE_IC) - mute_string = "IC (say and emote)" - feedback_string = "IC" - if(MUTE_OOC) - mute_string = "OOC" - feedback_string = "OOC" - if(MUTE_PRAY) - mute_string = "pray" - feedback_string = "Pray" - if(MUTE_ADMINHELP) - mute_string = "adminhelp, admin PM and ASAY" - feedback_string = "Adminhelp" - if(MUTE_DEADCHAT) - mute_string = "deadchat and DSAY" - feedback_string = "Deadchat" - if(MUTE_ALL) - mute_string = "everything" - feedback_string = "Everything" - else - return - - var/client/C - if(istype(whom, /client)) - C = whom - else if(istext(whom)) - C = GLOB.directory[whom] - else - return - - var/datum/preferences/P - if(C) - P = C.prefs - else - P = GLOB.preferences_datums[whom] - if(!P) - return - - if(automute) - if(!CONFIG_GET(flag/automute_on)) - return - else - if(!check_rights()) - return - - if(automute) - muteunmute = "auto-muted" - P.muted |= mute_type - log_admin("SPAM AUTOMUTE: [muteunmute] [key_name(whom)] from [mute_string]") - message_admins("SPAM AUTOMUTE: [muteunmute] [key_name_admin(whom)] from [mute_string].") - if(C) - to_chat(C, "You have been [muteunmute] from [mute_string] by the SPAM AUTOMUTE system. Contact an admin.") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Auto Mute [feedback_string]", "1")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - return - - if(P.muted & mute_type) - muteunmute = "unmuted" - P.muted &= ~mute_type - else - muteunmute = "muted" - P.muted |= mute_type - - log_admin("[key_name(usr)] has [muteunmute] [key_name(whom)] from [mute_string]") - message_admins("[key_name_admin(usr)] has [muteunmute] [key_name_admin(whom)] from [mute_string].") - if(C) - to_chat(C, "You have been [muteunmute] from [mute_string] by [key_name(usr, include_name = FALSE)].") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Mute [feedback_string]", "[P.muted & mute_type]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - - -//I use this proc for respawn character too. /N -/proc/create_xeno(ckey) - if(!ckey) - var/list/candidates = list() - for(var/mob/M in GLOB.player_list) - if(M.stat != DEAD) - continue //we are not dead! - if(!(ROLE_ALIEN in M.client.prefs.be_special)) - continue //we don't want to be an alium - if(M.client.is_afk()) - continue //we are afk - if(M.mind && M.mind.current && M.mind.current.stat != DEAD) - continue //we have a live body we are tied to - candidates += M.ckey - if(candidates.len) - ckey = input("Pick the player you want to respawn as a xeno.", "Suitable Candidates") as null|anything in candidates - else - to_chat(usr, "Error: create_xeno(): no suitable candidates.") - if(!istext(ckey)) - return 0 - - var/alien_caste = input(usr, "Please choose which caste to spawn.","Pick a caste",null) as null|anything in list("Queen","Praetorian","Hunter","Sentinel","Drone","Larva") - var/obj/effect/landmark/spawn_here = GLOB.xeno_spawn.len ? pick(GLOB.xeno_spawn) : null - var/mob/living/carbon/alien/new_xeno - switch(alien_caste) - if("Queen") - new_xeno = new /mob/living/carbon/alien/humanoid/royal/queen(spawn_here) - if("Praetorian") - new_xeno = new /mob/living/carbon/alien/humanoid/royal/praetorian(spawn_here) - if("Hunter") - new_xeno = new /mob/living/carbon/alien/humanoid/hunter(spawn_here) - if("Sentinel") - new_xeno = new /mob/living/carbon/alien/humanoid/sentinel(spawn_here) - if("Drone") - new_xeno = new /mob/living/carbon/alien/humanoid/drone(spawn_here) - if("Larva") - new_xeno = new /mob/living/carbon/alien/larva(spawn_here) - else - return 0 - if(!spawn_here) - SSjob.SendToLateJoin(new_xeno, FALSE) - - new_xeno.ckey = ckey - var/msg = "[key_name_admin(usr)] has spawned [ckey] as a filthy xeno [alien_caste]." - message_admins(msg) - admin_ticket_log(new_xeno, msg) - return 1 - -/* -If a guy was gibbed and you want to revive him, this is a good way to do so. -Works kind of like entering the game with a new character. Character receives a new mind if they didn't have one. -Traitors and the like can also be revived with the previous role mostly intact. -/N */ -/client/proc/respawn_character() - set category = "Special Verbs" - set name = "Respawn Character" - set desc = "Respawn a person that has been gibbed/dusted/killed. They must be a ghost for this to work and preferably should not have a body to go back into." - if(!check_rights(R_ADMIN)) - return - - var/input = ckey(input(src, "Please specify which key will be respawned.", "Key", "")) - if(!input) - return - - var/mob/dead/observer/G_found - for(var/mob/dead/observer/G in GLOB.player_list) - if(G.ckey == input) - G_found = G - break - - if(!G_found)//If a ghost was not found. - to_chat(usr, "There is no active key like that in the game or the person is not currently a ghost.") - return - - if(G_found.mind && !G_found.mind.active) //mind isn't currently in use by someone/something - //Check if they were an alien - if(G_found.mind.assigned_role == ROLE_ALIEN) - if(alert("This character appears to have been an alien. Would you like to respawn them as such?",,"Yes","No")=="Yes") - var/turf/T - if(GLOB.xeno_spawn.len) - T = pick(GLOB.xeno_spawn) - - var/mob/living/carbon/alien/new_xeno - switch(G_found.mind.special_role)//If they have a mind, we can determine which caste they were. - if("Hunter") - new_xeno = new /mob/living/carbon/alien/humanoid/hunter(T) - if("Sentinel") - new_xeno = new /mob/living/carbon/alien/humanoid/sentinel(T) - if("Drone") - new_xeno = new /mob/living/carbon/alien/humanoid/drone(T) - if("Praetorian") - new_xeno = new /mob/living/carbon/alien/humanoid/royal/praetorian(T) - if("Queen") - new_xeno = new /mob/living/carbon/alien/humanoid/royal/queen(T) - else//If we don't know what special role they have, for whatever reason, or they're a larva. - create_xeno(G_found.ckey) - return - - if(!T) - SSjob.SendToLateJoin(new_xeno, FALSE) - - //Now to give them their mind back. - G_found.mind.transfer_to(new_xeno) //be careful when doing stuff like this! I've already checked the mind isn't in use - new_xeno.key = G_found.key - to_chat(new_xeno, "You have been fully respawned. Enjoy the game.") - var/msg = "[key_name_admin(usr)] has respawned [new_xeno.key] as a filthy xeno." - message_admins(msg) - admin_ticket_log(new_xeno, msg) - return //all done. The ghost is auto-deleted - - //check if they were a monkey - else if(findtext(G_found.real_name,"monkey")) - if(alert("This character appears to have been a monkey. Would you like to respawn them as such?",,"Yes","No")=="Yes") - var/mob/living/carbon/monkey/new_monkey = new - SSjob.SendToLateJoin(new_monkey) - G_found.mind.transfer_to(new_monkey) //be careful when doing stuff like this! I've already checked the mind isn't in use - new_monkey.key = G_found.key - to_chat(new_monkey, "You have been fully respawned. Enjoy the game.") - var/msg = "[key_name_admin(usr)] has respawned [new_monkey.key] as a filthy xeno." - message_admins(msg) - admin_ticket_log(new_monkey, msg) - return //all done. The ghost is auto-deleted - - - //Ok, it's not a xeno or a monkey. So, spawn a human. - var/mob/living/carbon/human/new_character = new//The mob being spawned. - SSjob.SendToLateJoin(new_character) - - var/datum/data/record/record_found //Referenced to later to either randomize or not randomize the character. - if(G_found.mind && !G_found.mind.active) //mind isn't currently in use by someone/something - /*Try and locate a record for the person being respawned through GLOB.data_core. - This isn't an exact science but it does the trick more often than not.*/ - var/id = md5("[G_found.real_name][G_found.mind.assigned_role]") - - record_found = find_record("id", id, GLOB.data_core.locked) - - if(record_found)//If they have a record we can determine a few things. - new_character.real_name = record_found.fields["name"] - new_character.gender = record_found.fields["sex"] - new_character.age = record_found.fields["age"] - new_character.hardset_dna(record_found.fields["identity"], record_found.fields["enzymes"], record_found.fields["name"], record_found.fields["blood_type"], new record_found.fields["species"], record_found.fields["features"]) - else - var/datum/preferences/A = new() - A.copy_to(new_character) - A.real_name = G_found.real_name - new_character.dna.update_dna_identity() - - new_character.name = new_character.real_name - - if(G_found.mind && !G_found.mind.active) - G_found.mind.transfer_to(new_character) //be careful when doing stuff like this! I've already checked the mind isn't in use - else - new_character.mind_initialize() - if(!new_character.mind.assigned_role) - new_character.mind.assigned_role = "Assistant"//If they somehow got a null assigned role. - - new_character.key = G_found.key - - /* - The code below functions with the assumption that the mob is already a traitor if they have a special role. - So all it does is re-equip the mob with powers and/or items. Or not, if they have no special role. - If they don't have a mind, they obviously don't have a special role. - */ - - //Two variables to properly announce later on. - var/admin = key_name_admin(src) - var/player_key = G_found.key - - //Now for special roles and equipment. - var/datum/antagonist/traitor/traitordatum = new_character.mind.has_antag_datum(/datum/antagonist/traitor) - if(traitordatum) - SSjob.EquipRank(new_character, new_character.mind.assigned_role, 1) - traitordatum.equip() - - - switch(new_character.mind.special_role) - if(ROLE_WIZARD) - new_character.forceMove(pick(GLOB.wizardstart)) - var/datum/antagonist/wizard/A = new_character.mind.has_antag_datum(/datum/antagonist/wizard,TRUE) - A.equip_wizard() - if(ROLE_SYNDICATE) - new_character.forceMove(pick(GLOB.nukeop_start)) - var/datum/antagonist/nukeop/N = new_character.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE) - N.equip_op() - if(ROLE_NINJA) - var/list/ninja_spawn = list() - for(var/obj/effect/landmark/carpspawn/L in GLOB.landmarks_list) - ninja_spawn += L - var/datum/antagonist/ninja/ninjadatum = new_character.mind.has_antag_datum(/datum/antagonist/ninja) - ninjadatum.equip_space_ninja() - if(ninja_spawn.len) - new_character.forceMove(pick(ninja_spawn)) - - else//They may also be a cyborg or AI. - switch(new_character.mind.assigned_role) - if("Cyborg")//More rigging to make em' work and check if they're traitor. - new_character = new_character.Robotize(TRUE) - if("AI") - new_character = new_character.AIize() - else - SSjob.EquipRank(new_character, new_character.mind.assigned_role, 1)//Or we simply equip them. - - //Announces the character on all the systems, based on the record. - if(!issilicon(new_character))//If they are not a cyborg/AI. - if(!record_found&&new_character.mind.assigned_role!=new_character.mind.special_role)//If there are no records for them. If they have a record, this info is already in there. MODE people are not announced anyway. - //Power to the user! - if(alert(new_character,"Warning: No data core entry detected. Would you like to announce the arrival of this character by adding them to various databases, such as medical records?",,"No","Yes")=="Yes") - GLOB.data_core.manifest_inject(new_character, new_character.client) - - if(alert(new_character,"Would you like an active AI to announce this character?",,"No","Yes")=="Yes") - AnnounceArrival(new_character, new_character.mind.assigned_role) - - var/msg = "[admin] has respawned [player_key] as [new_character.real_name]." - message_admins(msg) - admin_ticket_log(new_character, msg) - - to_chat(new_character, "You have been fully respawned. Enjoy the game.") - - SSblackbox.record_feedback("tally", "admin_verb", 1, "Respawn Character") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - return new_character - -/client/proc/cmd_admin_add_freeform_ai_law() - set category = "Fun" - set name = "Add Custom AI law" - - if(!check_rights(R_ADMIN)) - return - - var/input = input(usr, "Please enter anything you want the AI to do. Anything. Serious.", "What?", "") as text|null - if(!input) - return - - log_admin("Admin [key_name(usr)] has added a new AI law - [input]") - message_admins("Admin [key_name_admin(usr)] has added a new AI law - [input]") - - var/show_log = alert(src, "Show ion message?", "Message", "Yes", "No") - var/announce_ion_laws = (show_log == "Yes" ? 1 : -1) - - var/datum/round_event/ion_storm/add_law_only/ion = new() - ion.announceEvent = announce_ion_laws - ion.ionMessage = input - - SSblackbox.record_feedback("tally", "admin_verb", 1, "Add Custom AI Law") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/cmd_admin_rejuvenate(mob/living/M in GLOB.mob_list) - set category = "Special Verbs" - set name = "Rejuvenate" - - if(!check_rights(R_ADMIN)) - return - - if(!mob) - return - if(!istype(M)) - alert("Cannot revive a ghost") - return - M.revive(full_heal = 1, admin_revive = 1) - - log_admin("[key_name(usr)] healed / revived [key_name(M)]") - var/msg = "Admin [key_name_admin(usr)] healed / revived [ADMIN_LOOKUPFLW(M)]!" - message_admins(msg) - admin_ticket_log(M, msg) - SSblackbox.record_feedback("tally", "admin_verb", 1, "Rejuvinate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/cmd_admin_create_centcom_report() - set category = "Special Verbs" - set name = "Create Command Report" - - if(!check_rights(R_ADMIN)) - return - - var/input = input(usr, "Enter a Command Report. Ensure it makes sense IC.", "What?", "") as message|null - if(!input) - return - - var/confirm = alert(src, "Do you want to announce the contents of the report to the crew?", "Announce", "Yes", "No", "Cancel") - var/announce_command_report = TRUE - switch(confirm) - if("Yes") - priority_announce(input, null, 'sound/ai/commandreport.ogg') - announce_command_report = FALSE - if("Cancel") - return - - print_command_report(input, "[announce_command_report ? "Classified " : ""][command_name()] Update", announce_command_report) - - log_admin("[key_name(src)] has created a command report: [input]") - message_admins("[key_name_admin(src)] has created a command report") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Create Command Report") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/cmd_change_command_name() - set category = "Special Verbs" - set name = "Change Command Name" - - if(!check_rights(R_ADMIN)) - return - - var/input = input(usr, "Please input a new name for Central Command.", "What?", "") as text|null - if(!input) - return - change_command_name(input) - message_admins("[key_name_admin(src)] has changed Central Command's name to [input]") - log_admin("[key_name(src)] has changed the Central Command name to: [input]") - -/client/proc/cmd_admin_delete(atom/A as obj|mob|turf in world) - set category = "Admin" - set name = "Delete" - - if(!check_rights(R_SPAWN|R_DEBUG)) - return - - admin_delete(A) - -/client/proc/admin_delete(datum/D) - var/atom/A = D - var/coords = "" - var/jmp_coords = "" - if(istype(A)) - var/turf/T = get_turf(A) - if(T) - coords = "at [COORD(T)]" - jmp_coords = "at [ADMIN_COORDJMP(T)]" - else - jmp_coords = coords = "in nullspace" - - if (alert(src, "Are you sure you want to delete:\n[D]\n[coords]?", "Confirmation", "Yes", "No") == "Yes") - log_admin("[key_name(usr)] deleted [D] [coords]") - message_admins("[key_name_admin(usr)] deleted [D] [jmp_coords]") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Delete") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - if(isturf(D)) - var/turf/T = D - T.ScrapeAway() - else - vv_update_display(D, "deleted", VV_MSG_DELETED) - qdel(D) - if(!QDELETED(D)) - vv_update_display(D, "deleted", "") - -/client/proc/cmd_admin_list_open_jobs() - set category = "Admin" - set name = "Manage Job Slots" - - if(!check_rights(R_ADMIN)) - return - holder.manage_free_slots() - SSblackbox.record_feedback("tally", "admin_verb", 1, "Manage Job Slots") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/cmd_admin_explosion(atom/O as obj|mob|turf in world) - set category = "Special Verbs" - set name = "Explosion" - - if(!check_rights(R_ADMIN)) - return - - var/devastation = input("Range of total devastation. -1 to none", text("Input")) as num|null - if(devastation == null) - return - var/heavy = input("Range of heavy impact. -1 to none", text("Input")) as num|null - if(heavy == null) - return - var/light = input("Range of light impact. -1 to none", text("Input")) as num|null - if(light == null) - return - var/flash = input("Range of flash. -1 to none", text("Input")) as num|null - if(flash == null) - return - var/flames = input("Range of flames. -1 to none", text("Input")) as num|null - if(flames == null) - return - - if ((devastation != -1) || (heavy != -1) || (light != -1) || (flash != -1) || (flames != -1)) - if ((devastation > 20) || (heavy > 20) || (light > 20) || (flames > 20)) - if (alert(src, "Are you sure you want to do this? It will laaag.", "Confirmation", "Yes", "No") == "No") - return - - explosion(O, devastation, heavy, light, flash, null, null,flames) - log_admin("[key_name(usr)] created an explosion ([devastation],[heavy],[light],[flames]) at [AREACOORD(O)]") - message_admins("[key_name_admin(usr)] created an explosion ([devastation],[heavy],[light],[flames]) at [AREACOORD(O)]") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Explosion") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - return - else - return - -/client/proc/cmd_admin_emp(atom/O as obj|mob|turf in world) - set category = "Special Verbs" - set name = "EM Pulse" - - if(!check_rights(R_ADMIN)) - return - - var/heavy = input("Range of heavy pulse.", text("Input")) as num|null - if(heavy == null) - return - var/light = input("Range of light pulse.", text("Input")) as num|null - if(light == null) - return - - if (heavy || light) - - empulse(O, heavy, light) - log_admin("[key_name(usr)] created an EM Pulse ([heavy],[light]) at [AREACOORD(O)]") - message_admins("[key_name_admin(usr)] created an EM Pulse ([heavy],[light]) at [AREACOORD(O)]") - SSblackbox.record_feedback("tally", "admin_verb", 1, "EM Pulse") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - - return - else - return - -/client/proc/cmd_admin_gib(mob/M in GLOB.mob_list) - set category = "Special Verbs" - set name = "Gib" - - if(!check_rights(R_ADMIN)) - return - - var/confirm = alert(src, "Drop a brain?", "Confirm", "Yes", "No","Cancel") - if(confirm == "Cancel") - return - //Due to the delay here its easy for something to have happened to the mob - if(!M) - return - - log_admin("[key_name(usr)] has gibbed [key_name(M)]") - message_admins("[key_name_admin(usr)] has gibbed [key_name_admin(M)]") - - if(isobserver(M)) - new /obj/effect/gibspawner/generic(get_turf(M)) - return - if(confirm == "Yes") - M.gib() - else - M.gib(1) - SSblackbox.record_feedback("tally", "admin_verb", 1, "Gib") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/cmd_admin_gib_self() - set name = "Gibself" - set category = "Fun" - - var/confirm = alert(src, "You sure?", "Confirm", "Yes", "No") - if(confirm == "Yes") - log_admin("[key_name(usr)] used gibself.") - message_admins("[key_name_admin(usr)] used gibself.") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Gib Self") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - mob.gib(1, 1, 1) - -/client/proc/cmd_admin_check_contents(mob/living/M in GLOB.mob_list) - set category = "Special Verbs" - set name = "Check Contents" - - var/list/L = M.get_contents() - for(var/t in L) - to_chat(usr, "[t]") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Check Contents") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/toggle_view_range() - set category = "Special Verbs" - set name = "Change View Range" - set desc = "switches between 1x and custom views" - - if(view == CONFIG_GET(string/default_view)) - change_view(input("Select view range:", "FUCK YE", 7) in list(1,2,3,4,5,6,7,8,9,10,11,12,13,14,128)) - else - change_view(CONFIG_GET(string/default_view)) - - log_admin("[key_name(usr)] changed their view range to [view].") - //message_admins("\blue [key_name_admin(usr)] changed their view range to [view].") //why? removed by order of XSI - - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Change View Range", "[view]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/admin_call_shuttle() - - set category = "Admin" - set name = "Call Shuttle" - - if(EMERGENCY_AT_LEAST_DOCKED) - return - - if(!check_rights(R_ADMIN)) - return - - var/confirm = alert(src, "You sure?", "Confirm", "Yes", "No") - if(confirm != "Yes") - return - - SSshuttle.emergency.request() - SSblackbox.record_feedback("tally", "admin_verb", 1, "Call Shuttle") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - log_admin("[key_name(usr)] admin-called the emergency shuttle.") - message_admins("[key_name_admin(usr)] admin-called the emergency shuttle.") - return - -/client/proc/admin_cancel_shuttle() - set category = "Admin" - set name = "Cancel Shuttle" - if(!check_rights(0)) - return - if(alert(src, "You sure?", "Confirm", "Yes", "No") != "Yes") - return - - if(EMERGENCY_AT_LEAST_DOCKED) - return - - SSshuttle.emergency.cancel() - SSblackbox.record_feedback("tally", "admin_verb", 1, "Cancel Shuttle") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - log_admin("[key_name(usr)] admin-recalled the emergency shuttle.") - message_admins("[key_name_admin(usr)] admin-recalled the emergency shuttle.") - - return - -/client/proc/everyone_random() - set category = "Fun" - set name = "Make Everyone Random" - set desc = "Make everyone have a random appearance. You can only use this before rounds!" - - if(SSticker.HasRoundStarted()) - to_chat(usr, "Nope you can't do this, the game's already started. This only works before rounds!") - return - - var/frn = CONFIG_GET(flag/force_random_names) - if(frn) - CONFIG_SET(flag/force_random_names, FALSE) - message_admins("Admin [key_name_admin(usr)] has disabled \"Everyone is Special\" mode.") - to_chat(usr, "Disabled.") - return - - - var/notifyplayers = alert(src, "Do you want to notify the players?", "Options", "Yes", "No", "Cancel") - if(notifyplayers == "Cancel") - return - - log_admin("Admin [key_name(src)] has forced the players to have random appearances.") - message_admins("Admin [key_name_admin(usr)] has forced the players to have random appearances.") - - if(notifyplayers == "Yes") - to_chat(world, "Admin [usr.key] has forced the players to have completely random identities!") - - to_chat(usr, "Remember: you can always disable the randomness by using the verb again, assuming the round hasn't started yet.") - - CONFIG_SET(flag/force_random_names, TRUE) - SSblackbox.record_feedback("tally", "admin_verb", 1, "Make Everyone Random") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - - -/client/proc/toggle_random_events() - set category = "Server" - set name = "Toggle random events on/off" - set desc = "Toggles random events such as meteors, black holes, blob (but not space dust) on/off" - var/new_are = !CONFIG_GET(flag/allow_random_events) - CONFIG_SET(flag/allow_random_events, new_are) - if(new_are) - to_chat(usr, "Random events enabled") - message_admins("Admin [key_name_admin(usr)] has enabled random events.") - else - to_chat(usr, "Random events disabled") - message_admins("Admin [key_name_admin(usr)] has disabled random events.") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Random Events", "[new_are ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - - -/client/proc/admin_change_sec_level() - set category = "Special Verbs" - set name = "Set Security Level" - set desc = "Changes the security level. Announcement only, i.e. setting to Delta won't activate nuke" - - if(!check_rights(R_ADMIN)) - return - - var/level = input("Select security level to change to","Set Security Level") as null|anything in list("green","blue","amber","red","delta") - if(level) - set_security_level(level) - - log_admin("[key_name(usr)] changed the security level to [level]") - message_admins("[key_name_admin(usr)] changed the security level to [level]") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Set Security Level [capitalize(level)]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/toggle_nuke(obj/machinery/nuclearbomb/N in GLOB.nuke_list) - set name = "Toggle Nuke" - set category = "Fun" - set popup_menu = 0 - if(!check_rights(R_DEBUG)) - return - - if(!N.timing) - var/newtime = input(usr, "Set activation timer.", "Activate Nuke", "[N.timer_set]") as num|null - if(!newtime) - return - N.timer_set = newtime - N.set_safety() - N.set_active() - - log_admin("[key_name(usr)] [N.timing ? "activated" : "deactivated"] a nuke at [AREACOORD(N)].") - message_admins("[ADMIN_LOOKUPFLW(usr)] [N.timing ? "activated" : "deactivated"] a nuke at [ADMIN_VERBOSEJMP(N)].") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Nuke", "[N.timing]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits - -/client/proc/create_outfits() - set category = "Debug" - set name = "Create Custom Outfit" - - if(!check_rights(R_DEBUG)) - return - - holder.create_outfit() - -/datum/admins/proc/create_outfit() - var/list/uniforms = typesof(/obj/item/clothing/under) - var/list/suits = typesof(/obj/item/clothing/suit) - var/list/gloves = typesof(/obj/item/clothing/gloves) - var/list/shoes = typesof(/obj/item/clothing/shoes) - var/list/headwear = typesof(/obj/item/clothing/head) - var/list/glasses = typesof(/obj/item/clothing/glasses) - var/list/masks = typesof(/obj/item/clothing/mask) - var/list/ids = typesof(/obj/item/card/id) - - var/uniform_select = "" - - var/suit_select = "" - - var/gloves_select = "" - - var/shoes_select = "" - - var/head_select = "" - - var/glasses_select = "" - - var/mask_select = "" - - var/id_select = "" - - var/dat = {" - Create Outfit -
- - [HrefTokenFormField()] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Name: - -
Uniform: - [uniform_select] -
Suit: - [suit_select] -
Back: - -
Belt: - -
Gloves: - [gloves_select] -
Shoes: - [shoes_select] -
Head: - [head_select] -
Mask: - [mask_select] -
Ears: - -
Glasses: - [glasses_select] -
ID: - [id_select] -
Left Pocket: - -
Right Pocket: - -
Suit Store: - -
Right Hand: - -
Left Hand: - -
-
- -
- "} - usr << browse(dat, "window=dressup;size=550x600") - -/client/proc/toggle_combo_hud() - set category = "Admin" - set name = "Toggle Combo HUD" - set desc = "Toggles the Admin Combo HUD (antag, sci, med, eng)" - - if(!check_rights(R_ADMIN)) - return - - var/adding_hud = !has_antag_hud() - - for(var/hudtype in list(DATA_HUD_SECURITY_ADVANCED, DATA_HUD_MEDICAL_ADVANCED, DATA_HUD_DIAGNOSTIC_ADVANCED)) // add data huds - var/datum/atom_hud/H = GLOB.huds[hudtype] - (adding_hud) ? H.add_hud_to(usr) : H.remove_hud_from(usr) - for(var/datum/atom_hud/antag/H in GLOB.huds) // add antag huds - (adding_hud) ? H.add_hud_to(usr) : H.remove_hud_from(usr) - - if(prefs.toggles & COMBOHUD_LIGHTING) - if(adding_hud) - mob.lighting_alpha = LIGHTING_PLANE_ALPHA_INVISIBLE - else - mob.lighting_alpha = initial(mob.lighting_alpha) - - mob.update_sight() - - to_chat(usr, "You toggled your admin combo HUD [adding_hud ? "ON" : "OFF"].") - message_admins("[key_name_admin(usr)] toggled their admin combo HUD [adding_hud ? "ON" : "OFF"].") - log_admin("[key_name(usr)] toggled their admin combo HUD [adding_hud ? "ON" : "OFF"].") - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Combo HUD", "[adding_hud ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - - -/client/proc/has_antag_hud() - var/datum/atom_hud/A = GLOB.huds[ANTAG_HUD_TRAITOR] - return A.hudusers[mob] - -/client/proc/open_shuttle_manipulator() - set category = "Admin" - set name = "Shuttle Manipulator" - set desc = "Opens the shuttle manipulator UI." - - for(var/obj/machinery/shuttle_manipulator/M in GLOB.machines) - M.ui_interact(usr) - -/client/proc/run_weather() - set category = "Fun" - set name = "Run Weather" - set desc = "Triggers a weather on the z-level you choose." - - if(!holder) - return - - var/weather_type = input("Choose a weather", "Weather") as null|anything in subtypesof(/datum/weather) - if(!weather_type) - return - - var/z_level = input("Z-Level to target? Leave blank to target current Z-Level.", "Z-Level") as num|null - if(!isnum(z_level)) - if(!src.mob) - return - z_level = src.mob.z - - SSweather.run_weather(weather_type, z_level) - - message_admins("[key_name_admin(usr)] started weather of type [weather_type] on the z-level [z_level].") - log_admin("[key_name(usr)] started weather of type [weather_type] on the z-level [z_level].") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Run Weather") - -/client/proc/mass_zombie_infection() - set category = "Fun" - set name = "Mass Zombie Infection" - set desc = "Infects all humans with a latent organ that will zombify \ - them on death." - - if(!check_rights(R_ADMIN)) - return - - var/confirm = alert(src, "Please confirm you want to add latent zombie organs in all humans?", "Confirm Zombies", "Yes", "No") - if(confirm != "Yes") - return - - for(var/mob/living/carbon/human/H in GLOB.carbon_list) - new /obj/item/organ/zombie_infection/nodamage(H) - - message_admins("[key_name_admin(usr)] added a latent zombie infection to all humans.") - log_admin("[key_name(usr)] added a latent zombie infection to all humans.") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Mass Zombie Infection") - -/client/proc/mass_zombie_cure() - set category = "Fun" - set name = "Mass Zombie Cure" - set desc = "Removes the zombie infection from all humans, returning them to normal." - if(!check_rights(R_ADMIN)) - return - - var/confirm = alert(src, "Please confirm you want to cure all zombies?", "Confirm Zombie Cure", "Yes", "No") - if(confirm != "Yes") - return - - for(var/obj/item/organ/zombie_infection/nodamage/I in GLOB.zombie_infection_list) - qdel(I) - - message_admins("[key_name_admin(usr)] cured all zombies.") - log_admin("[key_name(usr)] cured all zombies.") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Mass Zombie Cure") - -/client/proc/polymorph_all() - set category = "Fun" - set name = "Polymorph All" - set desc = "Applies the effects of the bolt of change to every single mob." - - if(!check_rights(R_ADMIN)) - return - - var/confirm = alert(src, "Please confirm you want polymorph all mobs?", "Confirm Polymorph", "Yes", "No") - if(confirm != "Yes") - return - - var/list/mobs = shuffle(GLOB.alive_mob_list.Copy()) // might change while iterating - var/who_did_it = key_name_admin(usr) - - message_admins("[key_name_admin(usr)] started polymorphed all living mobs.") - log_admin("[key_name(usr)] polymorphed all living mobs.") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Polymorph All") - - for(var/mob/living/M in mobs) - CHECK_TICK - - if(!M) - continue - - M.audible_message("...wabbajack...wabbajack...") - playsound(M.loc, 'sound/magic/staff_change.ogg', 50, 1, -1) - - wabbajack(M) - - message_admins("Mass polymorph started by [who_did_it] is complete.") - - -/client/proc/show_tip() - set category = "Admin" - set name = "Show Tip" - set desc = "Sends a tip (that you specify) to all players. After all \ - you're the experienced player here." - - if(!check_rights(R_ADMIN)) - return - - var/input = input(usr, "Please specify your tip that you want to send to the players.", "Tip", "") as message|null - if(!input) - return - - if(!SSticker) - return - - SSticker.selected_tip = input - - // If we've already tipped, then send it straight away. - if(SSticker.tipped) - SSticker.send_tip_of_the_round() - - - message_admins("[key_name_admin(usr)] sent a tip of the round.") - log_admin("[key_name(usr)] sent \"[input]\" as the Tip of the Round.") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Tip") - -/client/proc/modify_goals() - set category = "Debug" - set name = "Modify goals" - - if(!check_rights(R_ADMIN)) - return - - holder.modify_goals() - -/datum/admins/proc/modify_goals() - var/dat = "" - for(var/datum/station_goal/S in SSticker.mode.station_goals) - dat += "[S.name] - Announce | Remove
" - dat += "
Add New Goal" - usr << browse(dat, "window=goals;size=400x400") - - -/client/proc/toggle_hub() - set category = "Server" - set name = "Toggle Hub" - - world.update_hub_visibility(!GLOB.hub_visibility) - - log_admin("[key_name(usr)] has toggled the server's hub status for the round, it is now [(GLOB.hub_visibility?"on":"off")] the hub.") - message_admins("[key_name_admin(usr)] has toggled the server's hub status for the round, it is now [(GLOB.hub_visibility?"on":"off")] the hub.") - if (GLOB.hub_visibility && !world.reachable) - message_admins("WARNING: The server will not show up on the hub because byond is detecting that a filewall is blocking incoming connections.") - - SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggled Hub Visibility", "[GLOB.hub_visibility ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/breadify(atom/movable/target) - var/obj/item/reagent_containers/food/snacks/store/bread/plain/funnyBread = new(get_turf(target)) - target.forceMove(funnyBread) - -/client/proc/smite(mob/living/carbon/human/target as mob) - set name = "Smite" - set category = "Fun" - if(!check_rights(R_ADMIN) || !check_rights(R_FUN)) - return - - var/list/punishment_list = list(ADMIN_PUNISHMENT_PIE, - ADMIN_PUNISHMENT_FIREBALL, - ADMIN_PUNISHMENT_CLUWNE, - ADMIN_PUNISHMENT_LIGHTNING, - ADMIN_PUNISHMENT_BRAINDAMAGE, - ADMIN_PUNISHMENT_BSA, - ADMIN_PUNISHMENT_GIB, - ADMIN_PUNISHMENT_SUPPLYPOD, - ADMIN_PUNISHMENT_MAZING, - ADMIN_PUNISHMENT_ROD, - ADMIN_PUNISHMENT_TABLETIDESTATIONWIDE, - ADMIN_PUNISHMENT_FAKEBWOINK, - ADMIN_PUNISHMENT_NUGGET, - ADMIN_PUNISHMENT_BREADIFY) - - var/punishment = input("Choose a punishment", "DIVINE SMITING") as null|anything in punishment_list - - if(QDELETED(target) || !punishment) - return - - switch(punishment) - if(ADMIN_PUNISHMENT_LIGHTNING) - var/turf/T = get_step(get_step(target, NORTH), NORTH) - T.Beam(target, icon_state="lightning[rand(1,12)]", time = 5) - target.adjustFireLoss(75) - target.electrocution_animation(40) - to_chat(target, "The gods have punished you for your sins!") - if(ADMIN_PUNISHMENT_BRAINDAMAGE) - target.adjustOrganLoss(ORGAN_SLOT_BRAIN, 199, 199) - if(ADMIN_PUNISHMENT_GIB) - target.gib(FALSE) - if(ADMIN_PUNISHMENT_BSA) - bluespace_artillery(target) - if(ADMIN_PUNISHMENT_FIREBALL) - new /obj/effect/temp_visual/target(get_turf(target)) - if(ADMIN_PUNISHMENT_CLUWNE) - var/mob/living/simple_animal/hostile/floor_cluwne/FC = new /mob/living/simple_animal/hostile/floor_cluwne(get_turf(target)) - FC.smite = TRUE - FC.forced = TRUE - FC.Acquire_Victim(target) - FC.target = target - FC.current_victim = target - FC.interest = 5000 - FC.maxHealth = 5000 - FC.health = 5000 - if(ADMIN_PUNISHMENT_ROD) - var/turf/T = get_turf(target) - var/startside = pick(GLOB.cardinals) - var/turf/startT = spaceDebrisStartLoc(startside, T.z) - var/turf/endT = spaceDebrisFinishLoc(startside, T.z) - new /obj/effect/immovablerod(startT, endT,target) - if(ADMIN_PUNISHMENT_SUPPLYPOD) - var/datum/centcom_podlauncher/plaunch = new(usr) - if(!holder) - return - plaunch.specificTarget = target - plaunch.launchChoice = 0 - plaunch.damageChoice = 1 - plaunch.explosionChoice = 1 - plaunch.temp_pod.damage = 40//bring the mother fuckin ruckus - plaunch.temp_pod.explosionSize = list(0,0,0,2) - plaunch.temp_pod.effectStun = TRUE - plaunch.ui_interact(usr) - if(ADMIN_PUNISHMENT_MAZING) - if(!puzzle_imprison(target)) - to_chat(usr,"Imprisonment failed!") - return - if(ADMIN_PUNISHMENT_PIE) - var/obj/item/reagent_containers/food/snacks/pie/cream/nostun/creamy = new(get_turf(target)) - creamy.splat(target) - if(ADMIN_PUNISHMENT_TABLETIDESTATIONWIDE) - priority_announce(html_decode("[target] has brought the wrath of the gods upon themselves and is now being tableslammed across the station. Please stand by."), null, 'sound/misc/announce.ogg', "CentCom") - var/list/areas = list() - for(var/area/A in world) - if(A.z == SSmapping.station_start) - areas += A - SEND_SOUND(target, sound('hyperstation/sound/misc/slamofthenorthstar.ogg',volume=60)) - for(var/area/A in areas) - for(var/obj/structure/table/T in A) - T.tablepush(target, target) - sleep(1) - if(ADMIN_PUNISHMENT_FAKEBWOINK) - SEND_SOUND(target, 'sound/effects/adminhelp.ogg') - if(ADMIN_PUNISHMENT_NUGGET) - if (!iscarbon(target)) - return - var/mob/living/carbon/carbon_target = target - var/timer = 2 SECONDS - for (var/_limb in carbon_target.bodyparts) - var/obj/item/bodypart/limb = _limb - if (limb.body_part == HEAD || limb.body_part == CHEST) - continue - addtimer(CALLBACK(limb, /obj/item/bodypart/.proc/dismember), timer) - addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, carbon_target, 'sound/effects/cartoon_pop.ogg', 70), timer) - addtimer(CALLBACK(carbon_target, /mob/living/.proc/spin, 4, 1), timer - 0.4 SECONDS) - timer += 2 SECONDS - if(ADMIN_PUNISHMENT_BREADIFY) - #define BREADIFY_TIME (5 SECONDS) - var/mutable_appearance/bread_appearance = mutable_appearance('icons/obj/food/burgerbread.dmi', "bread") - var/mutable_appearance/transform_scanline = mutable_appearance('icons/effects/effects.dmi', "transform_effect") - target.transformation_animation(bread_appearance, time = BREADIFY_TIME, transform_overlay=transform_scanline, reset_after=TRUE) - addtimer(CALLBACK(GLOBAL_PROC, .proc/breadify, target), BREADIFY_TIME) - #undef BREADIFY_TIME - - - var/msg = "[key_name_admin(usr)] punished [key_name_admin(target)] with [punishment]." - message_admins(msg) - admin_ticket_log(target, msg) - log_admin("[key_name(usr)] punished [key_name(target)] with [punishment].") - - -/client/proc/trigger_centcom_recall() - if(!check_rights(R_ADMIN)) - return - var/message = pick(GLOB.admiral_messages) - message = input("Enter message from the on-call admiral to be put in the recall report.", "Admiral Message", message) as text|null - - if(!message) - return - - message_admins("[key_name_admin(usr)] triggered a CentCom recall, with the admiral message of: [message]") - log_game("[key_name(usr)] triggered a CentCom recall, with the message of: [message]") - SSshuttle.centcom_recall(SSshuttle.emergency.timer, message) - -/client/proc/cmd_admin_check_player_exp() //Allows admins to determine who the newer players are. - set category = "Admin" - set name = "Player Playtime" - if(!check_rights(R_ADMIN)) - return - - if(!CONFIG_GET(flag/use_exp_tracking)) - to_chat(usr, "Tracking is disabled in the server configuration file.") - return - - var/list/msg = list() - msg += "Playtime ReportPlaytime:
" - src << browse(msg.Join(), "window=Player_playtime_check") - -/datum/admins/proc/cmd_show_exp_panel(client/C) - if(!check_rights(R_ADMIN)) - return - if(!C) - to_chat(usr, "ERROR: Client not found.") - return - if(!CONFIG_GET(flag/use_exp_tracking)) - to_chat(usr, "Tracking is disabled in the server configuration file.") - return - - var/list/body = list() - body += "Playtime for [C.key]
Playtime:" - body += C.get_exp_report() - body += "Toggle Exempt status" - body += "" - usr << browse(body.Join(), "window=playerplaytime[C.ckey];size=550x615") - -/datum/admins/proc/toggle_exempt_status(client/C) - if(!check_rights(R_ADMIN)) - return - if(!C) - to_chat(usr, "ERROR: Client not found.") - return - - if(!C.set_db_player_flags()) - to_chat(usr, "ERROR: Unable read player flags from database. Please check logs.") - var/dbflags = C.prefs.db_flags - var/newstate = FALSE - if(dbflags & DB_FLAG_EXEMPT) - newstate = FALSE - else - newstate = TRUE - - if(C.update_flag_db(DB_FLAG_EXEMPT, newstate)) - to_chat(usr, "ERROR: Unable to update player flags. Please check logs.") - else - message_admins("[key_name_admin(usr)] has [newstate ? "activated" : "deactivated"] job exp exempt status on [key_name_admin(C)]") - log_admin("[key_name(usr)] has [newstate ? "activated" : "deactivated"] job exp exempt status on [key_name(C)]") +/client/proc/cmd_admin_drop_everything(mob/M in GLOB.mob_list) + set category = null + set name = "Drop Everything" + if(!check_rights(R_ADMIN)) + return + + var/confirm = alert(src, "Make [M] drop everything?", "Message", "Yes", "No") + if(confirm != "Yes") + return + + for(var/obj/item/W in M) + if(!M.dropItemToGround(W)) + qdel(W) + M.regenerate_icons() + + log_admin("[key_name(usr)] made [key_name(M)] drop everything!") + var/msg = "[key_name_admin(usr)] made [ADMIN_LOOKUPFLW(M)] drop everything!" + message_admins(msg) + admin_ticket_log(M, msg) + SSblackbox.record_feedback("tally", "admin_verb", 1, "Drop Everything") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_subtle_message(mob/M in GLOB.mob_list) + set category = "Special Verbs" + set name = "Subtle Message" + + if(!ismob(M)) + return + if(!check_rights(R_ADMIN)) + return + + message_admins("[key_name_admin(src)] has started answering [ADMIN_LOOKUPFLW(M)]'s prayer.") + var/msg = input("Message:", text("Subtle PM to [M.key]")) as text|null + + if (!msg) + message_admins("[key_name_admin(src)] decided not to answer [ADMIN_LOOKUPFLW(M)]'s prayer") + return + if(usr) + if (usr.client) + if(usr.client.holder) + to_chat(M, "You hear a voice in your head... [msg]") + + log_admin("SubtlePM: [key_name(usr)] -> [key_name(M)] : [msg]") + msg = " SubtleMessage: [key_name_admin(usr)] -> [key_name_admin(M)] : [msg]" + message_admins(msg) + admin_ticket_log(M, msg) + SSblackbox.record_feedback("tally", "admin_verb", 1, "Subtle Message") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_headset_message(mob/M in GLOB.mob_list) + set category = "Special Verbs" + set name = "Headset Message" + + admin_headset_message(M) + +/client/proc/admin_headset_message(mob/M in GLOB.mob_list, sender = null) + var/mob/living/carbon/human/H = M + + if(!check_rights(R_ADMIN)) + return + + if(!istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + return + if(!istype(H.ears, /obj/item/radio/headset)) + to_chat(usr, "The person you are trying to contact is not wearing a headset.") + return + + if (!sender) + sender = input("Who is the message from?", "Sender") as null|anything in list(RADIO_CHANNEL_CENTCOM,RADIO_CHANNEL_SYNDICATE) + if(!sender) + return + + message_admins("[key_name_admin(src)] has started answering [key_name_admin(H)]'s [sender] request.") + var/input = input("Please enter a message to reply to [key_name(H)] via their headset.","Outgoing message from [sender]", "") as text|null + if(!input) + message_admins("[key_name_admin(src)] decided not to answer [key_name_admin(H)]'s [sender] request.") + return + + log_directed_talk(src, H, input, LOG_ADMIN, "reply") + message_admins("[key_name_admin(src)] replied to [key_name_admin(H)]'s [sender] message with: \"[input]\"") + to_chat(H, "You hear something crackle in your ears for a moment before a voice speaks. \"Please stand by for a message from [sender == "Syndicate" ? "your benefactor" : "Central Command"]. Message as follows[sender == "Syndicate" ? ", agent." : ":"] [input]. Message ends.\"") + + SSblackbox.record_feedback("tally", "admin_verb", 1, "Headset Message") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_mod_antag_rep(client/C in GLOB.clients, var/operation) + set category = "Special Verbs" + set name = "Modify Antagonist Reputation" + + if(!check_rights(R_ADMIN)) + return + + var/msg = "" + var/log_text = "" + + if(operation == "zero") + log_text = "Set to 0" + SSpersistence.antag_rep -= C.ckey + else + var/prompt = "Please enter the amount of reputation to [operation]:" + + if(operation == "set") + prompt = "Please enter the new reputation value:" + + msg = input("Message:", prompt) as num|null + + if (!msg) + return + + var/ANTAG_REP_MAXIMUM = CONFIG_GET(number/antag_rep_maximum) + + if(operation == "set") + log_text = "Set to [num2text(msg)]" + SSpersistence.antag_rep[C.ckey] = max(0, min(msg, ANTAG_REP_MAXIMUM)) + else if(operation == "add") + log_text = "Added [num2text(msg)]" + SSpersistence.antag_rep[C.ckey] = min(SSpersistence.antag_rep[C.ckey]+msg, ANTAG_REP_MAXIMUM) + else if(operation == "subtract") + log_text = "Subtracted [num2text(msg)]" + SSpersistence.antag_rep[C.ckey] = max(SSpersistence.antag_rep[C.ckey]-msg, 0) + else + to_chat(src, "Invalid operation for antag rep modification: [operation] by user [key_name(usr)]") + return + + if(SSpersistence.antag_rep[C.ckey] <= 0) + SSpersistence.antag_rep -= C.ckey + + log_admin("[key_name(usr)]: Modified [key_name(C)]'s antagonist reputation [log_text]") + message_admins("[key_name_admin(usr)]: Modified [key_name(C)]'s antagonist reputation ([log_text])") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Modify Antagonist Reputation") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_world_narrate() + set category = "Special Verbs" + set name = "Global Narrate" + + if(!check_rights(R_ADMIN)) + return + + var/msg = input("Message:", text("Enter the text you wish to appear to everyone:")) as text|null + + if (!msg) + return + to_chat(world, "[msg]") + log_admin("GlobalNarrate: [key_name(usr)] : [msg]") + message_admins("[key_name_admin(usr)] Sent a global narrate") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Global Narrate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_direct_narrate(mob/M) + set category = "Special Verbs" + set name = "Direct Narrate" + + if(!check_rights(R_ADMIN)) + return + + if(!M) + M = input("Direct narrate to whom?", "Active Players") as null|anything in GLOB.player_list + + if(!M) + return + + var/msg = input("Message:", text("Enter the text you wish to appear to your target:")) as text|null + + if( !msg ) + return + + to_chat(M, msg) + log_admin("DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]") + msg = " DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]
" + message_admins(msg) + admin_ticket_log(M, msg) + SSblackbox.record_feedback("tally", "admin_verb", 1, "Direct Narrate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_local_narrate(atom/A) + set category = "Special Verbs" + set name = "Local Narrate" + + if(!check_rights(R_ADMIN)) + return + if(!A) + return + var/range = input("Range:", "Narrate to mobs within how many tiles:", 7) as num|null + if(!range) + return + var/msg = input("Message:", text("Enter the text you wish to appear to everyone within view:")) as text|null + if (!msg) + return + for(var/mob/M in view(range,A)) + to_chat(M, msg) + + log_admin("LocalNarrate: [key_name(usr)] at [AREACOORD(A)]: [msg]") + message_admins(" LocalNarrate: [key_name_admin(usr)] at [ADMIN_VERBOSEJMP(A)]: [msg]
") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Local Narrate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_godmode(mob/M in GLOB.mob_list) + set category = "Special Verbs" + set name = "Godmode" + if(!check_rights(R_ADMIN)) + return + + M.status_flags ^= GODMODE + to_chat(usr, "Toggled [(M.status_flags & GODMODE) ? "ON" : "OFF"]") + + log_admin("[key_name(usr)] has toggled [key_name(M)]'s nodamage to [(M.status_flags & GODMODE) ? "On" : "Off"]") + var/msg = "[key_name_admin(usr)] has toggled [ADMIN_LOOKUPFLW(M)]'s nodamage to [(M.status_flags & GODMODE) ? "On" : "Off"]" + message_admins(msg) + admin_ticket_log(M, msg) + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Godmode", "[M.status_flags & GODMODE ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +/proc/cmd_admin_mute(whom, mute_type, automute = 0) + if(!whom) + return + + var/muteunmute + var/mute_string + var/feedback_string + switch(mute_type) + if(MUTE_IC) + mute_string = "IC (say and emote)" + feedback_string = "IC" + if(MUTE_OOC) + mute_string = "OOC" + feedback_string = "OOC" + if(MUTE_PRAY) + mute_string = "pray" + feedback_string = "Pray" + if(MUTE_ADMINHELP) + mute_string = "adminhelp, admin PM and ASAY" + feedback_string = "Adminhelp" + if(MUTE_DEADCHAT) + mute_string = "deadchat and DSAY" + feedback_string = "Deadchat" + if(MUTE_ALL) + mute_string = "everything" + feedback_string = "Everything" + else + return + + var/client/C + if(istype(whom, /client)) + C = whom + else if(istext(whom)) + C = GLOB.directory[whom] + else + return + + var/datum/preferences/P + if(C) + P = C.prefs + else + P = GLOB.preferences_datums[whom] + if(!P) + return + + if(automute) + if(!CONFIG_GET(flag/automute_on)) + return + else + if(!check_rights()) + return + + if(automute) + muteunmute = "auto-muted" + P.muted |= mute_type + log_admin("SPAM AUTOMUTE: [muteunmute] [key_name(whom)] from [mute_string]") + message_admins("SPAM AUTOMUTE: [muteunmute] [key_name_admin(whom)] from [mute_string].") + if(C) + to_chat(C, "You have been [muteunmute] from [mute_string] by the SPAM AUTOMUTE system. Contact an admin.") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Auto Mute [feedback_string]", "1")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return + + if(P.muted & mute_type) + muteunmute = "unmuted" + P.muted &= ~mute_type + else + muteunmute = "muted" + P.muted |= mute_type + + log_admin("[key_name(usr)] has [muteunmute] [key_name(whom)] from [mute_string]") + message_admins("[key_name_admin(usr)] has [muteunmute] [key_name_admin(whom)] from [mute_string].") + if(C) + to_chat(C, "You have been [muteunmute] from [mute_string] by [key_name(usr, include_name = FALSE)].") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Mute [feedback_string]", "[P.muted & mute_type]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +//I use this proc for respawn character too. /N +/proc/create_xeno(ckey) + if(!ckey) + var/list/candidates = list() + for(var/mob/M in GLOB.player_list) + if(M.stat != DEAD) + continue //we are not dead! + if(!(ROLE_ALIEN in M.client.prefs.be_special)) + continue //we don't want to be an alium + if(M.client.is_afk()) + continue //we are afk + if(M.mind && M.mind.current && M.mind.current.stat != DEAD) + continue //we have a live body we are tied to + candidates += M.ckey + if(candidates.len) + ckey = input("Pick the player you want to respawn as a xeno.", "Suitable Candidates") as null|anything in candidates + else + to_chat(usr, "Error: create_xeno(): no suitable candidates.") + if(!istext(ckey)) + return 0 + + var/alien_caste = input(usr, "Please choose which caste to spawn.","Pick a caste",null) as null|anything in list("Queen","Praetorian","Hunter","Sentinel","Drone","Larva") + var/obj/effect/landmark/spawn_here = GLOB.xeno_spawn.len ? pick(GLOB.xeno_spawn) : null + var/mob/living/carbon/alien/new_xeno + switch(alien_caste) + if("Queen") + new_xeno = new /mob/living/carbon/alien/humanoid/royal/queen(spawn_here) + if("Praetorian") + new_xeno = new /mob/living/carbon/alien/humanoid/royal/praetorian(spawn_here) + if("Hunter") + new_xeno = new /mob/living/carbon/alien/humanoid/hunter(spawn_here) + if("Sentinel") + new_xeno = new /mob/living/carbon/alien/humanoid/sentinel(spawn_here) + if("Drone") + new_xeno = new /mob/living/carbon/alien/humanoid/drone(spawn_here) + if("Larva") + new_xeno = new /mob/living/carbon/alien/larva(spawn_here) + else + return 0 + if(!spawn_here) + SSjob.SendToLateJoin(new_xeno, FALSE) + + new_xeno.ckey = ckey + var/msg = "[key_name_admin(usr)] has spawned [ckey] as a filthy xeno [alien_caste]." + message_admins(msg) + admin_ticket_log(new_xeno, msg) + return 1 + +/* +If a guy was gibbed and you want to revive him, this is a good way to do so. +Works kind of like entering the game with a new character. Character receives a new mind if they didn't have one. +Traitors and the like can also be revived with the previous role mostly intact. +/N */ +/client/proc/respawn_character() + set category = "Special Verbs" + set name = "Respawn Character" + set desc = "Respawn a person that has been gibbed/dusted/killed. They must be a ghost for this to work and preferably should not have a body to go back into." + if(!check_rights(R_ADMIN)) + return + + var/input = ckey(input(src, "Please specify which key will be respawned.", "Key", "")) + if(!input) + return + + var/mob/dead/observer/G_found + for(var/mob/dead/observer/G in GLOB.player_list) + if(G.ckey == input) + G_found = G + break + + if(!G_found)//If a ghost was not found. + to_chat(usr, "There is no active key like that in the game or the person is not currently a ghost.") + return + + if(G_found.mind && !G_found.mind.active) //mind isn't currently in use by someone/something + //Check if they were an alien + if(G_found.mind.assigned_role == ROLE_ALIEN) + if(alert("This character appears to have been an alien. Would you like to respawn them as such?",,"Yes","No")=="Yes") + var/turf/T + if(GLOB.xeno_spawn.len) + T = pick(GLOB.xeno_spawn) + + var/mob/living/carbon/alien/new_xeno + switch(G_found.mind.special_role)//If they have a mind, we can determine which caste they were. + if("Hunter") + new_xeno = new /mob/living/carbon/alien/humanoid/hunter(T) + if("Sentinel") + new_xeno = new /mob/living/carbon/alien/humanoid/sentinel(T) + if("Drone") + new_xeno = new /mob/living/carbon/alien/humanoid/drone(T) + if("Praetorian") + new_xeno = new /mob/living/carbon/alien/humanoid/royal/praetorian(T) + if("Queen") + new_xeno = new /mob/living/carbon/alien/humanoid/royal/queen(T) + else//If we don't know what special role they have, for whatever reason, or they're a larva. + create_xeno(G_found.ckey) + return + + if(!T) + SSjob.SendToLateJoin(new_xeno, FALSE) + + //Now to give them their mind back. + G_found.mind.transfer_to(new_xeno) //be careful when doing stuff like this! I've already checked the mind isn't in use + new_xeno.key = G_found.key + to_chat(new_xeno, "You have been fully respawned. Enjoy the game.") + var/msg = "[key_name_admin(usr)] has respawned [new_xeno.key] as a filthy xeno." + message_admins(msg) + admin_ticket_log(new_xeno, msg) + return //all done. The ghost is auto-deleted + + //check if they were a monkey + else if(findtext(G_found.real_name,"monkey")) + if(alert("This character appears to have been a monkey. Would you like to respawn them as such?",,"Yes","No")=="Yes") + var/mob/living/carbon/monkey/new_monkey = new + SSjob.SendToLateJoin(new_monkey) + G_found.mind.transfer_to(new_monkey) //be careful when doing stuff like this! I've already checked the mind isn't in use + new_monkey.key = G_found.key + to_chat(new_monkey, "You have been fully respawned. Enjoy the game.") + var/msg = "[key_name_admin(usr)] has respawned [new_monkey.key] as a filthy xeno." + message_admins(msg) + admin_ticket_log(new_monkey, msg) + return //all done. The ghost is auto-deleted + + + //Ok, it's not a xeno or a monkey. So, spawn a human. + var/mob/living/carbon/human/new_character = new//The mob being spawned. + SSjob.SendToLateJoin(new_character) + + var/datum/data/record/record_found //Referenced to later to either randomize or not randomize the character. + if(G_found.mind && !G_found.mind.active) //mind isn't currently in use by someone/something + /*Try and locate a record for the person being respawned through GLOB.data_core. + This isn't an exact science but it does the trick more often than not.*/ + var/id = md5("[G_found.real_name][G_found.mind.assigned_role]") + + record_found = find_record("id", id, GLOB.data_core.locked) + + if(record_found)//If they have a record we can determine a few things. + new_character.real_name = record_found.fields["name"] + new_character.gender = record_found.fields["sex"] + new_character.age = record_found.fields["age"] + new_character.hardset_dna(record_found.fields["identity"], record_found.fields["enzymes"], record_found.fields["name"], record_found.fields["blood_type"], new record_found.fields["species"], record_found.fields["features"]) + else + var/datum/preferences/A = new() + A.copy_to(new_character) + A.real_name = G_found.real_name + new_character.dna.update_dna_identity() + + new_character.name = new_character.real_name + + if(G_found.mind && !G_found.mind.active) + G_found.mind.transfer_to(new_character) //be careful when doing stuff like this! I've already checked the mind isn't in use + else + new_character.mind_initialize() + if(!new_character.mind.assigned_role) + new_character.mind.assigned_role = "Assistant"//If they somehow got a null assigned role. + + new_character.key = G_found.key + + /* + The code below functions with the assumption that the mob is already a traitor if they have a special role. + So all it does is re-equip the mob with powers and/or items. Or not, if they have no special role. + If they don't have a mind, they obviously don't have a special role. + */ + + //Two variables to properly announce later on. + var/admin = key_name_admin(src) + var/player_key = G_found.key + + //Now for special roles and equipment. + var/datum/antagonist/traitor/traitordatum = new_character.mind.has_antag_datum(/datum/antagonist/traitor) + if(traitordatum) + SSjob.EquipRank(new_character, new_character.mind.assigned_role, 1) + traitordatum.equip() + + + switch(new_character.mind.special_role) + if(ROLE_WIZARD) + new_character.forceMove(pick(GLOB.wizardstart)) + var/datum/antagonist/wizard/A = new_character.mind.has_antag_datum(/datum/antagonist/wizard,TRUE) + A.equip_wizard() + if(ROLE_SYNDICATE) + new_character.forceMove(pick(GLOB.nukeop_start)) + var/datum/antagonist/nukeop/N = new_character.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE) + N.equip_op() + if(ROLE_NINJA) + var/list/ninja_spawn = list() + for(var/obj/effect/landmark/carpspawn/L in GLOB.landmarks_list) + ninja_spawn += L + var/datum/antagonist/ninja/ninjadatum = new_character.mind.has_antag_datum(/datum/antagonist/ninja) + ninjadatum.equip_space_ninja() + if(ninja_spawn.len) + new_character.forceMove(pick(ninja_spawn)) + + else//They may also be a cyborg or AI. + switch(new_character.mind.assigned_role) + if("Cyborg")//More rigging to make em' work and check if they're traitor. + new_character = new_character.Robotize(TRUE) + if("AI") + new_character = new_character.AIize() + else + SSjob.EquipRank(new_character, new_character.mind.assigned_role, 1)//Or we simply equip them. + + //Announces the character on all the systems, based on the record. + if(!issilicon(new_character))//If they are not a cyborg/AI. + if(!record_found&&new_character.mind.assigned_role!=new_character.mind.special_role)//If there are no records for them. If they have a record, this info is already in there. MODE people are not announced anyway. + //Power to the user! + if(alert(new_character,"Warning: No data core entry detected. Would you like to announce the arrival of this character by adding them to various databases, such as medical records?",,"No","Yes")=="Yes") + GLOB.data_core.manifest_inject(new_character, new_character.client) + + if(alert(new_character,"Would you like an active AI to announce this character?",,"No","Yes")=="Yes") + AnnounceArrival(new_character, new_character.mind.assigned_role) + + var/msg = "[admin] has respawned [player_key] as [new_character.real_name]." + message_admins(msg) + admin_ticket_log(new_character, msg) + + to_chat(new_character, "You have been fully respawned. Enjoy the game.") + + SSblackbox.record_feedback("tally", "admin_verb", 1, "Respawn Character") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return new_character + +/client/proc/cmd_admin_add_freeform_ai_law() + set category = "Fun" + set name = "Add Custom AI law" + + if(!check_rights(R_ADMIN)) + return + + var/input = input(usr, "Please enter anything you want the AI to do. Anything. Serious.", "What?", "") as text|null + if(!input) + return + + log_admin("Admin [key_name(usr)] has added a new AI law - [input]") + message_admins("Admin [key_name_admin(usr)] has added a new AI law - [input]") + + var/show_log = alert(src, "Show ion message?", "Message", "Yes", "No") + var/announce_ion_laws = (show_log == "Yes" ? 1 : -1) + + var/datum/round_event/ion_storm/add_law_only/ion = new() + ion.announceEvent = announce_ion_laws + ion.ionMessage = input + + SSblackbox.record_feedback("tally", "admin_verb", 1, "Add Custom AI Law") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_rejuvenate(mob/living/M in GLOB.mob_list) + set category = "Special Verbs" + set name = "Rejuvenate" + + if(!check_rights(R_ADMIN)) + return + + if(!mob) + return + if(!istype(M)) + alert("Cannot revive a ghost") + return + M.revive(full_heal = 1, admin_revive = 1) + + log_admin("[key_name(usr)] healed / revived [key_name(M)]") + var/msg = "Admin [key_name_admin(usr)] healed / revived [ADMIN_LOOKUPFLW(M)]!" + message_admins(msg) + admin_ticket_log(M, msg) + SSblackbox.record_feedback("tally", "admin_verb", 1, "Rejuvinate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_create_centcom_report() + set category = "Special Verbs" + set name = "Create Command Report" + + if(!check_rights(R_ADMIN)) + return + + var/input = input(usr, "Enter a Command Report. Ensure it makes sense IC.", "What?", "") as message|null + if(!input) + return + + var/confirm = alert(src, "Do you want to announce the contents of the report to the crew?", "Announce", "Yes", "No", "Cancel") + var/announce_command_report = TRUE + switch(confirm) + if("Yes") + priority_announce(input, null, 'sound/ai/commandreport.ogg') + announce_command_report = FALSE + if("Cancel") + return + + print_command_report(input, "[announce_command_report ? "Classified " : ""][command_name()] Update", announce_command_report) + + log_admin("[key_name(src)] has created a command report: [input]") + message_admins("[key_name_admin(src)] has created a command report") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Create Command Report") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_change_command_name() + set category = "Special Verbs" + set name = "Change Command Name" + + if(!check_rights(R_ADMIN)) + return + + var/input = input(usr, "Please input a new name for Central Command.", "What?", "") as text|null + if(!input) + return + change_command_name(input) + message_admins("[key_name_admin(src)] has changed Central Command's name to [input]") + log_admin("[key_name(src)] has changed the Central Command name to: [input]") + +/client/proc/cmd_admin_delete(atom/A as obj|mob|turf in world) + set category = "Admin" + set name = "Delete" + + if(!check_rights(R_SPAWN|R_DEBUG)) + return + + admin_delete(A) + +/client/proc/admin_delete(datum/D) + var/atom/A = D + var/coords = "" + var/jmp_coords = "" + if(istype(A)) + var/turf/T = get_turf(A) + if(T) + coords = "at [COORD(T)]" + jmp_coords = "at [ADMIN_COORDJMP(T)]" + else + jmp_coords = coords = "in nullspace" + + if (alert(src, "Are you sure you want to delete:\n[D]\n[coords]?", "Confirmation", "Yes", "No") == "Yes") + log_admin("[key_name(usr)] deleted [D] [coords]") + message_admins("[key_name_admin(usr)] deleted [D] [jmp_coords]") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Delete") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + if(isturf(D)) + var/turf/T = D + T.ScrapeAway() + else + vv_update_display(D, "deleted", VV_MSG_DELETED) + qdel(D) + if(!QDELETED(D)) + vv_update_display(D, "deleted", "") + +/client/proc/cmd_admin_list_open_jobs() + set category = "Admin" + set name = "Manage Job Slots" + + if(!check_rights(R_ADMIN)) + return + holder.manage_free_slots() + SSblackbox.record_feedback("tally", "admin_verb", 1, "Manage Job Slots") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_explosion(atom/O as obj|mob|turf in world) + set category = "Special Verbs" + set name = "Explosion" + + if(!check_rights(R_ADMIN)) + return + + var/devastation = input("Range of total devastation. -1 to none", text("Input")) as num|null + if(devastation == null) + return + var/heavy = input("Range of heavy impact. -1 to none", text("Input")) as num|null + if(heavy == null) + return + var/light = input("Range of light impact. -1 to none", text("Input")) as num|null + if(light == null) + return + var/flash = input("Range of flash. -1 to none", text("Input")) as num|null + if(flash == null) + return + var/flames = input("Range of flames. -1 to none", text("Input")) as num|null + if(flames == null) + return + + if ((devastation != -1) || (heavy != -1) || (light != -1) || (flash != -1) || (flames != -1)) + if ((devastation > 20) || (heavy > 20) || (light > 20) || (flames > 20)) + if (alert(src, "Are you sure you want to do this? It will laaag.", "Confirmation", "Yes", "No") == "No") + return + + explosion(O, devastation, heavy, light, flash, null, null,flames) + log_admin("[key_name(usr)] created an explosion ([devastation],[heavy],[light],[flames]) at [AREACOORD(O)]") + message_admins("[key_name_admin(usr)] created an explosion ([devastation],[heavy],[light],[flames]) at [AREACOORD(O)]") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Explosion") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return + else + return + +/client/proc/cmd_admin_emp(atom/O as obj|mob|turf in world) + set category = "Special Verbs" + set name = "EM Pulse" + + if(!check_rights(R_ADMIN)) + return + + var/heavy = input("Range of heavy pulse.", text("Input")) as num|null + if(heavy == null) + return + var/light = input("Range of light pulse.", text("Input")) as num|null + if(light == null) + return + + if (heavy || light) + + empulse(O, heavy, light) + log_admin("[key_name(usr)] created an EM Pulse ([heavy],[light]) at [AREACOORD(O)]") + message_admins("[key_name_admin(usr)] created an EM Pulse ([heavy],[light]) at [AREACOORD(O)]") + SSblackbox.record_feedback("tally", "admin_verb", 1, "EM Pulse") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + return + else + return + +/client/proc/cmd_admin_gib(mob/M in GLOB.mob_list) + set category = "Special Verbs" + set name = "Gib" + + if(!check_rights(R_ADMIN)) + return + + var/confirm = alert(src, "Drop a brain?", "Confirm", "Yes", "No","Cancel") + if(confirm == "Cancel") + return + //Due to the delay here its easy for something to have happened to the mob + if(!M) + return + + log_admin("[key_name(usr)] has gibbed [key_name(M)]") + message_admins("[key_name_admin(usr)] has gibbed [key_name_admin(M)]") + + if(isobserver(M)) + new /obj/effect/gibspawner/generic(get_turf(M)) + return + if(confirm == "Yes") + M.gib() + else + M.gib(1) + SSblackbox.record_feedback("tally", "admin_verb", 1, "Gib") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/cmd_admin_gib_self() + set name = "Gibself" + set category = "Fun" + + var/confirm = alert(src, "You sure?", "Confirm", "Yes", "No") + if(confirm == "Yes") + log_admin("[key_name(usr)] used gibself.") + message_admins("[key_name_admin(usr)] used gibself.") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Gib Self") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + mob.gib(1, 1, 1) + +/client/proc/cmd_admin_check_contents(mob/living/M in GLOB.mob_list) + set category = "Special Verbs" + set name = "Check Contents" + + var/list/L = M.get_contents() + for(var/t in L) + to_chat(usr, "[t]") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Check Contents") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/toggle_view_range() + set category = "Special Verbs" + set name = "Change View Range" + set desc = "switches between 1x and custom views" + + if(view == CONFIG_GET(string/default_view)) + change_view(input("Select view range:", "FUCK YE", 7) in list(1,2,3,4,5,6,7,8,9,10,11,12,13,14,128)) + else + change_view(CONFIG_GET(string/default_view)) + + log_admin("[key_name(usr)] changed their view range to [view].") + //message_admins("\blue [key_name_admin(usr)] changed their view range to [view].") //why? removed by order of XSI + + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Change View Range", "[view]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/admin_call_shuttle() + + set category = "Admin" + set name = "Call Shuttle" + + if(EMERGENCY_AT_LEAST_DOCKED) + return + + if(!check_rights(R_ADMIN)) + return + + var/confirm = alert(src, "You sure?", "Confirm", "Yes", "No") + if(confirm != "Yes") + return + + SSshuttle.emergency.request() + SSblackbox.record_feedback("tally", "admin_verb", 1, "Call Shuttle") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + log_admin("[key_name(usr)] admin-called the emergency shuttle.") + message_admins("[key_name_admin(usr)] admin-called the emergency shuttle.") + return + +/client/proc/admin_cancel_shuttle() + set category = "Admin" + set name = "Cancel Shuttle" + if(!check_rights(0)) + return + if(alert(src, "You sure?", "Confirm", "Yes", "No") != "Yes") + return + + if(EMERGENCY_AT_LEAST_DOCKED) + return + + SSshuttle.emergency.cancel() + SSblackbox.record_feedback("tally", "admin_verb", 1, "Cancel Shuttle") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + log_admin("[key_name(usr)] admin-recalled the emergency shuttle.") + message_admins("[key_name_admin(usr)] admin-recalled the emergency shuttle.") + + return + +/client/proc/everyone_random() + set category = "Fun" + set name = "Make Everyone Random" + set desc = "Make everyone have a random appearance. You can only use this before rounds!" + + if(SSticker.HasRoundStarted()) + to_chat(usr, "Nope you can't do this, the game's already started. This only works before rounds!") + return + + var/frn = CONFIG_GET(flag/force_random_names) + if(frn) + CONFIG_SET(flag/force_random_names, FALSE) + message_admins("Admin [key_name_admin(usr)] has disabled \"Everyone is Special\" mode.") + to_chat(usr, "Disabled.") + return + + + var/notifyplayers = alert(src, "Do you want to notify the players?", "Options", "Yes", "No", "Cancel") + if(notifyplayers == "Cancel") + return + + log_admin("Admin [key_name(src)] has forced the players to have random appearances.") + message_admins("Admin [key_name_admin(usr)] has forced the players to have random appearances.") + + if(notifyplayers == "Yes") + to_chat(world, "Admin [usr.key] has forced the players to have completely random identities!") + + to_chat(usr, "Remember: you can always disable the randomness by using the verb again, assuming the round hasn't started yet.") + + CONFIG_SET(flag/force_random_names, TRUE) + SSblackbox.record_feedback("tally", "admin_verb", 1, "Make Everyone Random") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +/client/proc/toggle_random_events() + set category = "Server" + set name = "Toggle random events on/off" + set desc = "Toggles random events such as meteors, black holes, blob (but not space dust) on/off" + var/new_are = !CONFIG_GET(flag/allow_random_events) + CONFIG_SET(flag/allow_random_events, new_are) + if(new_are) + to_chat(usr, "Random events enabled") + message_admins("Admin [key_name_admin(usr)] has enabled random events.") + else + to_chat(usr, "Random events disabled") + message_admins("Admin [key_name_admin(usr)] has disabled random events.") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Random Events", "[new_are ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +/client/proc/admin_change_sec_level() + set category = "Special Verbs" + set name = "Set Security Level" + set desc = "Changes the security level. Announcement only, i.e. setting to Delta won't activate nuke" + + if(!check_rights(R_ADMIN)) + return + + var/level = input("Select security level to change to","Set Security Level") as null|anything in list("green","blue","amber","red","delta") + if(level) + set_security_level(level) + + log_admin("[key_name(usr)] changed the security level to [level]") + message_admins("[key_name_admin(usr)] changed the security level to [level]") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Set Security Level [capitalize(level)]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/toggle_nuke(obj/machinery/nuclearbomb/N in GLOB.nuke_list) + set name = "Toggle Nuke" + set category = "Fun" + set popup_menu = 0 + if(!check_rights(R_DEBUG)) + return + + if(!N.timing) + var/newtime = input(usr, "Set activation timer.", "Activate Nuke", "[N.timer_set]") as num|null + if(!newtime) + return + N.timer_set = newtime + N.set_safety() + N.set_active() + + log_admin("[key_name(usr)] [N.timing ? "activated" : "deactivated"] a nuke at [AREACOORD(N)].") + message_admins("[ADMIN_LOOKUPFLW(usr)] [N.timing ? "activated" : "deactivated"] a nuke at [ADMIN_VERBOSEJMP(N)].") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Nuke", "[N.timing]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits + +/client/proc/create_outfits() + set category = "Debug" + set name = "Create Custom Outfit" + + if(!check_rights(R_DEBUG)) + return + + holder.create_outfit() + +/datum/admins/proc/create_outfit() + var/list/uniforms = typesof(/obj/item/clothing/under) + var/list/suits = typesof(/obj/item/clothing/suit) + var/list/gloves = typesof(/obj/item/clothing/gloves) + var/list/shoes = typesof(/obj/item/clothing/shoes) + var/list/headwear = typesof(/obj/item/clothing/head) + var/list/glasses = typesof(/obj/item/clothing/glasses) + var/list/masks = typesof(/obj/item/clothing/mask) + var/list/ids = typesof(/obj/item/card/id) + + var/uniform_select = "" + + var/suit_select = "" + + var/gloves_select = "" + + var/shoes_select = "" + + var/head_select = "" + + var/glasses_select = "" + + var/mask_select = "" + + var/id_select = "" + + var/dat = {" + Create Outfit +
+ + [HrefTokenFormField()] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name: + +
Uniform: + [uniform_select] +
Suit: + [suit_select] +
Back: + +
Belt: + +
Gloves: + [gloves_select] +
Shoes: + [shoes_select] +
Head: + [head_select] +
Mask: + [mask_select] +
Ears: + +
Glasses: + [glasses_select] +
ID: + [id_select] +
Left Pocket: + +
Right Pocket: + +
Suit Store: + +
Right Hand: + +
Left Hand: + +
+
+ +
+ "} + usr << browse(dat, "window=dressup;size=550x600") + +/client/proc/toggle_combo_hud() + set category = "Admin" + set name = "Toggle Combo HUD" + set desc = "Toggles the Admin Combo HUD (antag, sci, med, eng)" + + if(!check_rights(R_ADMIN)) + return + + var/adding_hud = !has_antag_hud() + + for(var/hudtype in list(DATA_HUD_SECURITY_ADVANCED, DATA_HUD_MEDICAL_ADVANCED, DATA_HUD_DIAGNOSTIC_ADVANCED)) // add data huds + var/datum/atom_hud/H = GLOB.huds[hudtype] + (adding_hud) ? H.add_hud_to(usr) : H.remove_hud_from(usr) + for(var/datum/atom_hud/antag/H in GLOB.huds) // add antag huds + (adding_hud) ? H.add_hud_to(usr) : H.remove_hud_from(usr) + + if(prefs.toggles & COMBOHUD_LIGHTING) + if(adding_hud) + mob.lighting_alpha = LIGHTING_PLANE_ALPHA_INVISIBLE + else + mob.lighting_alpha = initial(mob.lighting_alpha) + + mob.update_sight() + + to_chat(usr, "You toggled your admin combo HUD [adding_hud ? "ON" : "OFF"].") + message_admins("[key_name_admin(usr)] toggled their admin combo HUD [adding_hud ? "ON" : "OFF"].") + log_admin("[key_name(usr)] toggled their admin combo HUD [adding_hud ? "ON" : "OFF"].") + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Combo HUD", "[adding_hud ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +/client/proc/has_antag_hud() + var/datum/atom_hud/A = GLOB.huds[ANTAG_HUD_TRAITOR] + return A.hudusers[mob] + +/client/proc/open_shuttle_manipulator() + set category = "Admin" + set name = "Shuttle Manipulator" + set desc = "Opens the shuttle manipulator UI." + + for(var/obj/machinery/shuttle_manipulator/M in GLOB.machines) + M.ui_interact(usr) + +/client/proc/run_weather() + set category = "Fun" + set name = "Run Weather" + set desc = "Triggers a weather on the z-level you choose." + + if(!holder) + return + + var/weather_type = input("Choose a weather", "Weather") as null|anything in subtypesof(/datum/weather) + if(!weather_type) + return + + var/z_level = input("Z-Level to target? Leave blank to target current Z-Level.", "Z-Level") as num|null + if(!isnum(z_level)) + if(!src.mob) + return + z_level = src.mob.z + + SSweather.run_weather(weather_type, z_level) + + message_admins("[key_name_admin(usr)] started weather of type [weather_type] on the z-level [z_level].") + log_admin("[key_name(usr)] started weather of type [weather_type] on the z-level [z_level].") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Run Weather") + +/client/proc/mass_zombie_infection() + set category = "Fun" + set name = "Mass Zombie Infection" + set desc = "Infects all humans with a latent organ that will zombify \ + them on death." + + if(!check_rights(R_ADMIN)) + return + + var/confirm = alert(src, "Please confirm you want to add latent zombie organs in all humans?", "Confirm Zombies", "Yes", "No") + if(confirm != "Yes") + return + + for(var/mob/living/carbon/human/H in GLOB.carbon_list) + new /obj/item/organ/zombie_infection/nodamage(H) + + message_admins("[key_name_admin(usr)] added a latent zombie infection to all humans.") + log_admin("[key_name(usr)] added a latent zombie infection to all humans.") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Mass Zombie Infection") + +/client/proc/mass_zombie_cure() + set category = "Fun" + set name = "Mass Zombie Cure" + set desc = "Removes the zombie infection from all humans, returning them to normal." + if(!check_rights(R_ADMIN)) + return + + var/confirm = alert(src, "Please confirm you want to cure all zombies?", "Confirm Zombie Cure", "Yes", "No") + if(confirm != "Yes") + return + + for(var/obj/item/organ/zombie_infection/nodamage/I in GLOB.zombie_infection_list) + qdel(I) + + message_admins("[key_name_admin(usr)] cured all zombies.") + log_admin("[key_name(usr)] cured all zombies.") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Mass Zombie Cure") + +/client/proc/polymorph_all() + set category = "Fun" + set name = "Polymorph All" + set desc = "Applies the effects of the bolt of change to every single mob." + + if(!check_rights(R_ADMIN)) + return + + var/confirm = alert(src, "Please confirm you want polymorph all mobs?", "Confirm Polymorph", "Yes", "No") + if(confirm != "Yes") + return + + var/list/mobs = shuffle(GLOB.alive_mob_list.Copy()) // might change while iterating + var/who_did_it = key_name_admin(usr) + + message_admins("[key_name_admin(usr)] started polymorphed all living mobs.") + log_admin("[key_name(usr)] polymorphed all living mobs.") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Polymorph All") + + for(var/mob/living/M in mobs) + CHECK_TICK + + if(!M) + continue + + M.audible_message("...wabbajack...wabbajack...") + playsound(M.loc, 'sound/magic/staff_change.ogg', 50, 1, -1) + + wabbajack(M) + + message_admins("Mass polymorph started by [who_did_it] is complete.") + + +/client/proc/show_tip() + set category = "Admin" + set name = "Show Tip" + set desc = "Sends a tip (that you specify) to all players. After all \ + you're the experienced player here." + + if(!check_rights(R_ADMIN)) + return + + var/input = input(usr, "Please specify your tip that you want to send to the players.", "Tip", "") as message|null + if(!input) + return + + if(!SSticker) + return + + SSticker.selected_tip = input + + // If we've already tipped, then send it straight away. + if(SSticker.tipped) + SSticker.send_tip_of_the_round() + + + message_admins("[key_name_admin(usr)] sent a tip of the round.") + log_admin("[key_name(usr)] sent \"[input]\" as the Tip of the Round.") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Tip") + +/client/proc/modify_goals() + set category = "Debug" + set name = "Modify goals" + + if(!check_rights(R_ADMIN)) + return + + holder.modify_goals() + +/datum/admins/proc/modify_goals() + var/dat = "" + for(var/datum/station_goal/S in SSticker.mode.station_goals) + dat += "[S.name] - Announce | Remove
" + dat += "
Add New Goal" + usr << browse(dat, "window=goals;size=400x400") + + +/client/proc/toggle_hub() + set category = "Server" + set name = "Toggle Hub" + + world.update_hub_visibility(!GLOB.hub_visibility) + + log_admin("[key_name(usr)] has toggled the server's hub status for the round, it is now [(GLOB.hub_visibility?"on":"off")] the hub.") + message_admins("[key_name_admin(usr)] has toggled the server's hub status for the round, it is now [(GLOB.hub_visibility?"on":"off")] the hub.") + if (GLOB.hub_visibility && !world.reachable) + message_admins("WARNING: The server will not show up on the hub because byond is detecting that a filewall is blocking incoming connections.") + + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggled Hub Visibility", "[GLOB.hub_visibility ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/breadify(atom/movable/target) + var/obj/item/reagent_containers/food/snacks/store/bread/plain/funnyBread = new(get_turf(target)) + target.forceMove(funnyBread) + +/client/proc/smite(mob/living/carbon/human/target as mob) + set name = "Smite" + set category = "Fun" + if(!check_rights(R_ADMIN) || !check_rights(R_FUN)) + return + + var/list/punishment_list = list(ADMIN_PUNISHMENT_PIE, + ADMIN_PUNISHMENT_FIREBALL, + ADMIN_PUNISHMENT_CLUWNE, + ADMIN_PUNISHMENT_LIGHTNING, + ADMIN_PUNISHMENT_BRAINDAMAGE, + ADMIN_PUNISHMENT_BSA, + ADMIN_PUNISHMENT_GIB, + ADMIN_PUNISHMENT_SUPPLYPOD_QUICK, + ADMIN_PUNISHMENT_SUPPLYPOD, + ADMIN_PUNISHMENT_MAZING, + ADMIN_PUNISHMENT_ROD, + ADMIN_PUNISHMENT_TABLETIDESTATIONWIDE, + ADMIN_PUNISHMENT_FAKEBWOINK, + ADMIN_PUNISHMENT_NUGGET, + ADMIN_PUNISHMENT_BREADIFY) + + var/punishment = input("Choose a punishment", "DIVINE SMITING") as null|anything in punishment_list + + if(QDELETED(target) || !punishment) + return + + switch(punishment) + if(ADMIN_PUNISHMENT_LIGHTNING) + var/turf/T = get_step(get_step(target, NORTH), NORTH) + T.Beam(target, icon_state="lightning[rand(1,12)]", time = 5) + target.adjustFireLoss(75) + target.electrocution_animation(40) + to_chat(target, "The gods have punished you for your sins!") + if(ADMIN_PUNISHMENT_BRAINDAMAGE) + target.adjustOrganLoss(ORGAN_SLOT_BRAIN, 199, 199) + if(ADMIN_PUNISHMENT_GIB) + target.gib(FALSE) + if(ADMIN_PUNISHMENT_BSA) + bluespace_artillery(target) + if(ADMIN_PUNISHMENT_FIREBALL) + new /obj/effect/temp_visual/target(get_turf(target)) + if(ADMIN_PUNISHMENT_CLUWNE) + var/mob/living/simple_animal/hostile/floor_cluwne/FC = new /mob/living/simple_animal/hostile/floor_cluwne(get_turf(target)) + FC.smite = TRUE + FC.forced = TRUE + FC.Acquire_Victim(target) + FC.target = target + FC.current_victim = target + FC.interest = 5000 + FC.maxHealth = 5000 + FC.health = 5000 + if(ADMIN_PUNISHMENT_ROD) + var/turf/T = get_turf(target) + var/startside = pick(GLOB.cardinals) + var/turf/startT = spaceDebrisStartLoc(startside, T.z) + var/turf/endT = spaceDebrisFinishLoc(startside, T.z) + new /obj/effect/immovablerod(startT, endT,target) + if(ADMIN_PUNISHMENT_SUPPLYPOD_QUICK) + var/target_path = input(usr,"Enter typepath of an atom you'd like to send with the pod (type \"empty\" to send an empty pod):" ,"Typepath","/obj/item/reagent_containers/food/snacks/grown/harebell") as null|text + var/obj/structure/closet/supplypod/centcompod/pod = new() + pod.damage = 40 + pod.explosionSize = list(0,0,0,2) + pod.effectStun = TRUE + if (isnull(target_path)) //The user pressed "Cancel" + return + if (target_path != "empty")//if you didn't type empty, we want to load the pod with a delivery + var/delivery = text2path(target_path) + if(!ispath(delivery)) + delivery = pick_closest_path(target_path) + if(!delivery) + alert("ERROR: Incorrect / improper path given.") + new delivery(pod) + new /obj/effect/abstract/DPtarget(get_turf(target), pod) + if(ADMIN_PUNISHMENT_SUPPLYPOD) + var/datum/centcom_podlauncher/plaunch = new(usr) + if(!holder) + return + plaunch.specificTarget = target + plaunch.launchChoice = 0 + plaunch.damageChoice = 1 + plaunch.explosionChoice = 1 + plaunch.temp_pod.damage = 40//bring the mother fuckin ruckus + plaunch.temp_pod.explosionSize = list(0,0,0,2) + plaunch.temp_pod.effectStun = TRUE + plaunch.ui_interact(usr) + return //We return here because punish_log() is handled by the centcom_podlauncher datum + + if(ADMIN_PUNISHMENT_MAZING) + if(!puzzle_imprison(target)) + to_chat(usr,"Imprisonment failed!") + return + if(ADMIN_PUNISHMENT_PIE) + var/obj/item/reagent_containers/food/snacks/pie/cream/nostun/creamy = new(get_turf(target)) + creamy.splat(target) + if(ADMIN_PUNISHMENT_TABLETIDESTATIONWIDE) + priority_announce(html_decode("[target] has brought the wrath of the gods upon themselves and is now being tableslammed across the station. Please stand by."), null, 'sound/misc/announce.ogg', "CentCom") + var/list/areas = list() + for(var/area/A in world) + if(A.z == SSmapping.station_start) + areas += A + SEND_SOUND(target, sound('hyperstation/sound/misc/slamofthenorthstar.ogg',volume=60)) + for(var/area/A in areas) + for(var/obj/structure/table/T in A) + T.tablepush(target, target) + sleep(1) + if(ADMIN_PUNISHMENT_FAKEBWOINK) + SEND_SOUND(target, 'sound/effects/adminhelp.ogg') + if(ADMIN_PUNISHMENT_NUGGET) + if (!iscarbon(target)) + return + var/mob/living/carbon/carbon_target = target + var/timer = 2 SECONDS + for (var/_limb in carbon_target.bodyparts) + var/obj/item/bodypart/limb = _limb + if (limb.body_part == HEAD || limb.body_part == CHEST) + continue + addtimer(CALLBACK(limb, /obj/item/bodypart/.proc/dismember), timer) + addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, carbon_target, 'sound/effects/cartoon_pop.ogg', 70), timer) + addtimer(CALLBACK(carbon_target, /mob/living/.proc/spin, 4, 1), timer - 0.4 SECONDS) + timer += 2 SECONDS + if(ADMIN_PUNISHMENT_BREADIFY) + #define BREADIFY_TIME (5 SECONDS) + var/mutable_appearance/bread_appearance = mutable_appearance('icons/obj/food/burgerbread.dmi', "bread") + var/mutable_appearance/transform_scanline = mutable_appearance('icons/effects/effects.dmi', "transform_effect") + target.transformation_animation(bread_appearance, time = BREADIFY_TIME, transform_overlay=transform_scanline, reset_after=TRUE) + addtimer(CALLBACK(GLOBAL_PROC, .proc/breadify, target), BREADIFY_TIME) + #undef BREADIFY_TIME + + punish_log(target, punishment) + +/client/proc/punish_log(var/whom, var/punishment) + var/msg = "[key_name_admin(usr)] punished [key_name_admin(whom)] with [punishment]." + message_admins(msg) + admin_ticket_log(whom, msg) + log_admin("[key_name(usr)] punished [key_name(whom)] with [punishment].") + +/client/proc/trigger_centcom_recall() + if(!check_rights(R_ADMIN)) + return + var/message = pick(GLOB.admiral_messages) + message = input("Enter message from the on-call admiral to be put in the recall report.", "Admiral Message", message) as text|null + + if(!message) + return + + message_admins("[key_name_admin(usr)] triggered a CentCom recall, with the admiral message of: [message]") + log_game("[key_name(usr)] triggered a CentCom recall, with the message of: [message]") + SSshuttle.centcom_recall(SSshuttle.emergency.timer, message) + +/client/proc/cmd_admin_check_player_exp() //Allows admins to determine who the newer players are. + set category = "Admin" + set name = "Player Playtime" + if(!check_rights(R_ADMIN)) + return + + if(!CONFIG_GET(flag/use_exp_tracking)) + to_chat(usr, "Tracking is disabled in the server configuration file.") + return + + var/list/msg = list() + msg += "Playtime ReportPlaytime:
" + src << browse(msg.Join(), "window=Player_playtime_check") + +/datum/admins/proc/cmd_show_exp_panel(client/C) + if(!check_rights(R_ADMIN)) + return + if(!C) + to_chat(usr, "ERROR: Client not found.") + return + if(!CONFIG_GET(flag/use_exp_tracking)) + to_chat(usr, "Tracking is disabled in the server configuration file.") + return + + var/list/body = list() + body += "Playtime for [C.key]
Playtime:" + body += C.get_exp_report() + body += "Toggle Exempt status" + body += "" + usr << browse(body.Join(), "window=playerplaytime[C.ckey];size=550x615") + +/datum/admins/proc/toggle_exempt_status(client/C) + if(!check_rights(R_ADMIN)) + return + if(!C) + to_chat(usr, "ERROR: Client not found.") + return + + if(!C.set_db_player_flags()) + to_chat(usr, "ERROR: Unable read player flags from database. Please check logs.") + var/dbflags = C.prefs.db_flags + var/newstate = FALSE + if(dbflags & DB_FLAG_EXEMPT) + newstate = FALSE + else + newstate = TRUE + + if(C.update_flag_db(DB_FLAG_EXEMPT, newstate)) + to_chat(usr, "ERROR: Unable to update player flags. Please check logs.") + else + message_admins("[key_name_admin(usr)] has [newstate ? "activated" : "deactivated"] job exp exempt status on [key_name_admin(C)]") + log_admin("[key_name(usr)] has [newstate ? "activated" : "deactivated"] job exp exempt status on [key_name(C)]") diff --git a/code/modules/cargo/centcom_podlauncher.dm b/code/modules/cargo/centcom_podlauncher.dm index e482aa00..92cc1cd1 100644 --- a/code/modules/cargo/centcom_podlauncher.dm +++ b/code/modules/cargo/centcom_podlauncher.dm @@ -19,7 +19,7 @@ //Variables declared to change how items in the launch bay are picked and launched. (Almost) all of these are changed in the ui_act proc //Some effect groups are choices, while other are booleans. This is because some effects can stack, while others dont (ex: you can stack explosion and quiet, but you cant stack ordered launch and random launch) /datum/centcom_podlauncher - var/static/list/ignored_atoms = typecacheof(list(null, /mob/dead, /obj/effect/landmark, /obj/docking_port, /atom/movable/lighting_object, /obj/effect/particle_effect/sparks, /obj/effect/DPtarget, /obj/effect/supplypod_selector )) + var/static/list/ignored_atoms = typecacheof(list(null, /mob/dead, /obj/effect/landmark, /obj/docking_port, /atom/movable/lighting_object, /obj/effect/particle_effect/sparks, /obj/effect/abstract/DPtarget, /obj/effect/supplypod_selector )) var/turf/oldTurf //Keeps track of where the user was at if they use the "teleport to centcom" button, so they can go back var/client/holder //client of whoever is using this datum var/area/bay //What bay we're using to launch shit from. @@ -29,9 +29,10 @@ var/damageChoice = 0 //Determines if we do no damage (0), custom amnt of damage (1), or gib + 5000dmg (2) var/launcherActivated = FALSE //check if we've entered "launch mode" (when we click a pod is launched). Used for updating mouse cursor var/effectBurst = FALSE //Effect that launches 5 at once in a 3x3 area centered on the target + var/effectAnnounce = TRUE var/numTurfs = 0 //Counts the number of turfs with things we can launch in the chosen bay (in the centcom map) var/launchCounter = 1 //Used with the "Ordered" launch mode (launchChoice = 1) to see what item is launched - var/specificTarget //Do we want to target a specific mob instead of where we click? Also used for smiting + var/atom/specificTarget //Do we want to target a specific mob instead of where we click? Also used for smiting var/list/orderedArea = list() //Contains an ordered list of turfs in an area (filled in the createOrderedArea() proc), read top-left to bottom-right. Used for the "ordered" launch mode (launchChoice = 1) var/list/acceptableTurfs = list() //Contians a list of turfs (in the "bay" area on centcom) that have items that can be launched. Taken from orderedArea var/list/launchList = list() //Contains whatever is going to be put in the supplypod and fired. Taken from acceptableTurfs @@ -66,12 +67,14 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm data["launchChoice"] = launchChoice //Launch turfs all at once (0), ordered (1), or randomly(1) data["explosionChoice"] = explosionChoice //An explosion that occurs when landing. Can be no explosion (0), custom explosion (1), or maxcap (2) data["damageChoice"] = damageChoice //Damage that occurs to any mob under the pod when it lands. Can be no damage (0), custom damage (1), or gib+5000dmg (2) + data["fallDuration"] = temp_pod.fallDuration //How long the pod's falling animation lasts data["landingDelay"] = temp_pod.landingDelay //How long the pod takes to land after launching data["openingDelay"] = temp_pod.openingDelay //How long the pod takes to open after landing data["departureDelay"] = temp_pod.departureDelay //How long the pod takes to leave after opening (if bluespace=true, it deletes. if reversing=true, it flies back to centcom) data["styleChoice"] = temp_pod.style //Style is a variable that keeps track of what the pod is supposed to look like. It acts as an index to the POD_STYLES list in cargo.dm defines to get the proper icon/name/desc for the pod. data["effectStun"] = temp_pod.effectStun //If true, stuns anyone under the pod when it launches until it lands, forcing them to get hit by the pod. Devilish! data["effectLimb"] = temp_pod.effectLimb //If true, pops off a limb (if applicable) from anyone caught under the pod when it lands + data["effectOrgans"] = temp_pod.effectOrgans //If true, yeets the organs out of any bodies caught under the pod when it lands data["effectBluespace"] = temp_pod.bluespace //If true, the pod deletes (in a shower of sparks) after landing data["effectStealth"] = temp_pod.effectStealth //If true, a target icon isnt displayed on the turf where the pod will land data["effectQuiet"] = temp_pod.effectQuiet //The female sniper. If true, the pod makes no noise (including related explosions, opening sounds, etc) @@ -81,12 +84,14 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm data["effectReverse"] = temp_pod.reversing //If true, the pod will not send any items. Instead, after opening, it will close again (picking up items/mobs) and fly back to centcom data["effectTarget"] = specificTarget //Launches the pod at the turf of a specific mob target, rather than wherever the user clicked. Useful for smites data["effectName"] = temp_pod.adminNamed //Determines whether or not the pod has been named by an admin. If true, the pod's name will not get overridden when the style of the pod changes (changing the style of the pod normally also changes the name+desc) + data["effectAnnounce"] = effectAnnounce data["giveLauncher"] = launcherActivated //If true, the user is in launch mode, and whenever they click a pod will be launched (either at their mouse position or at a specific target) data["numObjects"] = numTurfs //Counts the number of turfs that contain a launchable object in the centcom supplypod bay + data["fallingSound"] = temp_pod.fallingSound != initial(temp_pod.fallingSound)//Admin sound to play as the pod falls data["landingSound"] = temp_pod.landingSound //Admin sound to play when the pod lands data["openingSound"] = temp_pod.openingSound //Admin sound to play when the pod opens data["leavingSound"] = temp_pod.leavingSound //Admin sound to play when the pod leaves - data["soundVolume"] = temp_pod.soundVolume != 50 //Admin sound to play when the pod leaves + data["soundVolume"] = temp_pod.soundVolume != initial(temp_pod.soundVolume) //Admin sound to play when the pod leaves return data /datum/centcom_podlauncher/ui_act(action, params) @@ -227,6 +232,9 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm if("effectLimb") //Toggle: Anyone carbon mob under the pod loses a limb when it lands temp_pod.effectLimb = !temp_pod.effectLimb . = TRUE + if("effectOrgans") //Toggle: Any carbon mob under the pod loses every limb and organ + temp_pod.effectOrgans = !temp_pod.effectOrgans + . = TRUE if("effectBluespace") //Toggle: Deletes the pod after landing temp_pod.bluespace = !temp_pod.bluespace . = TRUE @@ -245,6 +253,9 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm if("effectBurst") //Toggle: Launch 5 pods (with a very slight delay between) in a 3x3 area centered around the target effectBurst = !effectBurst . = TRUE + if("effectAnnounce") //Toggle: Sends a ghost announcement. + effectAnnounce = !effectAnnounce + . = TRUE if("effectReverse") //Toggle: Don't send any items. Instead, after landing, close (taking any objects inside) and go back to the centcom bay it came from temp_pod.reversing = !temp_pod.reversing . = TRUE @@ -261,11 +272,23 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm . = TRUE ////////////////////////////TIMER DELAYS////////////////// + if("fallDuration") //Change the falling animation duration + if (temp_pod.fallDuration != initial(temp_pod.fallDuration)) //If the fall duration has already been changed when we push the "change value" button, then set it to default + temp_pod.fallDuration = initial(temp_pod.fallDuration) + return + var/timeInput = input("Enter the duration of the pod's falling animation, in seconds", "Delay Time", initial(temp_pod.fallDuration) * 0.1) as null|num + if (isnull(timeInput)) + return + if (!isnum(timeInput)) //Sanitize input, if it doesnt check out, error and set to default + alert(usr, "That wasnt a number! Value set to default ([initial(temp_pod.fallDuration)*0.1]) instead.") + timeInput = initial(temp_pod.fallDuration) + temp_pod.fallDuration = 10 * timeInput + . = TRUE if("landingDelay") //Change the time it takes the pod to land, after firing if (temp_pod.landingDelay != initial(temp_pod.landingDelay)) //If the landing delay has already been changed when we push the "change value" button, then set it to default temp_pod.landingDelay = initial(temp_pod.landingDelay) return - var/timeInput = input("Delay Time", "Enter the time it takes for the pod to land, in seconds", 0.5) as null|num + var/timeInput = input("Enter the time it takes for the pod to land, in seconds", "Delay Time", initial(temp_pod.landingDelay) * 0.1) as null|num if (isnull(timeInput)) return if (!isnum(timeInput)) //Sanitize input, if it doesnt check out, error and set to default @@ -277,7 +300,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm if (temp_pod.openingDelay != initial(temp_pod.openingDelay)) //If the opening delay has already been changed when we push the "change value" button, then set it to default temp_pod.openingDelay = initial(temp_pod.openingDelay) return - var/timeInput = input("Delay Time", "Enter the time it takes for the pod to open after landing, in seconds", 3) as null|num + var/timeInput = input("Enter the time it takes for the pod to open after landing, in seconds", "Delay Time", initial(temp_pod.openingDelay) * 0.1) as null|num if (isnull(timeInput)) return if (!isnum(timeInput)) //Sanitize input @@ -289,7 +312,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm if (temp_pod.departureDelay != initial(temp_pod.departureDelay)) //If the departure delay has already been changed when we push the "change value" button, then set it to default temp_pod.departureDelay = initial(temp_pod.departureDelay) return - var/timeInput = input("Delay Time", "Enter the time it takes for the pod to leave after opening, in seconds", 3) as null|num + var/timeInput = input("Enter the time it takes for the pod to leave after opening, in seconds", "Delay Time", initial(temp_pod.departureDelay) * 0.1) as null|num if (isnull(timeInput)) return if (!isnum(timeInput)) @@ -299,31 +322,57 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm . = TRUE ////////////////////////////ADMIN SOUNDS////////////////// + if("fallingSound") //Admin sound from a local file that plays when the pod falls + if ((temp_pod.fallingSound) != initial(temp_pod.fallingSound)) + temp_pod.fallingSound = initial(temp_pod.fallingSound) + temp_pod.fallingSoundLength = initial(temp_pod.fallingSoundLength) + return + var/soundInput = input(holder, "Please pick a sound file to play when the pod lands! NOTICE: Take a note of exactly how long the sound is.", "Pick a Sound File") as null|sound + if (isnull(soundInput)) + return + var/timeInput = input(holder, "What is the exact length of the sound file, in seconds. This number will be used to line the sound up so that it finishes right as the pod lands!", "Pick a Sound File", 0.3) as null|num + if (isnull(timeInput)) + return + if (!isnum(timeInput)) + alert(usr, "That wasnt a number! Value set to default ([initial(temp_pod.fallingSoundLength)*0.1]) instead.") + temp_pod.fallingSound = soundInput + temp_pod.fallingSoundLength = 10 * timeInput + . = TRUE if("landingSound") //Admin sound from a local file that plays when the pod lands if (!isnull(temp_pod.landingSound)) temp_pod.landingSound = null return - temp_pod.landingSound = input(holder, "Please pick a sound file to play when the pod lands! I reccomend a nice \"oh shit, i'm sorry\", incase you hit someone with the pod.", "Pick a Sound File") as null|sound + var/soundInput = input(holder, "Please pick a sound file to play when the pod lands! I reccomend a nice \"oh shit, i'm sorry\", incase you hit someone with the pod.", "Pick a Sound File") as null|sound + if (isnull(soundInput)) + return + temp_pod.landingSound = soundInput . = TRUE if("openingSound") //Admin sound from a local file that plays when the pod opens if (!isnull(temp_pod.openingSound)) temp_pod.openingSound = null return - temp_pod.openingSound = input(holder, "Please pick a sound file to play when the pod opens! I reccomend a stock sound effect of kids cheering at a party, incase your pod is full of fun exciting stuff!", "Pick a Sound File") as null|sound + var/soundInput = input(holder, "Please pick a sound file to play when the pod opens! I reccomend a stock sound effect of kids cheering at a party, incase your pod is full of fun exciting stuff!", "Pick a Sound File") as null|sound + if (isnull(soundInput)) + return + temp_pod.openingSound = soundInput . = TRUE if("leavingSound") //Admin sound from a local file that plays when the pod leaves if (!isnull(temp_pod.leavingSound)) temp_pod.leavingSound = null return - temp_pod.leavingSound = input(holder, "Please pick a sound file to play when the pod leaves! I reccomend a nice slide whistle sound, especially if you're using the reverse pod effect.", "Pick a Sound File") as null|sound + var/soundInput = input(holder, "Please pick a sound file to play when the pod leaves! I reccomend a nice slide whistle sound, especially if you're using the reverse pod effect.", "Pick a Sound File") as null|sound + if (isnull(soundInput)) + return + temp_pod.leavingSound = soundInput . = TRUE if("soundVolume") //Admin sound from a local file that plays when the pod leaves - if (temp_pod.soundVolume != 50) - temp_pod.soundVolume = 50 + if (temp_pod.soundVolume != initial(temp_pod.soundVolume)) + temp_pod.soundVolume = initial(temp_pod.soundVolume) return - temp_pod.soundVolume = input(holder, "Please pick a volume. Default is between 1 and 100 with 50 being average, but pick whatever. I'm a notification, not a cop. If you still cant hear your sound, consider turning on the Quiet effect. It will silence all pod sounds except for the custom admin ones set by the previous three buttons.", "Pick Admin Sound Volume") as null|num - if (isnull(temp_pod.soundVolume)) - temp_pod.soundVolume = 50 + var/soundInput = input(holder, "Please pick a volume. Default is between 1 and 100 with 80 being average, but pick whatever. I'm a notification, not a cop. If you still cant hear your sound, consider turning on the Quiet effect. It will silence all pod sounds except for the custom admin ones set by the previous three buttons.", "Pick Admin Sound Volume") as null|num + if (isnull(soundInput)) + return + temp_pod.soundVolume = soundInput . = TRUE ////////////////////////////STYLE CHANGES////////////////// //Style is a value that is used to keep track of what the pod is supposed to look like. It can be used with the POD_STYLES list (in cargo.dm defines) @@ -364,6 +413,9 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm if("styleGondola") temp_pod.setStyle(STYLE_GONDOLA) . = TRUE + if("styleSeeThrough") + temp_pod.setStyle(STYLE_SEETHROUGH) + . = TRUE if("refresh") //Refresh the Pod bay. User should press this if they spawn something new in the centcom bay. Automatically called whenever the user launches a pod refreshBay() . = TRUE @@ -403,12 +455,17 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm if(left_click) //When we left click: preLaunch() //Fill the acceptableTurfs list from the orderedArea list. Then, fill up the launchList list with items from the acceptableTurfs list based on the manner of launch (ordered, random, etc) if (!isnull(specificTarget)) - target = get_turf(specificTarget) //if we have a specific mob target, then always launch the pod at the turf of the mob + target = get_turf(specificTarget) //if we have a specific target, then always launch the pod at the turf of the target else if (target) target = get_turf(target) //Make sure we're aiming at a turf rather than an item or effect or something else return //if target is null and we don't have a specific target, cancel - + if (effectAnnounce) + deadchat_broadcast("A special package is being launched at the station!", turf_target = target) + var/list/bouttaDie = list() + for (var/mob/living/M in target) + bouttaDie.Add(M) + supplypod_punish_log(bouttaDie) if (!effectBurst) //If we're not using burst mode, just launch normally. launch(target) else @@ -422,7 +479,6 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm else launch(target) //If we couldn't locate an adjacent turf, just launch at the normal target sleep(rand()*2) //looks cooler than them all appearing at once. Gives the impression of burst fire. - log_admin("Centcom Supplypod Launch: [key_name(user)] launched a supplypod in [AREACOORD(target)]") /datum/centcom_podlauncher/proc/refreshBay() //Called whenever the bay is switched, as well as wheneber a pod is launched orderedArea = createOrderedArea(bay) //Create an ordered list full of turfs form the bay @@ -486,11 +542,11 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm if (launchClone) //We arent launching the actual items from the bay, rather we are creating clones and launching those for (var/atom/movable/O in launchList) DuplicateObject(O).forceMove(toLaunch) //Duplicate each atom/movable in launchList and forceMove them into the supplypod - new /obj/effect/DPtarget(A, toLaunch) //Create the DPTarget, which will eventually forceMove the temp_pod to it's location - else + new /obj/effect/abstract/DPtarget(A, toLaunch) //Create the DPTarget, which will eventually forceMove the temp_pod to it's location + else for (var/atom/movable/O in launchList) //If we aren't cloning the objects, just go through the launchList O.forceMove(toLaunch) //and forceMove any atom/moveable into the supplypod - new /obj/effect/DPtarget(A, toLaunch) //Then, create the DPTarget effect, which will eventually forceMove the temp_pod to it's location + new /obj/effect/abstract/DPtarget(A, toLaunch) //Then, create the DPTarget effect, which will eventually forceMove the temp_pod to it's location if (launchClone) launchCounter++ //We only need to increment launchCounter if we are cloning objects. //If we aren't cloning objects, taking and removing the first item each time from the acceptableTurfs list will inherently iterate through the list in order @@ -508,4 +564,26 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm updateCursor(FALSE) //Make sure our moues cursor resets to default. False means we are not in launch mode qdel(temp_pod) //Delete the temp_pod qdel(selector) //Delete the selector effect - . = ..() \ No newline at end of file + . = ..() + +/datum/centcom_podlauncher/proc/supplypod_punish_log(var/list/whoDyin) + var/podString = effectBurst ? "5 pods" : "a pod" + var/whomString = "" + if (LAZYLEN(whoDyin)) + for (var/mob/living/M in whoDyin) + whomString += "[key_name(M)], " + + var/delayString = temp_pod.landingDelay == initial(temp_pod.landingDelay) ? "" : " Delay=[temp_pod.landingDelay*0.1]s" + var/damageString = temp_pod.damage == 0 ? "" : " Dmg=[temp_pod.damage]" + var/explosionString = "" + var/explosion_sum = temp_pod.explosionSize[1] + temp_pod.explosionSize[2] + temp_pod.explosionSize[3] + temp_pod.explosionSize[4] + if (explosion_sum != 0) + explosionString = " Boom=|" + for (var/X in temp_pod.explosionSize) + explosionString += "[X]|" + + var/msg = "launched [podString][whomString].[delayString][damageString][explosionString]]" + message_admins("[key_name_admin(usr)] [msg] in [AREACOORD(specificTarget)].") + if (!isemptylist(whoDyin)) + for (var/mob/living/M in whoDyin) + admin_ticket_log(M, "[key_name_admin(usr)] [msg]") diff --git a/code/modules/cargo/expressconsole.dm b/code/modules/cargo/expressconsole.dm index 642719c8..b0a814b6 100644 --- a/code/modules/cargo/expressconsole.dm +++ b/code/modules/cargo/expressconsole.dm @@ -1,206 +1,206 @@ -#define MAX_EMAG_ROCKETS 8 -#define BEACON_COST 5000 -#define SP_LINKED 1 -#define SP_READY 2 -#define SP_LAUNCH 3 -#define SP_UNLINK 4 -#define SP_UNREADY 5 - -/obj/machinery/computer/cargo/express - name = "express supply console" - desc = "This console allows the user to purchase a package \ - with 1/40th of the delivery time: made possible by Kinaris's new \"1500mm Orbital Railgun\".\ - All sales are near instantaneous - please choose carefully" - icon_screen = "supply_express" - circuit = /obj/item/circuitboard/computer/cargo/express - blockade_warning = "Bluespace instability detected. Delivery impossible." - req_access = list(ACCESS_QM) - var/message - var/printed_beacons = 0 //number of beacons printed. Used to determine beacon names. - var/list/meme_pack_data - var/obj/item/supplypod_beacon/beacon //the linked supplypod beacon - var/area/landingzone = /area/quartermaster/storage //where we droppin boys - var/podType = /obj/structure/closet/supplypod - var/cooldown = 0 //cooldown to prevent printing supplypod beacon spam - var/locked = TRUE //is the console locked? unlock with ID - var/usingBeacon = FALSE //is the console in beacon mode? exists to let beacon know when a pod may come in - -/obj/machinery/computer/cargo/express/Initialize() - . = ..() - packin_up() - -/obj/machinery/computer/cargo/express/Destroy() - if(beacon) - beacon.unlink_console() - return ..() - -/obj/machinery/computer/cargo/express/attackby(obj/item/W, mob/living/user, params) - if((istype(W, /obj/item/card/id) || istype(W, /obj/item/pda)) && allowed(user)) - locked = !locked - to_chat(user, "You [locked ? "lock" : "unlock"] the interface.") - return - else if(istype(W, /obj/item/disk/cargo/bluespace_pod)) - podType = /obj/structure/closet/supplypod/bluespacepod - to_chat(user, "You insert the disk into [src], allowing for advanced supply delivery vehicles.") - qdel(W) - return TRUE - else if(istype(W, /obj/item/supplypod_beacon)) - var/obj/item/supplypod_beacon/sb = W - if (sb.express_console != src) - sb.link_console(src, user) - return TRUE - else - to_chat(user, "[src] is already linked to [sb].") - ..() - -/obj/machinery/computer/cargo/express/emag_act(mob/living/user) - . = SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT) - if(obj_flags & EMAGGED) - return - user.visible_message("[user] swipes a suspicious card through [src]!", - "You change the routing protocols, allowing the Supply Pod to land anywhere on the station.") - obj_flags |= EMAGGED - // This also sets this on the circuit board - var/obj/item/circuitboard/computer/cargo/board = circuit - board.obj_flags |= EMAGGED - packin_up() - req_access = list() - return TRUE - -/obj/machinery/computer/cargo/express/proc/packin_up() // oh shit, I'm sorry - meme_pack_data = list() // sorry for what? - for(var/pack in SSshuttle.supply_packs) // our quartermaster taught us not to be ashamed of our supply packs - var/datum/supply_pack/P = SSshuttle.supply_packs[pack] // specially since they're such a good price and all - if(!meme_pack_data[P.group]) // yeah, I see that, your quartermaster gave you good advice - meme_pack_data[P.group] = list( // it gets cheaper when I return it - "name" = P.group, // mmhm - "packs" = list() // sometimes, I return it so much, I rip the manifest - ) // see, my quartermaster taught me a few things too - if((P.hidden) || (P.special)) // like, how not to rip the manifest - continue// by using someone else's crate - if(!(obj_flags & EMAGGED) && P.contraband) // will you show me? - continue // i'd be right happy to - meme_pack_data[P.group]["packs"] += list(list( - "name" = P.name, - "cost" = P.cost, - "id" = pack, - "desc" = P.desc || P.name // If there is a description, use it. Otherwise use the pack's name. - )) - -/obj/machinery/computer/cargo/express/ui_interact(mob/living/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state. - ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "cargo_express", name, 600, 700, master_ui, state) - ui.open() - -/obj/machinery/computer/cargo/express/ui_data(mob/user) - var/canBeacon = beacon && (isturf(beacon.loc) || ismob(beacon.loc))//is the beacon in a valid location? - var/list/data = list() - data["locked"] = locked//swipe an ID to unlock - data["siliconUser"] = user.has_unlimited_silicon_privilege - data["beaconzone"] = beacon ? get_area(beacon) : ""//where is the beacon located? outputs in the tgui - data["usingBeacon"] = usingBeacon //is the mode set to deliver to the beacon or the cargobay? - data["canBeacon"] = !usingBeacon || canBeacon //is the mode set to beacon delivery, and is the beacon in a valid location? - data["canBuyBeacon"] = cooldown <= 0 && SSshuttle.points >= BEACON_COST - data["beaconError"] = usingBeacon && !canBeacon ? "(BEACON ERROR)" : ""//changes button text to include an error alert if necessary - data["hasBeacon"] = beacon != null//is there a linked beacon? - data["beaconName"] = beacon ? beacon.name : "No Beacon Found" - data["printMsg"] = cooldown > 0 ? "Print Beacon for [BEACON_COST] credits ([cooldown])" : "Print Beacon for [BEACON_COST] credits"//buttontext for printing beacons - data["points"] = SSshuttle.points - data["supplies"] = list() - message = "Sales are near-instantaneous - please choose carefully." - if(SSshuttle.supplyBlocked) - message = blockade_warning - if(usingBeacon && !beacon) - message = "BEACON ERROR: BEACON MISSING"//beacon was destroyed - else if (usingBeacon && !canBeacon) - message = "BEACON ERROR: MUST BE EXPOSED"//beacon's loc/user's loc must be a turf - if(obj_flags & EMAGGED) - message = "(&!#@ERROR: ROUTING_#PROTOCOL MALF(*CT#ON. $UG%ESTE@ ACT#0N: !^/PULS3-%E)ET CIR*)ITB%ARD." - data["message"] = message - if(!meme_pack_data) - packin_up() - stack_trace("You didn't give the cargo tech good advice, and he ripped the manifest. As a result, there was no pack data for [src]") - data["supplies"] = meme_pack_data - if (cooldown > 0)//cooldown used for printing beacons - cooldown-- - return data - -/obj/machinery/computer/cargo/express/ui_act(action, params, datum/tgui/ui) - switch(action) - if("LZCargo") - usingBeacon = FALSE - if (beacon) - beacon.update_status(SP_UNREADY) //ready light on beacon will turn off - if("LZBeacon") - usingBeacon = TRUE - if (beacon) - beacon.update_status(SP_READY) //turns on the beacon's ready light - if("printBeacon") - if (SSshuttle.points >= BEACON_COST) - cooldown = 10//a ~ten second cooldown for printing beacons to prevent spam - var/obj/item/supplypod_beacon/C = new /obj/item/supplypod_beacon(drop_location()) - C.link_console(src, usr)//rather than in beacon's Initialize(), we can assign the computer to the beacon by reusing this proc) - printed_beacons++//printed_beacons starts at 0, so the first one out will be called beacon # 1 - beacon.name = "Supply Pod Beacon #[printed_beacons]" - SSshuttle.points -= BEACON_COST - - if("add")//Generate Supply Order first - var/id = text2path(params["id"]) - var/datum/supply_pack/pack = SSshuttle.supply_packs[id] - if(!istype(pack)) - return - var/name = "*None Provided*" - var/rank = "*None Provided*" - var/ckey = usr.ckey - if(ishuman(usr)) - var/mob/living/carbon/human/H = usr - name = H.get_authentification_name() - rank = H.get_assignment(hand_first = TRUE) - else if(issilicon(usr)) - name = usr.real_name - rank = "Silicon" - var/reason = "" - var/list/empty_turfs - var/datum/supply_order/SO = new(pack, name, rank, ckey, reason) - if(!(obj_flags & EMAGGED)) - if(SO.pack.cost <= SSshuttle.points) - var/LZ - if (istype(beacon) && usingBeacon)//prioritize beacons over landing in cargobay - LZ = get_turf(beacon) - beacon.update_status(SP_LAUNCH) - else if (!usingBeacon)//find a suitable supplypod landing zone in cargobay - landingzone = GLOB.areas_by_type[/area/quartermaster/storage] - if (!landingzone) - WARNING("[src] couldnt find a Quartermaster/Storage (aka cargobay) area on the station, and as such it has set the supplypod landingzone to the area it resides in.") - landingzone = get_area(src) - for(var/turf/open/floor/T in landingzone.contents)//uses default landing zone - if(is_blocked_turf(T)) - continue - LAZYADD(empty_turfs, T) - CHECK_TICK - if(empty_turfs && empty_turfs.len) - LZ = pick(empty_turfs) - if (SO.pack.cost <= SSshuttle.points && LZ)//we need to call the cost check again because of the CHECK_TICK call - SSshuttle.points -= SO.pack.cost - new /obj/effect/DPtarget(LZ, podType, SO) - . = TRUE - update_icon() - else - if(SO.pack.cost * (0.72*MAX_EMAG_ROCKETS) <= SSshuttle.points) // bulk discount :^) - landingzone = GLOB.areas_by_type[pick(GLOB.the_station_areas)] //override default landing zone - for(var/turf/open/floor/T in landingzone.contents) - if(is_blocked_turf(T)) - continue - LAZYADD(empty_turfs, T) - CHECK_TICK - if(empty_turfs && empty_turfs.len) - SSshuttle.points -= SO.pack.cost * (0.72*MAX_EMAG_ROCKETS) - SO.generateRequisition(get_turf(src)) - for(var/i in 1 to MAX_EMAG_ROCKETS) - var/LZ = pick(empty_turfs) - LAZYREMOVE(empty_turfs, LZ) - new /obj/effect/DPtarget(LZ, podType, SO) - . = TRUE - update_icon() - CHECK_TICK +#define MAX_EMAG_ROCKETS 8 +#define BEACON_COST 5000 +#define SP_LINKED 1 +#define SP_READY 2 +#define SP_LAUNCH 3 +#define SP_UNLINK 4 +#define SP_UNREADY 5 + +/obj/machinery/computer/cargo/express + name = "express supply console" + desc = "This console allows the user to purchase a package \ + with 1/40th of the delivery time: made possible by Kinaris's new \"1500mm Orbital Railgun\".\ + All sales are near instantaneous - please choose carefully" + icon_screen = "supply_express" + circuit = /obj/item/circuitboard/computer/cargo/express + blockade_warning = "Bluespace instability detected. Delivery impossible." + req_access = list(ACCESS_QM) + var/message + var/printed_beacons = 0 //number of beacons printed. Used to determine beacon names. + var/list/meme_pack_data + var/obj/item/supplypod_beacon/beacon //the linked supplypod beacon + var/area/landingzone = /area/quartermaster/storage //where we droppin boys + var/podType = /obj/structure/closet/supplypod + var/cooldown = 0 //cooldown to prevent printing supplypod beacon spam + var/locked = TRUE //is the console locked? unlock with ID + var/usingBeacon = FALSE //is the console in beacon mode? exists to let beacon know when a pod may come in + +/obj/machinery/computer/cargo/express/Initialize() + . = ..() + packin_up() + +/obj/machinery/computer/cargo/express/Destroy() + if(beacon) + beacon.unlink_console() + return ..() + +/obj/machinery/computer/cargo/express/attackby(obj/item/W, mob/living/user, params) + if((istype(W, /obj/item/card/id) || istype(W, /obj/item/pda)) && allowed(user)) + locked = !locked + to_chat(user, "You [locked ? "lock" : "unlock"] the interface.") + return + else if(istype(W, /obj/item/disk/cargo/bluespace_pod)) + podType = /obj/structure/closet/supplypod/bluespacepod + to_chat(user, "You insert the disk into [src], allowing for advanced supply delivery vehicles.") + qdel(W) + return TRUE + else if(istype(W, /obj/item/supplypod_beacon)) + var/obj/item/supplypod_beacon/sb = W + if (sb.express_console != src) + sb.link_console(src, user) + return TRUE + else + to_chat(user, "[src] is already linked to [sb].") + ..() + +/obj/machinery/computer/cargo/express/emag_act(mob/living/user) + . = SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT) + if(obj_flags & EMAGGED) + return + user.visible_message("[user] swipes a suspicious card through [src]!", + "You change the routing protocols, allowing the Supply Pod to land anywhere on the station.") + obj_flags |= EMAGGED + // This also sets this on the circuit board + var/obj/item/circuitboard/computer/cargo/board = circuit + board.obj_flags |= EMAGGED + packin_up() + req_access = list() + return TRUE + +/obj/machinery/computer/cargo/express/proc/packin_up() // oh shit, I'm sorry + meme_pack_data = list() // sorry for what? + for(var/pack in SSshuttle.supply_packs) // our quartermaster taught us not to be ashamed of our supply packs + var/datum/supply_pack/P = SSshuttle.supply_packs[pack] // specially since they're such a good price and all + if(!meme_pack_data[P.group]) // yeah, I see that, your quartermaster gave you good advice + meme_pack_data[P.group] = list( // it gets cheaper when I return it + "name" = P.group, // mmhm + "packs" = list() // sometimes, I return it so much, I rip the manifest + ) // see, my quartermaster taught me a few things too + if((P.hidden) || (P.special)) // like, how not to rip the manifest + continue// by using someone else's crate + if(!(obj_flags & EMAGGED) && P.contraband) // will you show me? + continue // i'd be right happy to + meme_pack_data[P.group]["packs"] += list(list( + "name" = P.name, + "cost" = P.cost, + "id" = pack, + "desc" = P.desc || P.name // If there is a description, use it. Otherwise use the pack's name. + )) + +/obj/machinery/computer/cargo/express/ui_interact(mob/living/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state. + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "cargo_express", name, 600, 700, master_ui, state) + ui.open() + +/obj/machinery/computer/cargo/express/ui_data(mob/user) + var/canBeacon = beacon && (isturf(beacon.loc) || ismob(beacon.loc))//is the beacon in a valid location? + var/list/data = list() + data["locked"] = locked//swipe an ID to unlock + data["siliconUser"] = user.has_unlimited_silicon_privilege + data["beaconzone"] = beacon ? get_area(beacon) : ""//where is the beacon located? outputs in the tgui + data["usingBeacon"] = usingBeacon //is the mode set to deliver to the beacon or the cargobay? + data["canBeacon"] = !usingBeacon || canBeacon //is the mode set to beacon delivery, and is the beacon in a valid location? + data["canBuyBeacon"] = cooldown <= 0 && SSshuttle.points >= BEACON_COST + data["beaconError"] = usingBeacon && !canBeacon ? "(BEACON ERROR)" : ""//changes button text to include an error alert if necessary + data["hasBeacon"] = beacon != null//is there a linked beacon? + data["beaconName"] = beacon ? beacon.name : "No Beacon Found" + data["printMsg"] = cooldown > 0 ? "Print Beacon for [BEACON_COST] credits ([cooldown])" : "Print Beacon for [BEACON_COST] credits"//buttontext for printing beacons + data["points"] = SSshuttle.points + data["supplies"] = list() + message = "Sales are near-instantaneous - please choose carefully." + if(SSshuttle.supplyBlocked) + message = blockade_warning + if(usingBeacon && !beacon) + message = "BEACON ERROR: BEACON MISSING"//beacon was destroyed + else if (usingBeacon && !canBeacon) + message = "BEACON ERROR: MUST BE EXPOSED"//beacon's loc/user's loc must be a turf + if(obj_flags & EMAGGED) + message = "(&!#@ERROR: ROUTING_#PROTOCOL MALF(*CT#ON. $UG%ESTE@ ACT#0N: !^/PULS3-%E)ET CIR*)ITB%ARD." + data["message"] = message + if(!meme_pack_data) + packin_up() + stack_trace("You didn't give the cargo tech good advice, and he ripped the manifest. As a result, there was no pack data for [src]") + data["supplies"] = meme_pack_data + if (cooldown > 0)//cooldown used for printing beacons + cooldown-- + return data + +/obj/machinery/computer/cargo/express/ui_act(action, params, datum/tgui/ui) + switch(action) + if("LZCargo") + usingBeacon = FALSE + if (beacon) + beacon.update_status(SP_UNREADY) //ready light on beacon will turn off + if("LZBeacon") + usingBeacon = TRUE + if (beacon) + beacon.update_status(SP_READY) //turns on the beacon's ready light + if("printBeacon") + if (SSshuttle.points >= BEACON_COST) + cooldown = 10//a ~ten second cooldown for printing beacons to prevent spam + var/obj/item/supplypod_beacon/C = new /obj/item/supplypod_beacon(drop_location()) + C.link_console(src, usr)//rather than in beacon's Initialize(), we can assign the computer to the beacon by reusing this proc) + printed_beacons++//printed_beacons starts at 0, so the first one out will be called beacon # 1 + beacon.name = "Supply Pod Beacon #[printed_beacons]" + SSshuttle.points -= BEACON_COST + + if("add")//Generate Supply Order first + var/id = text2path(params["id"]) + var/datum/supply_pack/pack = SSshuttle.supply_packs[id] + if(!istype(pack)) + return + var/name = "*None Provided*" + var/rank = "*None Provided*" + var/ckey = usr.ckey + if(ishuman(usr)) + var/mob/living/carbon/human/H = usr + name = H.get_authentification_name() + rank = H.get_assignment(hand_first = TRUE) + else if(issilicon(usr)) + name = usr.real_name + rank = "Silicon" + var/reason = "" + var/list/empty_turfs + var/datum/supply_order/SO = new(pack, name, rank, ckey, reason) + if(!(obj_flags & EMAGGED)) + if(SO.pack.cost <= SSshuttle.points) + var/LZ + if (istype(beacon) && usingBeacon)//prioritize beacons over landing in cargobay + LZ = get_turf(beacon) + beacon.update_status(SP_LAUNCH) + else if (!usingBeacon)//find a suitable supplypod landing zone in cargobay + landingzone = GLOB.areas_by_type[/area/quartermaster/storage] + if (!landingzone) + WARNING("[src] couldnt find a Quartermaster/Storage (aka cargobay) area on the station, and as such it has set the supplypod landingzone to the area it resides in.") + landingzone = get_area(src) + for(var/turf/open/floor/T in landingzone.contents)//uses default landing zone + if(is_blocked_turf(T)) + continue + LAZYADD(empty_turfs, T) + CHECK_TICK + if(empty_turfs && empty_turfs.len) + LZ = pick(empty_turfs) + if (SO.pack.cost <= SSshuttle.points && LZ)//we need to call the cost check again because of the CHECK_TICK call + SSshuttle.points -= SO.pack.cost + new /obj/effect/abstract/DPtarget(LZ, podType, SO) + . = TRUE + update_icon() + else + if(SO.pack.cost * (0.72*MAX_EMAG_ROCKETS) <= SSshuttle.points) // bulk discount :^) + landingzone = GLOB.areas_by_type[pick(GLOB.the_station_areas)] //override default landing zone + for(var/turf/open/floor/T in landingzone.contents) + if(is_blocked_turf(T)) + continue + LAZYADD(empty_turfs, T) + CHECK_TICK + if(empty_turfs && empty_turfs.len) + SSshuttle.points -= SO.pack.cost * (0.72*MAX_EMAG_ROCKETS) + SO.generateRequisition(get_turf(src)) + for(var/i in 1 to MAX_EMAG_ROCKETS) + var/LZ = pick(empty_turfs) + LAZYREMOVE(empty_turfs, LZ) + new /obj/effect/abstract/DPtarget(LZ, podType, SO) + . = TRUE + update_icon() + CHECK_TICK diff --git a/code/modules/cargo/gondolapod.dm b/code/modules/cargo/gondolapod.dm index f36ff0ce..7b78facf 100644 --- a/code/modules/cargo/gondolapod.dm +++ b/code/modules/cargo/gondolapod.dm @@ -39,15 +39,22 @@ set name = "Release Contents" set category = "Gondola" set desc = "Release any contents stored within your vast belly." - linked_pod.open(src, manual = TRUE) + linked_pod.open(src, forced = TRUE) + +/mob/living/simple_animal/pet/gondola/gondolapod/examine(mob/user) + ..() + if (contents.len) + to_chat(user, "It looks like it hasn't made its delivery yet.
") + else + to_chat(user, "It looks like it has already made its delivery.
") /mob/living/simple_animal/pet/gondola/gondolapod/verb/check() set name = "Count Contents" set category = "Gondola" set desc = "Take a deep look inside youself, and count up what's inside" var/total = contents.len - if (total) - to_chat(src, "You detect [total] object[total > 1 ? "s" : ""] within your incredibly vast belly.") + if (total) + to_chat(src, "You detect [total] object\s within your incredibly vast belly.") else to_chat(src, "A closer look inside yourself reveals... nothing.") diff --git a/code/modules/cargo/supplypod.dm b/code/modules/cargo/supplypod.dm index f5e203cd..7e568dae 100644 --- a/code/modules/cargo/supplypod.dm +++ b/code/modules/cargo/supplypod.dm @@ -15,15 +15,17 @@ armor = list("melee" = 30, "bullet" = 50, "laser" = 50, "energy" = 100, "bomb" = 100, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 80) anchored = TRUE //So it cant slide around after landing anchorable = FALSE + flags_1 = PREVENT_CONTENTS_EXPLOSION_1 //*****NOTE*****: Many of these comments are similarly described in centcom_podlauncher.dm. If you change them here, please consider doing so in the centcom podlauncher code as well! var/adminNamed = FALSE //Determines whether or not the pod has been named by an admin. If true, the pod's name will not get overridden when the style of the pod changes (changing the style of the pod normally also changes the name+desc) var/bluespace = FALSE //If true, the pod deletes (in a shower of sparks) after landing var/landingDelay = 30 //How long the pod takes to land after launching var/openingDelay = 30 //How long the pod takes to open after landing - var/departureDelay = 30 //How long the pod takes to leave after opening (if bluespace=true, it deletes. if reversing=true, it flies back to centcom) + var/departureDelay = 30 //How long the pod takes to leave after opening. If bluespace = TRUE, it deletes. If reversing = TRUE, it flies back to centcom. var/damage = 0 //Damage that occurs to any mob under the pod when it lands. var/effectStun = FALSE //If true, stuns anyone under the pod when it launches until it lands, forcing them to get hit by the pod. Devilish! var/effectLimb = FALSE //If true, pops off a limb (if applicable) from anyone caught under the pod when it lands + var/effectOrgans = FALSE //If true, yeets out every limb and organ from anyone caught under the pod when it lands var/effectGib = FALSE //If true, anyone under the pod will be gibbed when it lands var/effectStealth = FALSE //If true, a target icon isnt displayed on the turf where the pod will land var/effectQuiet = FALSE //The female sniper. If true, the pod makes no noise (including related explosions, opening sounds, etc) @@ -31,10 +33,13 @@ var/effectCircle = FALSE //If true, allows the pod to come in at any angle. Bit of a weird feature but whatever its here var/style = STYLE_STANDARD //Style is a variable that keeps track of what the pod is supposed to look like. It acts as an index to the POD_STYLES list in cargo.dm defines to get the proper icon/name/desc for the pod. var/reversing = FALSE //If true, the pod will not send any items. Instead, after opening, it will close again (picking up items/mobs) and fly back to centcom + var/fallDuration = 4 + var/fallingSoundLength = 11 + var/fallingSound = 'sound/weapons/mortar_long_whistle.ogg'//Admin sound to play before the pod lands var/landingSound //Admin sound to play when the pod lands var/openingSound //Admin sound to play when the pod opens var/leavingSound //Admin sound to play when the pod leaves - var/soundVolume = 50 //Volume to play sounds at. Ignores the cap + var/soundVolume = 80 //Volume to play sounds at. Ignores the cap var/bay //Used specifically for the centcom_podlauncher datum. Holds the current bay the user is launching objects from. Bays are specific rooms on the centcom map. var/list/explosionSize = list(0,0,2,3) @@ -48,16 +53,18 @@ style = STYLE_CENTCOM bluespace = TRUE explosionSize = list(0,0,0,0) - landingDelay = 5 //Very speedy! + landingDelay = 20 //Very speedy! resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF /obj/structure/closet/supplypod/Initialize() - ..() + . = ..() setStyle(style, TRUE) //Upon initialization, give the supplypod an iconstate, name, and description based on the "style" variable. This system is important for the centcom_podlauncher to function correctly /obj/structure/closet/supplypod/update_icon() cut_overlays() - if (style != STYLE_INVISIBLE) //If we're invisible, we dont bother adding any overlays + if (style == STYLE_SEETHROUGH || style == STYLE_INVISIBLE) //If we're invisible, we dont bother adding any overlays + return + else if (opened) add_overlay("[icon_state]_open") else @@ -75,7 +82,7 @@ update_icon() /obj/structure/closet/supplypod/tool_interact(obj/item/W, mob/user) - if (bluespace) //We dont want to worry about interacting with bluespace pods, as they are due to delete themselves soon anyways. + if(bluespace) //We dont want to worry about interacting with bluespace pods, as they are due to delete themselves soon anyways. return FALSE else ..() @@ -86,9 +93,6 @@ /obj/structure/closet/supplypod/contents_explosion() //Supplypods also protect their contents from the harmful effects of fucking exploding. return -/obj/structure/closet/supplypod/prevent_content_explosion() //Useful for preventing epicenter explosions from damaging contents - return TRUE - /obj/structure/closet/supplypod/toggle(mob/living/user) //Supplypods shouldn't be able to be manually opened under any circumstances, as the open() proc generates supply order datums return @@ -101,17 +105,33 @@ if (effectLimb && iscarbon(M)) //If effectLimb is true (which means we pop limbs off when we hit people): var/mob/living/carbon/CM = M for (var/obj/item/bodypart/bodypart in CM.bodyparts) //Look at the bodyparts in our poor mob beneath our pod as it lands - if(bodypart.body_part != HEAD && bodypart.body_zone != CHEST)//we dont want to kill him, just teach em a lesson! + if(bodypart.body_part != HEAD && bodypart.body_part != CHEST)//we dont want to kill him, just teach em a lesson! if (bodypart.dismemberable) bodypart.dismember() //Using the power of flextape i've sawed this man's limb in half! break + if (effectOrgans && iscarbon(M)) //effectOrgans means remove every organ in our mob + var/mob/living/carbon/CM = M + for(var/X in CM.internal_organs) + var/destination = get_edge_target_turf(T, pick(GLOB.alldirs)) //Pick a random direction to toss them in + var/obj/item/organ/O = X + O.Remove(CM) //Note that this isn't the same proc as for lists + O.forceMove(T) //Move the organ outta the body + O.throw_at(destination, 2, 3) //Thow the organ at a random tile 3 spots away + sleep(1) + for (var/obj/item/bodypart/bodypart in CM.bodyparts) //Look at the bodyparts in our poor mob beneath our pod as it lands + var/destination = get_edge_target_turf(T, pick(GLOB.alldirs)) + if (bodypart.dismemberable) + bodypart.dismember() //Using the power of flextape i've sawed this man's bodypart in half! + bodypart.throw_at(destination, 2, 3) + sleep(1) + if (effectGib) //effectGib is on, that means whatever's underneath us better be fucking oof'd on M.adjustBruteLoss(5000) //THATS A LOT OF DAMAGE (called just in case gib() doesnt work on em) M.gib() //After adjusting the fuck outta that brute loss we finish the job with some satisfying gibs - M.adjustBruteLoss(damage) - - - if (B[1] || B[2] || B[3] || B[4]) //If the explosion list isn't all zeroes, call an explosion + else + M.adjustBruteLoss(damage) + var/explosion_sum = B[1] + B[2] + B[3] + B[4] + if (explosion_sum != 0) //If the explosion list isn't all zeroes, call an explosion explosion(get_turf(src), B[1], B[2], B[3], flame_range = B[4], silent = effectQuiet, ignorecap = istype(src, /obj/structure/closet/supplypod/centcompod)) //less advanced equipment than bluespace pod, so larger explosion when landing else if (!effectQuiet) //If our explosion list IS all zeroes, we still make a nice explosion sound (unless the effectQuiet var is true) playsound(src, "explosion", landingSound ? 15 : 80, 1) @@ -128,22 +148,31 @@ /obj/structure/closet/supplypod/open(atom/movable/holder, var/broken = FALSE, var/forced = FALSE) //The holder var represents an atom whose contents we will be working with var/turf/T = get_turf(holder) //Get the turf of whoever's contents we're talking about + if (!holder) + return + if(opened) + return + opened = TRUE //This is to ensure we don't open something that has already been opened var/mob/M if (istype(holder, /mob)) //Allows mobs to assume the role of the holder, meaning we look at the mob's contents rather than the supplypod's contents. Typically by this point the supplypod's contents have already been moved over to the mob's contents M = holder if (M.key && !forced && !broken) //If we are player controlled, then we shouldnt open unless the opening is manual, or if it is due to being destroyed (represented by the "broken" parameter) return - opened = TRUE //This is to ensure we don't open something that has already been opened if (openingSound) - playsound(get_turf(holder), openingSound, soundVolume, 0, 0) + playsound(get_turf(holder), openingSound, soundVolume, 0, 0) //Special admin sound to play INVOKE_ASYNC(holder, .proc/setOpened) //Use the INVOKE_ASYNC proc to call setOpened() on whatever the holder may be, without giving the atom/movable base class a setOpened() proc definition + if (style == STYLE_SEETHROUGH) + update_icon() for (var/atom/movable/O in holder.contents) //Go through the contents of the holder O.forceMove(T) //move everything from the contents of the holder to the turf of the holder - if (!effectQuiet) //If we aren't being quiet, play an open sound + if (!effectQuiet && !openingSound && style != STYLE_SEETHROUGH) //If we aren't being quiet, play the default pod open sound playsound(get_turf(holder), open_sound, 15, 1, -3) if (broken) //If the pod is opening because it's been destroyed, we end here return - addtimer(CALLBACK(src, .proc/depart, holder), departureDelay) //Finish up the pod's duties after a certain amount of time + if (style == STYLE_SEETHROUGH) + depart(src) + else + addtimer(CALLBACK(src, .proc/depart, holder), departureDelay) //Finish up the pod's duties after a certain amount of time /obj/structure/closet/supplypod/proc/depart(atom/movable/holder) if (leavingSound) @@ -151,7 +180,7 @@ if (reversing) //If we're reversing, we call the close proc. This sends the pod back up to centcom close(holder) else if (bluespace) //If we're a bluespace pod, then delete ourselves (along with our holder, if a seperate holder exists) - if (style != STYLE_INVISIBLE) + if (!effectQuiet && style != STYLE_INVISIBLE && style != STYLE_SEETHROUGH) do_sparks(5, TRUE, holder) //Create some sparks right before closing qdel(src) //Delete ourselves and the holder if (holder != src) @@ -164,13 +193,14 @@ if (ismob(O) && !isliving(O)) //We dont want to take ghosts with us continue O.forceMove(holder) //Put objects inside before we close - var/obj/effect/temp_visual/risingPod = new /obj/effect/temp_visual/DPfall(get_turf(holder), src) //Make a nice animation of flying back up + var/obj/effect/temp_visual/risingPod = new /obj/effect/abstract/DPfall(get_turf(holder), src) //Make a nice animation of flying back up risingPod.pixel_z = 0 //The initial value of risingPod's pixel_z is 200 because it normally comes down from a high spot holder.forceMove(bay) //Move the pod back to centcom, where it belongs animate(risingPod, pixel_z = 200, time = 10, easing = LINEAR_EASING) //Animate our rising pod + QDEL_IN(risingPod, 10) reversing = FALSE //Now that we're done reversing, we set this to false (otherwise we would get stuck in an infinite loop of calling the close proc at the bottom of open() ) + bluespace = TRUE //Make it so that the pod doesn't stay in centcom forever open(holder, forced = TRUE) - return /obj/structure/closet/supplypod/proc/setOpened() //Proc exists here, as well as in any atom that can assume the role of a "holder" of a supplypod. Check the open() proc for more details update_icon() @@ -179,12 +209,11 @@ update_icon() /obj/structure/closet/supplypod/Destroy() - if (!opened) //If we havent opened yet, we're opening because we've been destroyed. Lets dump our contents by opening up - open(src, broken = TRUE) - return ..() + open(src, broken = TRUE) //Lets dump our contents by opening up + . = ..() //------------------------------------FALLING SUPPLY POD-------------------------------------// -/obj/effect/temp_visual/DPfall //Falling pod +/obj/effect/abstract/DPfall //Falling pod name = "" icon = 'icons/obj/supplypods.dmi' pixel_x = -16 @@ -192,17 +221,22 @@ pixel_z = 200 desc = "Get out of the way!" layer = FLY_LAYER//that wasnt flying, that was falling with style! - randomdir = FALSE icon_state = "" -/obj/effect/temp_visual/DPfall/Initialize(dropLocation, obj/structure/closet/supplypod/pod) - if (pod.style != STYLE_INVISIBLE) //Check to ensure the pod isn't invisible +/obj/effect/abstract/DPfall/Initialize(dropLocation, obj/structure/closet/supplypod/pod) + if (pod.style == STYLE_SEETHROUGH) + pixel_x = -16 + pixel_y = 0 + for (var/atom/movable/O in pod.contents) + var/icon/I = getFlatIcon(O) //im so sorry + add_overlay(I) + else if (pod.style != STYLE_INVISIBLE) //Check to ensure the pod isn't invisible icon_state = "[pod.icon_state]_falling" name = pod.name . = ..() //------------------------------------TEMPORARY_VISUAL-------------------------------------// -/obj/effect/DPtarget //This is the object that forceMoves the supplypod to it's location +/obj/effect/abstract/DPtarget //This is the object that forceMoves the supplypod to it's location name = "Landing Zone Indicator" desc = "A holographic projection designating the landing zone of something. It's probably best to stand back." icon = 'icons/mob/actions/actions_items.dmi' @@ -212,45 +246,60 @@ var/obj/effect/temp_visual/fallingPod //Temporary "falling pod" that we animate var/obj/structure/closet/supplypod/pod //The supplyPod that will be landing ontop of this target -/obj/effect/ex_act() - return - -/obj/effect/DPtarget/Initialize(mapload, podParam, var/datum/supply_order/SO = null) +/obj/effect/abstract/DPtarget/Initialize(mapload, podParam, single_order = null) + . = ..() if (ispath(podParam)) //We can pass either a path for a pod (as expressconsoles do), or a reference to an instantiated pod (as the centcom_podlauncher does) podParam = new podParam() //If its just a path, instantiate it pod = podParam - if (SO) - SO.generate(pod) - for (var/mob/living/M in podParam) //If there are any mobs in the supplypod, we want to forceMove them into the target. This is so that they can see where they are about to land, AND so that they don't get sent to the nullspace error room (as the pod is currently in nullspace) + if (single_order) + if (istype(single_order, /datum/supply_order)) + var/datum/supply_order/SO = single_order + SO.generate(pod) + else if (istype(single_order, /atom/movable)) + var/atom/movable/O = single_order + O.forceMove(pod) + for (var/mob/living/M in pod) //If there are any mobs in the supplypod, we want to forceMove them into the target. This is so that they can see where they are about to land, AND so that they don't get sent to the nullspace error room (as the pod is currently in nullspace) M.forceMove(src) if(pod.effectStun) //If effectStun is true, stun any mobs caught on this target until the pod gets a chance to hit them for (var/mob/living/M in get_turf(src)) M.Stun(pod.landingDelay+10, ignore_canstun = TRUE)//you aint goin nowhere, kid. if (pod.effectStealth) //If effectStealth is true we want to be invisible - alpha = 255 + icon_state = "" + if (pod.fallDuration == initial(pod.fallDuration) && pod.landingDelay + pod.fallDuration < pod.fallingSoundLength) + pod.fallingSoundLength = 3 //The default falling sound is a little long, so if the landing time is shorter than the default falling sound, use a special, shorter default falling sound + pod.fallingSound = 'sound/weapons/mortar_whistle.ogg' + var/soundStartTime = pod.landingDelay - pod.fallingSoundLength + pod.fallDuration + if (soundStartTime < 0) + soundStartTime = 1 + if (!pod.effectQuiet) + addtimer(CALLBACK(src, .proc/playFallingSound), soundStartTime) addtimer(CALLBACK(src, .proc/beginLaunch, pod.effectCircle), pod.landingDelay) -/obj/effect/DPtarget/proc/beginLaunch(effectCircle) //Begin the animation for the pod falling. The effectCircle param determines whether the pod gets to come in from any descent angle - fallingPod = new /obj/effect/temp_visual/DPfall(drop_location(), pod) +/obj/effect/abstract/DPtarget/proc/playFallingSound() + playsound(src, pod.fallingSound, pod.soundVolume, 1, 6) + +/obj/effect/abstract/DPtarget/proc/beginLaunch(effectCircle) //Begin the animation for the pod falling. The effectCircle param determines whether the pod gets to come in from any descent angle + fallingPod = new /obj/effect/abstract/DPfall(drop_location(), pod) var/matrix/M = matrix(fallingPod.transform) //Create a new matrix that we can rotate var/angle = effectCircle ? rand(0,360) : rand(70,110) //The angle that we can come in from - fallingPod.pixel_x = cos(angle)*200 //Use some ADVANCED MATHEMATICS to set the animated pod's position to somewhere on the edge of a circle with the center being the target - fallingPod.pixel_z = sin(angle)*200 + fallingPod.pixel_x = cos(angle)*400 //Use some ADVANCED MATHEMATICS to set the animated pod's position to somewhere on the edge of a circle with the center being the target + fallingPod.pixel_z = sin(angle)*400 var/rotation = Get_Pixel_Angle(fallingPod.pixel_z, fallingPod.pixel_x) //CUSTOM HOMEBREWED proc that is just arctan with extra steps M.Turn(rotation) //Turn our matrix accordingly fallingPod.transform = M //Transform the animated pod according to the matrix M = matrix(pod.transform) //Make another matrix based on the pod M.Turn(rotation) //Turn the matrix pod.transform = M //Turn the actual pod (Won't be visible until endLaunch() proc tho) - animate(fallingPod, pixel_z = 0, pixel_x = -16, time = 3, , easing = LINEAR_EASING) //Make the pod fall! At an angle! - addtimer(CALLBACK(src, .proc/endLaunch), 3, TIMER_CLIENT_TIME) //Go onto the last step after a very short falling animation + animate(fallingPod, pixel_z = 0, pixel_x = -16, time = pod.fallDuration, , easing = LINEAR_EASING) //Make the pod fall! At an angle! + addtimer(CALLBACK(src, .proc/endLaunch), pod.fallDuration, TIMER_CLIENT_TIME) //Go onto the last step after a very short falling animation -/obj/effect/DPtarget/proc/endLaunch() +/obj/effect/abstract/DPtarget/proc/endLaunch() + pod.update_icon() pod.forceMove(drop_location()) //The fallingPod animation is over, now's a good time to forceMove the actual pod into position + QDEL_NULL(fallingPod) //Delete the falling pod effect, because at this point its animation is over. We dont use temp_visual because we want to manually delete it as soon as the pod appears for (var/mob/living/M in src) //Remember earlier (initialization) when we moved mobs into the DPTarget so they wouldnt get lost in nullspace? Time to get them out M.forceMove(pod) pod.preOpen() //Begin supplypod open procedures. Here effects like explosions, damage, and other dangerous (and potentially admin-caused, if the centcom_podlauncher datum was used) memes will take place - QDEL_NULL(fallingPod) //The fallingPod's (the animated effect, not the actual pod) purpose is complete. It can rest easy now qdel(src) //ditto //------------------------------------UPGRADES-------------------------------------// diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm index 6c67cb3d..773167ad 100644 --- a/code/modules/events/immovable_rod.dm +++ b/code/modules/events/immovable_rod.dm @@ -1,169 +1,167 @@ -/* -Immovable rod random event. -The rod will spawn at some location outside the station, and travel in a straight line to the opposite side of the station -Everything solid in the way will be ex_act()'d -In my current plan for it, 'solid' will be defined as anything with density == 1 - ---NEOFite -*/ - -/datum/round_event_control/immovable_rod - name = "Immovable Rod" - typepath = /datum/round_event/immovable_rod - min_players = 15 - max_occurrences = 5 - var/atom/special_target - - -/datum/round_event_control/immovable_rod/admin_setup() - if(!check_rights(R_FUN)) - return - - var/aimed = alert("Aimed at current location?","Sniperod", "Yes", "No") - if(aimed == "Yes") - special_target = get_turf(usr) - -/datum/round_event/immovable_rod - announceWhen = 5 - -/datum/round_event/immovable_rod/announce(fake) - priority_announce("What the fuck was that?!", "General Alert") - -/datum/round_event/immovable_rod/start() - var/datum/round_event_control/immovable_rod/C = control - var/startside = pick(GLOB.cardinals) - var/z = pick(SSmapping.levels_by_trait(ZTRAIT_STATION)) - var/turf/startT = spaceDebrisStartLoc(startside, z) - var/turf/endT = spaceDebrisFinishLoc(startside, z) - new /obj/effect/immovablerod(startT, endT, C.special_target) - -/obj/effect/immovablerod - name = "immovable rod" - desc = "What the fuck is that?" - icon = 'icons/obj/objects.dmi' - icon_state = "immrod" - throwforce = 100 - move_force = INFINITY - move_resist = INFINITY - pull_force = INFINITY - density = TRUE - anchored = TRUE - var/mob/living/wizard - var/z_original = 0 - var/destination - var/notify = TRUE - var/atom/special_target - -/obj/effect/immovablerod/New(atom/start, atom/end, aimed_at) - ..() - SSaugury.register_doom(src, 2000) - z_original = z - destination = end - special_target = aimed_at - if(notify) - notify_ghosts("\A [src] is inbound!", - enter_link="(Click to orbit)", - source=src, action=NOTIFY_ORBIT) - GLOB.poi_list += src - - var/special_target_valid = FALSE - if(special_target) - var/turf/T = get_turf(special_target) - if(T.z == z_original) - special_target_valid = TRUE - if(special_target_valid) - walk_towards(src, special_target, 1) - else if(end && end.z==z_original) - walk_towards(src, destination, 1) - -/obj/effect/immovablerod/Topic(href, href_list) - if(href_list["orbit"]) - var/mob/dead/observer/ghost = usr - if(istype(ghost)) - ghost.ManualFollow(src) - -/obj/effect/immovablerod/Destroy() - GLOB.poi_list -= src - . = ..() - -/obj/effect/immovablerod/Moved() - if((z != z_original) || (loc == destination)) - qdel(src) - if(special_target && loc == get_turf(special_target)) - complete_trajectory() - return ..() - -/obj/effect/immovablerod/proc/complete_trajectory() - //We hit what we wanted to hit, time to go - special_target = null - destination = get_edge_target_turf(src, dir) - walk(src,0) - walk_towards(src, destination, 1) - -/obj/effect/immovablerod/ex_act(severity, target) - return 0 - -/obj/structure/closet/supplypod/prevent_content_explosion() - return TRUE - -/obj/effect/immovablerod/singularity_act() - return - -/obj/effect/immovablerod/singularity_pull() - return - -/obj/effect/immovablerod/Bump(atom/clong) - if(prob(10)) - playsound(src, 'sound/effects/bang.ogg', 50, 1) - audible_message("You hear a CLANG!") - - if(clong && prob(25)) - x = clong.x - y = clong.y - - if(special_target && clong == special_target) - complete_trajectory() - - if(isturf(clong) || isobj(clong)) - if(clong.density) - clong.ex_act(EXPLODE_HEAVY) - - else if(isliving(clong)) - penetrate(clong) - else if(istype(clong, type)) - var/obj/effect/immovablerod/other = clong - visible_message("[src] collides with [other]!\ - ") - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(2, get_turf(src)) - smoke.start() - qdel(src) - qdel(other) - -/obj/effect/immovablerod/proc/penetrate(mob/living/L) - L.visible_message("[L] is penetrated by an immovable rod!" , "The rod penetrates you!" , "You hear a CLANG!") - if(ishuman(L)) - var/mob/living/carbon/human/H = L - H.adjustBruteLoss(160) - if(L && (L.density || prob(10))) - L.ex_act(EXPLODE_HEAVY) - -obj/effect/immovablerod/attack_hand(mob/living/user) - if(ishuman(user)) - var/mob/living/carbon/human/U = user - if(U.job in list("Research Director")) - playsound(src, 'sound/effects/meteorimpact.ogg', 100, 1) - for(var/mob/M in urange(8, src)) - if(!M.stat) - shake_camera(M, 2, 3) - if(wizard) - U.visible_message("[src] transforms into [wizard] as [U] suplexes them!", "As you grab [src], it suddenly turns into [wizard] as you suplex them!") - to_chat(wizard, "You're suddenly jolted out of rod-form as [U] somehow manages to grab you, slamming you into the ground!") - wizard.Stun(60) - wizard.apply_damage(25, BRUTE) - qdel(src) - else - U.visible_message("[U] suplexes [src] into the ground!", "You suplex [src] into the ground!") - new /obj/structure/festivus/anchored(drop_location()) - new /obj/effect/anomaly/flux(drop_location()) - qdel(src) +/* +Immovable rod random event. +The rod will spawn at some location outside the station, and travel in a straight line to the opposite side of the station +Everything solid in the way will be ex_act()'d +In my current plan for it, 'solid' will be defined as anything with density == 1 + +--NEOFite +*/ + +/datum/round_event_control/immovable_rod + name = "Immovable Rod" + typepath = /datum/round_event/immovable_rod + min_players = 15 + max_occurrences = 5 + var/atom/special_target + + +/datum/round_event_control/immovable_rod/admin_setup() + if(!check_rights(R_FUN)) + return + + var/aimed = alert("Aimed at current location?","Sniperod", "Yes", "No") + if(aimed == "Yes") + special_target = get_turf(usr) + +/datum/round_event/immovable_rod + announceWhen = 5 + +/datum/round_event/immovable_rod/announce(fake) + priority_announce("What the fuck was that?!", "General Alert") + +/datum/round_event/immovable_rod/start() + var/datum/round_event_control/immovable_rod/C = control + var/startside = pick(GLOB.cardinals) + var/z = pick(SSmapping.levels_by_trait(ZTRAIT_STATION)) + var/turf/startT = spaceDebrisStartLoc(startside, z) + var/turf/endT = spaceDebrisFinishLoc(startside, z) + new /obj/effect/immovablerod(startT, endT, C.special_target) + +/obj/effect/immovablerod + name = "immovable rod" + desc = "What the fuck is that?" + icon = 'icons/obj/objects.dmi' + icon_state = "immrod" + throwforce = 100 + move_force = INFINITY + move_resist = INFINITY + pull_force = INFINITY + density = TRUE + anchored = TRUE + flags_1 = PREVENT_CONTENTS_EXPLOSION_1 + var/mob/living/wizard + var/z_original = 0 + var/destination + var/notify = TRUE + var/atom/special_target + +/obj/effect/immovablerod/New(atom/start, atom/end, aimed_at) + ..() + SSaugury.register_doom(src, 2000) + z_original = z + destination = end + special_target = aimed_at + if(notify) + notify_ghosts("\A [src] is inbound!", + enter_link="(Click to orbit)", + source=src, action=NOTIFY_ORBIT) + GLOB.poi_list += src + + var/special_target_valid = FALSE + if(special_target) + var/turf/T = get_turf(special_target) + if(T.z == z_original) + special_target_valid = TRUE + if(special_target_valid) + walk_towards(src, special_target, 1) + else if(end && end.z==z_original) + walk_towards(src, destination, 1) + +/obj/effect/immovablerod/Topic(href, href_list) + if(href_list["orbit"]) + var/mob/dead/observer/ghost = usr + if(istype(ghost)) + ghost.ManualFollow(src) + +/obj/effect/immovablerod/Destroy() + GLOB.poi_list -= src + . = ..() + +/obj/effect/immovablerod/Moved() + if((z != z_original) || (loc == destination)) + qdel(src) + if(special_target && loc == get_turf(special_target)) + complete_trajectory() + return ..() + +/obj/effect/immovablerod/proc/complete_trajectory() + //We hit what we wanted to hit, time to go + special_target = null + destination = get_edge_target_turf(src, dir) + walk(src,0) + walk_towards(src, destination, 1) + +/obj/effect/immovablerod/ex_act(severity, target) + return 0 + +/obj/effect/immovablerod/singularity_act() + return + +/obj/effect/immovablerod/singularity_pull() + return + +/obj/effect/immovablerod/Bump(atom/clong) + if(prob(10)) + playsound(src, 'sound/effects/bang.ogg', 50, 1) + audible_message("You hear a CLANG!") + + if(clong && prob(25)) + x = clong.x + y = clong.y + + if(special_target && clong == special_target) + complete_trajectory() + + if(isturf(clong) || isobj(clong)) + if(clong.density) + clong.ex_act(EXPLODE_HEAVY) + + else if(isliving(clong)) + penetrate(clong) + else if(istype(clong, type)) + var/obj/effect/immovablerod/other = clong + visible_message("[src] collides with [other]!\ + ") + var/datum/effect_system/smoke_spread/smoke = new + smoke.set_up(2, get_turf(src)) + smoke.start() + qdel(src) + qdel(other) + +/obj/effect/immovablerod/proc/penetrate(mob/living/L) + L.visible_message("[L] is penetrated by an immovable rod!" , "The rod penetrates you!" , "You hear a CLANG!") + if(ishuman(L)) + var/mob/living/carbon/human/H = L + H.adjustBruteLoss(160) + if(L && (L.density || prob(10))) + L.ex_act(EXPLODE_HEAVY) + +obj/effect/immovablerod/attack_hand(mob/living/user) + if(ishuman(user)) + var/mob/living/carbon/human/U = user + if(U.job in list("Research Director")) + playsound(src, 'sound/effects/meteorimpact.ogg', 100, 1) + for(var/mob/M in urange(8, src)) + if(!M.stat) + shake_camera(M, 2, 3) + if(wizard) + U.visible_message("[src] transforms into [wizard] as [U] suplexes them!", "As you grab [src], it suddenly turns into [wizard] as you suplex them!") + to_chat(wizard, "You're suddenly jolted out of rod-form as [U] somehow manages to grab you, slamming you into the ground!") + wizard.Stun(60) + wizard.apply_damage(25, BRUTE) + qdel(src) + else + U.visible_message("[U] suplexes [src] into the ground!", "You suplex [src] into the ground!") + new /obj/structure/festivus/anchored(drop_location()) + new /obj/effect/anomaly/flux(drop_location()) + qdel(src) diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 1b4aff7f..668a4c17 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -1,413 +1,411 @@ -/mob/living/silicon - gender = NEUTER - has_unlimited_silicon_privilege = 1 - verb_say = "states" - verb_ask = "queries" - verb_exclaim = "declares" - verb_yell = "alarms" - initial_language_holder = /datum/language_holder/synthetic - see_in_dark = 8 - bubble_icon = "machine" - weather_immunities = list("ash") - possible_a_intents = list(INTENT_HELP, INTENT_HARM) - mob_biotypes = list(MOB_SILICON) - rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE - speech_span = SPAN_ROBOT - - var/datum/ai_laws/laws = null//Now... THEY ALL CAN ALL HAVE LAWS - var/last_lawchange_announce = 0 - var/list/alarms_to_show = list() - var/list/alarms_to_clear = list() - var/designation = "" - var/radiomod = "" //Radio character used before state laws/arrivals announce to allow department transmissions, default, or none at all. - var/obj/item/camera/siliconcam/aicamera = null //photography - hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_TRACK_HUD) - - var/obj/item/radio/borg/radio = null //AIs dont use this but this is at the silicon level to advoid copypasta in say() - - var/list/alarm_types_show = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0) - var/list/alarm_types_clear = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0) - - var/lawcheck[1] - var/ioncheck[1] - var/hackedcheck[1] - var/devillawcheck[5] - - var/sensors_on = 0 - var/med_hud = DATA_HUD_MEDICAL_ADVANCED //Determines the med hud to use - var/sec_hud = DATA_HUD_SECURITY_ADVANCED //Determines the sec hud to use - var/d_hud = DATA_HUD_DIAGNOSTIC_BASIC //Determines the diag hud to use - - var/law_change_counter = 0 - var/obj/machinery/camera/builtInCamera = null - var/updating = FALSE //portable camera camerachunk update - - var/hack_software = FALSE //Will be able to use hacking actions - var/interaction_range = 7 //wireless control range - -/mob/living/silicon/Initialize() - . = ..() - GLOB.silicon_mobs += src - faction += "silicon" - for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds) - diag_hud.add_to_hud(src) - diag_hud_set_status() - diag_hud_set_health() - -/mob/living/silicon/med_hud_set_health() - return //we use a different hud - -/mob/living/silicon/med_hud_set_status() - return //we use a different hud - -/mob/living/silicon/Destroy() - radio = null - aicamera = null - QDEL_NULL(builtInCamera) - GLOB.silicon_mobs -= src - return ..() - -/mob/living/silicon/contents_explosion(severity, target) - return - -/mob/living/silicon/prevent_content_explosion() - return TRUE - -/mob/living/silicon/proc/cancelAlarm() - return - -/mob/living/silicon/proc/triggerAlarm() - return - -/mob/living/silicon/proc/queueAlarm(message, type, incoming = 1) - var/in_cooldown = (alarms_to_show.len > 0 || alarms_to_clear.len > 0) - if(incoming) - alarms_to_show += message - alarm_types_show[type] += 1 - else - alarms_to_clear += message - alarm_types_clear[type] += 1 - - if(!in_cooldown) - spawn(3 * 10) // 3 seconds - - if(alarms_to_show.len < 5) - for(var/msg in alarms_to_show) - to_chat(src, msg) - else if(alarms_to_show.len) - - var/msg = "--- " - - if(alarm_types_show["Burglar"]) - msg += "BURGLAR: [alarm_types_show["Burglar"]] alarms detected. - " - - if(alarm_types_show["Motion"]) - msg += "MOTION: [alarm_types_show["Motion"]] alarms detected. - " - - if(alarm_types_show["Fire"]) - msg += "FIRE: [alarm_types_show["Fire"]] alarms detected. - " - - if(alarm_types_show["Atmosphere"]) - msg += "ATMOSPHERE: [alarm_types_show["Atmosphere"]] alarms detected. - " - - if(alarm_types_show["Power"]) - msg += "POWER: [alarm_types_show["Power"]] alarms detected. - " - - if(alarm_types_show["Camera"]) - msg += "CAMERA: [alarm_types_show["Camera"]] alarms detected. - " - - msg += "\[Show Alerts\]" - to_chat(src, msg) - - if(alarms_to_clear.len < 3) - for(var/msg in alarms_to_clear) - to_chat(src, msg) - - else if(alarms_to_clear.len) - var/msg = "--- " - - if(alarm_types_clear["Motion"]) - msg += "MOTION: [alarm_types_clear["Motion"]] alarms cleared. - " - - if(alarm_types_clear["Fire"]) - msg += "FIRE: [alarm_types_clear["Fire"]] alarms cleared. - " - - if(alarm_types_clear["Atmosphere"]) - msg += "ATMOSPHERE: [alarm_types_clear["Atmosphere"]] alarms cleared. - " - - if(alarm_types_clear["Power"]) - msg += "POWER: [alarm_types_clear["Power"]] alarms cleared. - " - - if(alarm_types_show["Camera"]) - msg += "CAMERA: [alarm_types_clear["Camera"]] alarms cleared. - " - - msg += "\[Show Alerts\]" - to_chat(src, msg) - - - alarms_to_show = list() - alarms_to_clear = list() - for(var/key in alarm_types_show) - alarm_types_show[key] = 0 - for(var/key in alarm_types_clear) - alarm_types_clear[key] = 0 - -/mob/living/silicon/can_inject(mob/user, error_msg) - if(error_msg) - to_chat(user, "[p_their(TRUE)] outer shell is too tough.") - return FALSE - -/mob/living/silicon/IsAdvancedToolUser() - return TRUE - -/proc/islinked(mob/living/silicon/robot/bot, mob/living/silicon/ai/ai) - if(!istype(bot) || !istype(ai)) - return FALSE - if(bot.connected_ai == ai) - return TRUE - return FALSE - -/mob/living/silicon/Topic(href, href_list) - if (href_list["lawc"]) // Toggling whether or not a law gets stated by the State Laws verb --NeoFite - var/L = text2num(href_list["lawc"]) - switch(lawcheck[L+1]) - if ("Yes") - lawcheck[L+1] = "No" - if ("No") - lawcheck[L+1] = "Yes" - checklaws() - - if (href_list["lawi"]) // Toggling whether or not a law gets stated by the State Laws verb --NeoFite - var/L = text2num(href_list["lawi"]) - switch(ioncheck[L]) - if ("Yes") - ioncheck[L] = "No" - if ("No") - ioncheck[L] = "Yes" - checklaws() - - if (href_list["lawh"]) - var/L = text2num(href_list["lawh"]) - switch(hackedcheck[L]) - if ("Yes") - hackedcheck[L] = "No" - if ("No") - hackedcheck[L] = "Yes" - checklaws() - - if (href_list["lawdevil"]) // Toggling whether or not a law gets stated by the State Laws verb --NeoFite - var/L = text2num(href_list["lawdevil"]) - switch(devillawcheck[L]) - if ("Yes") - devillawcheck[L] = "No" - if ("No") - devillawcheck[L] = "Yes" - checklaws() - - - if (href_list["laws"]) // With how my law selection code works, I changed statelaws from a verb to a proc, and call it through my law selection panel. --NeoFite - statelaws() - - return - - -/mob/living/silicon/proc/statelaws(force = 0) - - //"radiomod" is inserted before a hardcoded message to change if and how it is handled by an internal radio. - say("[radiomod] Current Active Laws:") - //laws_sanity_check() - //laws.show_laws(world) - var/number = 1 - sleep(10) - - if (laws.devillaws && laws.devillaws.len) - for(var/index = 1, index <= laws.devillaws.len, index++) - if (force || devillawcheck[index] == "Yes") - say("[radiomod] 666. [laws.devillaws[index]]") - sleep(10) - - - if (laws.zeroth) - if (force || lawcheck[1] == "Yes") - say("[radiomod] 0. [laws.zeroth]") - sleep(10) - - for (var/index = 1, index <= laws.hacked.len, index++) - var/law = laws.hacked[index] - var/num = ionnum() - if (length(law) > 0) - if (force || hackedcheck[index] == "Yes") - say("[radiomod] [num]. [law]") - sleep(10) - - for (var/index = 1, index <= laws.ion.len, index++) - var/law = laws.ion[index] - var/num = ionnum() - if (length(law) > 0) - if (force || ioncheck[index] == "Yes") - say("[radiomod] [num]. [law]") - sleep(10) - - for (var/index = 1, index <= laws.inherent.len, index++) - var/law = laws.inherent[index] - - if (length(law) > 0) - if (force || lawcheck[index+1] == "Yes") - say("[radiomod] [number]. [law]") - number++ - sleep(10) - - for (var/index = 1, index <= laws.supplied.len, index++) - var/law = laws.supplied[index] - - if (length(law) > 0) - if(lawcheck.len >= number+1) - if (force || lawcheck[number+1] == "Yes") - say("[radiomod] [number]. [law]") - number++ - sleep(10) - - -/mob/living/silicon/proc/checklaws() //Gives you a link-driven interface for deciding what laws the statelaws() proc will share with the crew. --NeoFite - - var/list = "Which laws do you want to include when stating them for the crew?

" - - if (laws.devillaws && laws.devillaws.len) - for(var/index = 1, index <= laws.devillaws.len, index++) - if (!devillawcheck[index]) - devillawcheck[index] = "No" - list += {"[devillawcheck[index]] 666: [laws.devillaws[index]]
"} - - if (laws.zeroth) - if (!lawcheck[1]) - lawcheck[1] = "No" //Given Law 0's usual nature, it defaults to NOT getting reported. --NeoFite - list += {"[lawcheck[1]] 0: [laws.zeroth]
"} - - for (var/index = 1, index <= laws.hacked.len, index++) - var/law = laws.hacked[index] - if (length(law) > 0) - if (!hackedcheck[index]) - hackedcheck[index] = "No" - list += {"[hackedcheck[index]] [ionnum()]: [law]
"} - hackedcheck.len += 1 - - for (var/index = 1, index <= laws.ion.len, index++) - var/law = laws.ion[index] - - if (length(law) > 0) - if (!ioncheck[index]) - ioncheck[index] = "Yes" - list += {"[ioncheck[index]] [ionnum()]: [law]
"} - ioncheck.len += 1 - - var/number = 1 - for (var/index = 1, index <= laws.inherent.len, index++) - var/law = laws.inherent[index] - - if (length(law) > 0) - lawcheck.len += 1 - - if (!lawcheck[number+1]) - lawcheck[number+1] = "Yes" - list += {"[lawcheck[number+1]] [number]: [law]
"} - number++ - - for (var/index = 1, index <= laws.supplied.len, index++) - var/law = laws.supplied[index] - if (length(law) > 0) - lawcheck.len += 1 - if (!lawcheck[number+1]) - lawcheck[number+1] = "Yes" - list += {"[lawcheck[number+1]] [number]: [law]
"} - number++ - list += {"

State Laws"} - - usr << browse(list, "window=laws") - -/mob/living/silicon/proc/set_autosay() //For allowing the AI and borgs to set the radio behavior of auto announcements (state laws, arrivals). - if(!radio) - to_chat(src, "Radio not detected.") - return - - //Ask the user to pick a channel from what it has available. - var/Autochan = input("Select a channel:") as null|anything in list("Default","None") + radio.channels - - if(!Autochan) - return - if(Autochan == "Default") //Autospeak on whatever frequency to which the radio is set, usually Common. - radiomod = ";" - Autochan += " ([radio.frequency])" - else if(Autochan == "None") //Prevents use of the radio for automatic annoucements. - radiomod = "" - else //For department channels, if any, given by the internal radio. - for(var/key in GLOB.department_radio_keys) - if(GLOB.department_radio_keys[key] == Autochan) - radiomod = ":" + key - break - - to_chat(src, "Automatic announcements [Autochan == "None" ? "will not use the radio." : "set to [Autochan]."]") - -/mob/living/silicon/put_in_hand_check() // This check is for borgs being able to receive items, not put them in others' hands. - return 0 - -// The src mob is trying to place an item on someone -// But the src mob is a silicon!! Disable. -/mob/living/silicon/stripPanelEquip(obj/item/what, mob/who, slot) - return 0 - - -/mob/living/silicon/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) //Secbots won't hunt silicon units - return -10 - -/mob/living/silicon/proc/remove_sensors() - var/datum/atom_hud/secsensor = GLOB.huds[sec_hud] - var/datum/atom_hud/medsensor = GLOB.huds[med_hud] - var/datum/atom_hud/diagsensor = GLOB.huds[d_hud] - secsensor.remove_hud_from(src) - medsensor.remove_hud_from(src) - diagsensor.remove_hud_from(src) - -/mob/living/silicon/proc/add_sensors() - var/datum/atom_hud/secsensor = GLOB.huds[sec_hud] - var/datum/atom_hud/medsensor = GLOB.huds[med_hud] - var/datum/atom_hud/diagsensor = GLOB.huds[d_hud] - secsensor.add_hud_to(src) - medsensor.add_hud_to(src) - diagsensor.add_hud_to(src) - -/mob/living/silicon/proc/toggle_sensors() - if(incapacitated()) - return - sensors_on = !sensors_on - if (!sensors_on) - to_chat(src, "Sensor overlay deactivated.") - remove_sensors() - return - add_sensors() - to_chat(src, "Sensor overlay activated.") - -/mob/living/silicon/proc/GetPhoto(mob/user) - if (aicamera) - return aicamera.selectpicture(user) - -/* -/mob/living/silicon/update_transform() - var/matrix/ntransform = matrix(transform) //aka transform.Copy() - var/changed = 0 - if(resize != RESIZE_DEFAULT_SIZE) - changed++ - ntransform.Scale(resize) - resize = RESIZE_DEFAULT_SIZE - - if(changed) - animate(src, transform = ntransform, time = 2,easing = EASE_IN|EASE_OUT) - return ..() */ - -/mob/living/silicon/is_literate() - return 1 - -/mob/living/silicon/get_inactive_held_item() - return FALSE - -/mob/living/silicon/handle_high_gravity(gravity) - return +/mob/living/silicon + gender = NEUTER + has_unlimited_silicon_privilege = 1 + verb_say = "states" + verb_ask = "queries" + verb_exclaim = "declares" + verb_yell = "alarms" + initial_language_holder = /datum/language_holder/synthetic + see_in_dark = 8 + bubble_icon = "machine" + weather_immunities = list("ash") + possible_a_intents = list(INTENT_HELP, INTENT_HARM) + mob_biotypes = list(MOB_SILICON) + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE + speech_span = SPAN_ROBOT + flags_1 = PREVENT_CONTENTS_EXPLOSION_1 + + var/datum/ai_laws/laws = null//Now... THEY ALL CAN ALL HAVE LAWS + var/last_lawchange_announce = 0 + var/list/alarms_to_show = list() + var/list/alarms_to_clear = list() + var/designation = "" + var/radiomod = "" //Radio character used before state laws/arrivals announce to allow department transmissions, default, or none at all. + var/obj/item/camera/siliconcam/aicamera = null //photography + hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_TRACK_HUD) + + var/obj/item/radio/borg/radio = null //AIs dont use this but this is at the silicon level to advoid copypasta in say() + + var/list/alarm_types_show = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0) + var/list/alarm_types_clear = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0) + + var/lawcheck[1] + var/ioncheck[1] + var/hackedcheck[1] + var/devillawcheck[5] + + var/sensors_on = 0 + var/med_hud = DATA_HUD_MEDICAL_ADVANCED //Determines the med hud to use + var/sec_hud = DATA_HUD_SECURITY_ADVANCED //Determines the sec hud to use + var/d_hud = DATA_HUD_DIAGNOSTIC_BASIC //Determines the diag hud to use + + var/law_change_counter = 0 + var/obj/machinery/camera/builtInCamera = null + var/updating = FALSE //portable camera camerachunk update + + var/hack_software = FALSE //Will be able to use hacking actions + var/interaction_range = 7 //wireless control range + +/mob/living/silicon/Initialize() + . = ..() + GLOB.silicon_mobs += src + faction += "silicon" + for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds) + diag_hud.add_to_hud(src) + diag_hud_set_status() + diag_hud_set_health() + +/mob/living/silicon/med_hud_set_health() + return //we use a different hud + +/mob/living/silicon/med_hud_set_status() + return //we use a different hud + +/mob/living/silicon/Destroy() + radio = null + aicamera = null + QDEL_NULL(builtInCamera) + GLOB.silicon_mobs -= src + return ..() + +/mob/living/silicon/contents_explosion(severity, target) + return + +/mob/living/silicon/proc/cancelAlarm() + return + +/mob/living/silicon/proc/triggerAlarm() + return + +/mob/living/silicon/proc/queueAlarm(message, type, incoming = 1) + var/in_cooldown = (alarms_to_show.len > 0 || alarms_to_clear.len > 0) + if(incoming) + alarms_to_show += message + alarm_types_show[type] += 1 + else + alarms_to_clear += message + alarm_types_clear[type] += 1 + + if(!in_cooldown) + spawn(3 * 10) // 3 seconds + + if(alarms_to_show.len < 5) + for(var/msg in alarms_to_show) + to_chat(src, msg) + else if(alarms_to_show.len) + + var/msg = "--- " + + if(alarm_types_show["Burglar"]) + msg += "BURGLAR: [alarm_types_show["Burglar"]] alarms detected. - " + + if(alarm_types_show["Motion"]) + msg += "MOTION: [alarm_types_show["Motion"]] alarms detected. - " + + if(alarm_types_show["Fire"]) + msg += "FIRE: [alarm_types_show["Fire"]] alarms detected. - " + + if(alarm_types_show["Atmosphere"]) + msg += "ATMOSPHERE: [alarm_types_show["Atmosphere"]] alarms detected. - " + + if(alarm_types_show["Power"]) + msg += "POWER: [alarm_types_show["Power"]] alarms detected. - " + + if(alarm_types_show["Camera"]) + msg += "CAMERA: [alarm_types_show["Camera"]] alarms detected. - " + + msg += "\[Show Alerts\]" + to_chat(src, msg) + + if(alarms_to_clear.len < 3) + for(var/msg in alarms_to_clear) + to_chat(src, msg) + + else if(alarms_to_clear.len) + var/msg = "--- " + + if(alarm_types_clear["Motion"]) + msg += "MOTION: [alarm_types_clear["Motion"]] alarms cleared. - " + + if(alarm_types_clear["Fire"]) + msg += "FIRE: [alarm_types_clear["Fire"]] alarms cleared. - " + + if(alarm_types_clear["Atmosphere"]) + msg += "ATMOSPHERE: [alarm_types_clear["Atmosphere"]] alarms cleared. - " + + if(alarm_types_clear["Power"]) + msg += "POWER: [alarm_types_clear["Power"]] alarms cleared. - " + + if(alarm_types_show["Camera"]) + msg += "CAMERA: [alarm_types_clear["Camera"]] alarms cleared. - " + + msg += "\[Show Alerts\]" + to_chat(src, msg) + + + alarms_to_show = list() + alarms_to_clear = list() + for(var/key in alarm_types_show) + alarm_types_show[key] = 0 + for(var/key in alarm_types_clear) + alarm_types_clear[key] = 0 + +/mob/living/silicon/can_inject(mob/user, error_msg) + if(error_msg) + to_chat(user, "[p_their(TRUE)] outer shell is too tough.") + return FALSE + +/mob/living/silicon/IsAdvancedToolUser() + return TRUE + +/proc/islinked(mob/living/silicon/robot/bot, mob/living/silicon/ai/ai) + if(!istype(bot) || !istype(ai)) + return FALSE + if(bot.connected_ai == ai) + return TRUE + return FALSE + +/mob/living/silicon/Topic(href, href_list) + if (href_list["lawc"]) // Toggling whether or not a law gets stated by the State Laws verb --NeoFite + var/L = text2num(href_list["lawc"]) + switch(lawcheck[L+1]) + if ("Yes") + lawcheck[L+1] = "No" + if ("No") + lawcheck[L+1] = "Yes" + checklaws() + + if (href_list["lawi"]) // Toggling whether or not a law gets stated by the State Laws verb --NeoFite + var/L = text2num(href_list["lawi"]) + switch(ioncheck[L]) + if ("Yes") + ioncheck[L] = "No" + if ("No") + ioncheck[L] = "Yes" + checklaws() + + if (href_list["lawh"]) + var/L = text2num(href_list["lawh"]) + switch(hackedcheck[L]) + if ("Yes") + hackedcheck[L] = "No" + if ("No") + hackedcheck[L] = "Yes" + checklaws() + + if (href_list["lawdevil"]) // Toggling whether or not a law gets stated by the State Laws verb --NeoFite + var/L = text2num(href_list["lawdevil"]) + switch(devillawcheck[L]) + if ("Yes") + devillawcheck[L] = "No" + if ("No") + devillawcheck[L] = "Yes" + checklaws() + + + if (href_list["laws"]) // With how my law selection code works, I changed statelaws from a verb to a proc, and call it through my law selection panel. --NeoFite + statelaws() + + return + + +/mob/living/silicon/proc/statelaws(force = 0) + + //"radiomod" is inserted before a hardcoded message to change if and how it is handled by an internal radio. + say("[radiomod] Current Active Laws:") + //laws_sanity_check() + //laws.show_laws(world) + var/number = 1 + sleep(10) + + if (laws.devillaws && laws.devillaws.len) + for(var/index = 1, index <= laws.devillaws.len, index++) + if (force || devillawcheck[index] == "Yes") + say("[radiomod] 666. [laws.devillaws[index]]") + sleep(10) + + + if (laws.zeroth) + if (force || lawcheck[1] == "Yes") + say("[radiomod] 0. [laws.zeroth]") + sleep(10) + + for (var/index = 1, index <= laws.hacked.len, index++) + var/law = laws.hacked[index] + var/num = ionnum() + if (length(law) > 0) + if (force || hackedcheck[index] == "Yes") + say("[radiomod] [num]. [law]") + sleep(10) + + for (var/index = 1, index <= laws.ion.len, index++) + var/law = laws.ion[index] + var/num = ionnum() + if (length(law) > 0) + if (force || ioncheck[index] == "Yes") + say("[radiomod] [num]. [law]") + sleep(10) + + for (var/index = 1, index <= laws.inherent.len, index++) + var/law = laws.inherent[index] + + if (length(law) > 0) + if (force || lawcheck[index+1] == "Yes") + say("[radiomod] [number]. [law]") + number++ + sleep(10) + + for (var/index = 1, index <= laws.supplied.len, index++) + var/law = laws.supplied[index] + + if (length(law) > 0) + if(lawcheck.len >= number+1) + if (force || lawcheck[number+1] == "Yes") + say("[radiomod] [number]. [law]") + number++ + sleep(10) + + +/mob/living/silicon/proc/checklaws() //Gives you a link-driven interface for deciding what laws the statelaws() proc will share with the crew. --NeoFite + + var/list = "Which laws do you want to include when stating them for the crew?

" + + if (laws.devillaws && laws.devillaws.len) + for(var/index = 1, index <= laws.devillaws.len, index++) + if (!devillawcheck[index]) + devillawcheck[index] = "No" + list += {"[devillawcheck[index]] 666: [laws.devillaws[index]]
"} + + if (laws.zeroth) + if (!lawcheck[1]) + lawcheck[1] = "No" //Given Law 0's usual nature, it defaults to NOT getting reported. --NeoFite + list += {"[lawcheck[1]] 0: [laws.zeroth]
"} + + for (var/index = 1, index <= laws.hacked.len, index++) + var/law = laws.hacked[index] + if (length(law) > 0) + if (!hackedcheck[index]) + hackedcheck[index] = "No" + list += {"[hackedcheck[index]] [ionnum()]: [law]
"} + hackedcheck.len += 1 + + for (var/index = 1, index <= laws.ion.len, index++) + var/law = laws.ion[index] + + if (length(law) > 0) + if (!ioncheck[index]) + ioncheck[index] = "Yes" + list += {"[ioncheck[index]] [ionnum()]: [law]
"} + ioncheck.len += 1 + + var/number = 1 + for (var/index = 1, index <= laws.inherent.len, index++) + var/law = laws.inherent[index] + + if (length(law) > 0) + lawcheck.len += 1 + + if (!lawcheck[number+1]) + lawcheck[number+1] = "Yes" + list += {"[lawcheck[number+1]] [number]: [law]
"} + number++ + + for (var/index = 1, index <= laws.supplied.len, index++) + var/law = laws.supplied[index] + if (length(law) > 0) + lawcheck.len += 1 + if (!lawcheck[number+1]) + lawcheck[number+1] = "Yes" + list += {"[lawcheck[number+1]] [number]: [law]
"} + number++ + list += {"

State Laws"} + + usr << browse(list, "window=laws") + +/mob/living/silicon/proc/set_autosay() //For allowing the AI and borgs to set the radio behavior of auto announcements (state laws, arrivals). + if(!radio) + to_chat(src, "Radio not detected.") + return + + //Ask the user to pick a channel from what it has available. + var/Autochan = input("Select a channel:") as null|anything in list("Default","None") + radio.channels + + if(!Autochan) + return + if(Autochan == "Default") //Autospeak on whatever frequency to which the radio is set, usually Common. + radiomod = ";" + Autochan += " ([radio.frequency])" + else if(Autochan == "None") //Prevents use of the radio for automatic annoucements. + radiomod = "" + else //For department channels, if any, given by the internal radio. + for(var/key in GLOB.department_radio_keys) + if(GLOB.department_radio_keys[key] == Autochan) + radiomod = ":" + key + break + + to_chat(src, "Automatic announcements [Autochan == "None" ? "will not use the radio." : "set to [Autochan]."]") + +/mob/living/silicon/put_in_hand_check() // This check is for borgs being able to receive items, not put them in others' hands. + return 0 + +// The src mob is trying to place an item on someone +// But the src mob is a silicon!! Disable. +/mob/living/silicon/stripPanelEquip(obj/item/what, mob/who, slot) + return 0 + + +/mob/living/silicon/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) //Secbots won't hunt silicon units + return -10 + +/mob/living/silicon/proc/remove_sensors() + var/datum/atom_hud/secsensor = GLOB.huds[sec_hud] + var/datum/atom_hud/medsensor = GLOB.huds[med_hud] + var/datum/atom_hud/diagsensor = GLOB.huds[d_hud] + secsensor.remove_hud_from(src) + medsensor.remove_hud_from(src) + diagsensor.remove_hud_from(src) + +/mob/living/silicon/proc/add_sensors() + var/datum/atom_hud/secsensor = GLOB.huds[sec_hud] + var/datum/atom_hud/medsensor = GLOB.huds[med_hud] + var/datum/atom_hud/diagsensor = GLOB.huds[d_hud] + secsensor.add_hud_to(src) + medsensor.add_hud_to(src) + diagsensor.add_hud_to(src) + +/mob/living/silicon/proc/toggle_sensors() + if(incapacitated()) + return + sensors_on = !sensors_on + if (!sensors_on) + to_chat(src, "Sensor overlay deactivated.") + remove_sensors() + return + add_sensors() + to_chat(src, "Sensor overlay activated.") + +/mob/living/silicon/proc/GetPhoto(mob/user) + if (aicamera) + return aicamera.selectpicture(user) + +/* +/mob/living/silicon/update_transform() + var/matrix/ntransform = matrix(transform) //aka transform.Copy() + var/changed = 0 + if(resize != RESIZE_DEFAULT_SIZE) + changed++ + ntransform.Scale(resize) + resize = RESIZE_DEFAULT_SIZE + + if(changed) + animate(src, transform = ntransform, time = 2,easing = EASE_IN|EASE_OUT) + return ..() */ + +/mob/living/silicon/is_literate() + return 1 + +/mob/living/silicon/get_inactive_held_item() + return FALSE + +/mob/living/silicon/handle_high_gravity(gravity) + return diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm index 9bea6c5d..b17dca07 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm @@ -27,6 +27,7 @@ mob_size = MOB_SIZE_LARGE layer = LARGE_MOB_LAYER //Looks weird with them slipping under mineral walls and cameras and shit otherwise mouse_opacity = MOUSE_OPACITY_OPAQUE // Easier to click on in melee, they're giant targets anyway + flags_1 = PREVENT_CONTENTS_EXPLOSION_1 var/list/crusher_loot var/medal_type var/score_type = BOSS_SCORE @@ -44,9 +45,6 @@ QDEL_NULL(internal) . = ..() -/mob/living/simple_animal/hostile/megafauna/prevent_content_explosion() - return TRUE - /mob/living/simple_animal/hostile/megafauna/death(gibbed) if(health > 0) return diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 8f416cc0..cc70253d 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -78,6 +78,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) icon_state = "darkmatter" density = TRUE anchored = TRUE + flags_1 = PREVENT_CONTENTS_EXPLOSION_1 var/uid = 1 var/static/gl_uid = 1 light_range = 4 @@ -728,9 +729,6 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) /obj/machinery/power/supermatter_crystal/contents_explosion(severity, target) return -/obj/machinery/power/supermatter_crystal/prevent_content_explosion() - return TRUE - /obj/machinery/power/supermatter_crystal/engine is_main_engine = TRUE diff --git a/html/create_object.html b/html/create_object.html index 3609e469..461dd373 100644 --- a/html/create_object.html +++ b/html/create_object.html @@ -40,6 +40,7 @@ Where: @@ -105,4 +106,4 @@ - \ No newline at end of file + diff --git a/sound/weapons/mortar_long_whistle.ogg b/sound/weapons/mortar_long_whistle.ogg new file mode 100644 index 0000000000000000000000000000000000000000..646d37d8ab62890e7af60bff9a79a0bdf440b17d GIT binary patch literal 14156 zcmaib1z1&2xA&$IkOo1zIW$OjC~*L3kVcRW>5xw8JakBRNea>>-Q7rgKtM`V@Z0GB zz3=`rT0p;&dh_sA00)P(oa4S*w2TaCm0RS!l zn9xJ8lPnY(P@_evZ3;c;xnwkRC~hdWbr^>*pg+__0YJM*%F~1rs^3?p;WS|+VD*;V zd61?g%Nc{EG&cx?XOKEriRZ8|>ACP>X+f;;7v_dZX-xKpX{ZwSoVHnYJF20N%ec^f z)<4yQKYCDubCE_ReT6HHe$PG}Qk>=tvihqQH4p%*3CJZ7D!eBgc~3qzMX&OWO^twW z>d7+=O=T_cax>I%H(zjfTX6T)O$*ik;H&!~RDUtl@H+G*N!UN-yYI&Jefgt0H3E=J zCzP@c$)|ms|5+#>DI}~C5qNcP66yzuw2;ICg<=bvYU|7}ol*S%6bs!H^Z&g_S`D%QlAtX=Igx*IqJO4N|H+vR?T>{A0nn$C>TLbaymBtQ zpIk)2BIo*a2&Oc4p@j10J0^?Lzlt&D+zocJa30OV>07>Ob9z;H@A#1bEZ2&Gn1*M zEG_eo2kpj5w?SV*hSU3V(%BI0S()}##0n(S?bJo)tXk|+; zz_GfM8GEHIgkUQImdVuEqWPEKKd>k>${Oz$+5$&JEN9xbJTL@XH?Ok3jy<^V`|t3P z1pW4Mkz^n{h}t(6)s&E?m?nwRH4Zx|mwOOWNEs6=3oQ#)RVQUCat->UIW+);;Qm4J zzp6h_{)^(m#7LH5=K4{d5w`oPvUgkkCYOQDkf36iih=V3?*7#08NxKsKGJc_CRC=+MoYWNIbnc`vBcp|2y zsios?ubb+&(j02I=(e%oyRi^s{3z_d1M9yc2LOX6*2%f3&Dr*oKP7%4y5Swf88_w{V&uE#?xtlLFnd>+E z>NfooFn_~lW5Mk|BIiCtXoX_8;*da9z9B)5Nci@Nk|Fq6D*;Jw65_|Oky7rg?h2hH`SSmo+<^$ zFbKp_KkO+sP}mhj2bVo$Kn(x_xCgoWNSwzNhH{^db3e$24GJ+8B~2?p*i%TJKp2Yg z&9<`&rWJ+?VI+!?*@gIK5mn$I01f=Z%$tlSLXac`08=b=3`i(UeH^kEuRhGZORf$T zD#_9q7ec298RkaK4#tHPk!y@YK9PrvO6_I^Pf9TZ0Cg7v_$STG`|25h%LHsX(oZDu zDiSg%5XmLhPrL;-c!-`*Pp@~n;RZC6F zTvt;|*WFzAT1#i%R}rLYC@&FdX*FprUD|7<_-?ss8S0oXU2EwQ`{^%)Ze96qk=%1$ zm~#WEFXzo)HoI*wTW46?FbFqfB?l{eX!S6AuhAC%{p57$|iS62?#)l^j5!9i+u zX?Y!6c{y7}UFFYmHh5EMd27{hU2SG{1-$75vzHCt>R4V~T~T**Pi?J&4>-YFxqONt zBgGY8TFY8n9pJ4_qfPeY1?68lSVnqkhwDz@t(*;RG-_IIYcRuY9Z(N@V~-sD>(DxT zkl-^$uiU-@rMm#7n{0BFhYLrsY+cfy>fQ?TV}Zg}P9a8fJ=`nR7G1QtJHmzqoS}$B5&FK7 z*w%r2?=jT6>RxzRKe2u+C|tvquXx_(o}h0pHlN`Ft(u=zj{ym0_U&^S-Y5Uk+|-7B zVBWOqUO3D9!{F zApP?~=nO@~iY)B?+O`k~s0BNicl-%kRON_%1dNBe4}hm&6c12?>kcYu5lQeQNg<&b zE^QGB=$9fwGtjmqF4)p6q-Nt%%#aXOC<`PM7plNe1SYr`LrI%0xl zip3p9?W)Pcf)}C$Whx536f;#k&8tj7KFjP;s|C$wQ8?if)aAUH4_o=x?eM)LTGs~S;zo2EKwa4 z2dY%&j0M`RU;CZ_(>tODp<&18jtjzSKu-o*)&Ih_nx<&pw32TD1aaeDhAk8%*p9UT zz$ywFP>V$NjGu|*0SoV|KS~5pgJz884kI*;UIt z4-?pQa0CM6Yn{T93+sEPHvjmV228f4|5*EeW1tTDBKICGG*6)*s_rpD69T&7Z(m6K zfA!%C@Bf7s2&nzP&%sos|3C{p5A1_bfFNW3(_#Qy5B?@_f4~@m52kW3kn`U@7(OWD zPkIMazegl!ntQ?@sQzg^pt(2KpNDDwj=j$XL5L#VuflW(^aaDTcD!3XNUBzYP#^#c z0Gt+W;E?%2>i(>d6vdEuXIxVbJoQK+x%cMsr2QmwFzzBk4RzatEYoN;m25L8cW)(3 z8_JvzH0@m3=spVWD5=o_E?k-?fszP>B!i%!5M&6DTiZ3sZGeotgU^G3h4CrGW!f4E zzzrG1N(g^}g-=i(m~Sc!yf82sL<_)*iD`(!JmBdy*nc;`2mmDjBtE33rOgnE#g4;?$4$UX#7`oCf$#-@O@sg(Ab=hvJUrYY zwxD+#iT>%UkixzlWQITF`wAWX?^Xr*Py6o%xl8IV`F?|ZFNT}e(w>)#os(;Rl!=*v znVy-Ei<@g?7y@3*%uJkIJe*TZ5NN?N^~?RROw(Fd|F=q~x7P0c$Gwg}pd6 z6Q7nSE8b-B<4H=FFU&TW@~(V6qaw%mOjh<@mcEk7IkA!&{EO<k=cvp`$dz5xM~KsyEJ>a5AQE!WoK0~!q-B3mZ|+sX z$M@MZe1LAnTVVZGTb6g|k<)s%k!7a{y#w!U7y8H;CMC1w zN=I<>-6Ry+Uj4bTE zK3tF0ig%j(c)AjZ3DbJLe3F;U;yn+YMbeW?d;%9Ot~t%|AkawjG2s$8vn%Pdxve3_ zrae`wOI>6*f?dx`7gUZGVtvdIteikC>cgJZJIhUq8-c()fe+7%T-(VVHVD#bGsU3H zc7)4GQv>h#{HLP)j2IbRY3fytrMEw!A0f0OY3{bZTw)XC7X0q%Hn6ut$L-DK#M zKri@;VH|c`>XHl;A}EGYguz3%U{7fHr8om)e242f`Xkk}=CnkJNOTRb-edTEEr*k| zAz(g2MHY*`{H2SO9g?&wKAsY>wr@zoQ8XV~+(B&Rc9|%ST6ycU#Lrk~G|F3`WI{iR zCFUKY_<3PYg8F?^j-$hyuy_mSrZ<_&Bo{XqNL@K(#Vw7fbXx+Zg3mXT`#XB};Y}L8 zsVBcbPWM{2^%SBgG8Q3N*leF#sN-W%u8R*6nnMjd4&pMaa=t$4kA1YnVNv4GVKR#% zMnO`YbbNZb8(6WakP}0R{diF0<)e@VX$z(N3a^x==fzd%I}b1Gd+I7`8sG)DhLU=< z#;hGi{Vf_FFJ@D5sj5=9oMH^dR;j!E`$Rn9HG{Ii>VwPqu&%~h-hee@b!oj1raX+5 zIkIx_^pO(HxpenDtmmneZaY7m6qesUU%Rk)jS54#9dgku$J}?drOn1=M%&uaSFKDA zOsT1R+xxlk?X>ouHX^0dFB)ng>YrJ0vgob+U;vpQ3X}N0>7Y0nYOJa(67C9?jY&?6 zgnCb-QR|4cFGWSs^lmQL&*&h%^EdiF7mL5LnpOMVhV^=%w{yiT`1z<+o3339h6mgF z+qJi7FGmPoW*Q~C#C6Duend3>>8y9FWyl}U`!*I^Pytw+`aL|~kfTF`qZ6o7r>5H~ z^=(z|d7M<;2~SFu#`a}Yv2SBka6&vATC~)0K!?N9oKj9&?l?Cqa((GD?(fE)81f9b z;a}&)a7DMUva)fiy%Xzr1fO>_&?&fEHY^FFQsR3f80}r3`ZG~`#=c<>rmdRie5TnG z0{Gb5`+SRD$ZXkih%I$u_1N9-Y&9;s8DCKGGbXI%urIU6*NL7j8M zV7{5!lMWo+_{fma>umC9%uC7(jrw6z;Auy6wxv76MY1vviH5#%N2$Rs%cOx{H=+bw zv}IjJ@Hmv%x4+VUUXmoJHbQXSsiPY6Pd@_Ior-M>LY!~_>+S%ZUW7F$?)+TIEp)-&JimjmbOHP-h>CLsb$e zfL|z4tuZTK4OBgh#Q>c^uBM_%>+qQ$NlDR2`6-=8=6U9S z*m9TfPGR`BrP|d~T=bM*7!Ai<_>=>;s-lSqB`>e*m}n)g(atlOsg9}jOV-+f8 zMV3?mnEtn4cPhI?{to#uN7h5{{N=J$DvkV=Na)V`E>ioL|J(HXC3p;7P5 zDWfSXQu0{2**(3i#Z6I;3`n%WrkE9Dn;W4$db67NjO{6tY8SsP@e^*`;&#;X57Hk; zV{A}W?61vuEIoHtw5aq{+rsk6bw)&Rm`_cXwXKAr10nhys)zP+`4{@DB55y&y2oh> zM6Bo(KO(ZhhA@gG3udL~k|OWt??%nldxP~Iql4BM8i{_!WM200HQ#pS&5CSvEW{{_ zT=nsA_X9C#m)>`V-~pHZfOJ@McS-5FdnYe^G!LV)rT_gd>h`Id_7{J5fDNO6=mo0A z`r_B7*Ce8w2q%EQ4tP9Z-amS}@O%hB--{aKL`543Y5F|bpzGTU$7R)_of`n6}t^vxs1k#x9}vgL=i;j z{oK1nD5|d|$c=%?1jr6X~ukGVHNd}2J1$Kj1U!Urs&F>lDgal_AX1=W2hF{i@_~1*3u@P-SR@P~lqu|Uwcyh2x5F;5e*^D+iIDt|@|db;YbWuec+DZc z-Rrec8Tg5>U6M`d$cOjj=U@C z35DF(Y2@U9U7DuUicWIb=nu zBobm?DQXE&6gH)cMeFS&_M>7i=j41zOtW~0n(yG&X1u0BzcyVSTx3VsW$6o$)t}#f!B2C< zm8B9UfS@kB64IL=-||{~tG9i6IUe+SrR@o64wDXc8)Y&XR>w4 za9oGO_43nQ!VXyc(^5iu0QuW+D=#7Z@K^6=H^s8-stQseFTlp{TFeUQDWq>V{bh zlxCh!KMW$r@GhAt>+5YF0tIlUfM+@s5?anQS ze(K2AS%Qz7Mb`V!qRMMZH9i5zKV19j5r8aXTUG>8)_|Q7p_Wx2<+=C!N>uWXAMM6w zvEgCVS*BKLv`vV+?i<+A@aqXS=uR*rkv!VjeB^zhD{?|6jX^I8EHEylim~ z>igM~)0@#qlCEn5wwW;Si0Ca<_>y*4#|{GG-fLHT#se0Yn9{7xk4qb+HICo|N|CMO z4BL7B=jL^`B!nVwjTwvQziZ4s&P_4@1m!f>H~-v;0Ne@gbdl^JdIz%I_nd--Zq68ALcZswzS&vnjsBlI`8RZ@B9oxuBjqCr5o4bP!JTly{1e z%x#wVz?bqD5BfqOJ!|B?ZeHpFv3J66(rg32tF&h|)QIvc6+~i(=RK;K_oRA*`cBdosEkbzK+s_Zw$%Yt2#85t+Us;<&h818I^M z0U06sEvB>Mh+J{_9QL%Wm!Xoyxt12H!%JrFU%tX$*BcGZe{h-jOn5%3V-_kK!~m}D zK{nK^BBw{n!D$|(oXN&N3nmlCI-qfnzsS>L&cN5Lr|N8n zY8M$?KQ*R@n^*4&=J#j~Fp)Gl*v81h^sEGHp9ekg>)4EVDUbB{lr$*4`>l5xnSNr= zV7QHFXzu|5GoLU^bl**VmM9IJrn@6g<~ZUd4hnFmP-qc1#6;cexYOiR2bjUhB&G%` z$OGIR@5EMc#3pelL^pnmc{keo_|b?MQ0>gK7cdblDeH%M+rqfa$1YZ56Sg1|H@fLs zA+a51k=bHR9!qTD5@q!#obTHctSmPb7h6*7Go_1^xxMh?Lh>?|d!SRRd)6oA41jQ^ zKnRiSF7?gwLEX#Hw+-%}D)G$8LkK<)pNM>YJS#8=hK+FfcK5 z^9)Tx7#LZf@N!NKjZKYDERD_G2|ay7c7!NAm^j`Ap+JnTdiTAfvPuD%O=5TH^x56$ z=0~;e_dEUA{%X%0{-uFO#p8_xscdW(;X>g^<>M*j2UsI>3d&Bk2!-}~Rf)R!I00ITsnIa=nOV+{AMf1j zt=n5Yo6c-6S=B6-e8Trq-blEVlH-XEqOvBNA7gym^2xvUwOq|J_Ufr2pFsS^w!OqD zE*u~6hEC~aN$|VeqNjbN(FAHH@d!UgzxWk#Nb&n{RUx$wVh3zASjQ~AK?;zYCmN%w z>-DaAok=+LK)6SL=<|2`@$HW0B*KSudN%kiI1e2-$|`Uoj~a?-Oo=C6qRjLn8NZV( z==5=hDs}H=R9tWmv>*b05j)*@ib<3&h!T*pwb$NkvhD_~3r6fdg3#jw!N0z;{yye8 zv0TpS$P)kAly${_XFy3x>RzEmpqkd}fsXj8E-UKydc$lANDMiurGuf3Vi zMYh6NSk_|Q_;iT&qC)8thDSFo02n}V&JLQ zHqmITnQa7vxVkJkxsCG~!I(hKGV&g=C(w1P?^7(uRc!8)#OpT#{CFF6O_gN4-t3po z$LcN2Q}4lRbbCf0;pMnAQKW`aqh&K}i$<3|i|mE}ey1@w<8!Yc{-v-mg)Fh0sac|S z?fU}T0ea~HDqg|fD5mK_cm0oIBs^;_shmeP$GtD0Xm zt6#xM*eiOERiNBh)8zgn>$3h6mcivWg$j+Z_TF)-9HroAygw5Sba3aA8ru2A@Ut5= zhDnW$>Dy+|#7SP)u&O2Gtq_)F!G4({=a({+JErqw^eWbu5@hP#QZugx5D{BFftA^nxn9xoiU_u#OHmRVEd>KeHloA1)spPtFT z{6$Y}0Nu)IUT&NTM`uF;=F>*E?D>TQXQfgO%A#7oO6;!kB%!uCEjKAFGC*0-azA;F z)QX6b`Utmvw9|dTA#sAw$)oc?*IWQpkLRoSat^{gA;vVmax?7t(pFMhA<4zmQIBd%){7owAqyKvvfat5Iqf}X|z*KS;RQ8ZYQ6t@wncdI4Hv= z6k*)`z86RZn*ivIDRP_Ze>EE{<&1XM9BmcRQ2Bm+?VJ)(!lMeNr;j@jNPnA%7wX?JH07z`H zlHCiPrV&i?V?sVLW$O5;#$nDUU5yQ_taNH`=O#EbLOQm8E{b0!_H&WAn)E&*^?RW} z@teJk@NfsKx=2vtEuk+|`!paq??H zmEZ2tg%i$=H^R`yPf9vNq!=*^!=U`rtsOfs>wvqGUu**f(XTtLBTwR2be;!c${8|l zn~z0lHS0&p>^d9-zWDyehEV_!a6cH`(nr0UG)vYMyh8xe9+H&U7Zn}}$st@&Ctp{X zE8xA3M*D3rvOaA3ra8edo3+)>TPJW$j^x6`)go%X)~50cO;8iw;-&of*$CYi$H6$= zM#r7N)wh29OD{(Cwlx}(elu*m-4LQ!vt`)Lue&aoE|{$}NhWSH^+ENr1%>Gua z+fc)D(RD)CJx_mUrb02ke9~ zuc)7#ea`Y8AH~F?r0joMM9Z+-U!ud&1Q{YilHe*}BMOy1HIW#Zpp^0}3_q$n z1IW`UZ!fXmW>U4ag|c}G%CGG$~Y4-XWJAoxuO}Rv{^7uvpZtlxbZSVs^*au#B5mrZQhnDizeKZ#326yM$}F+KIPl`$ zibGcUfRT(OUZJ7%VD32=t%!|Kd+_IGzgGHD(mu2XG{+{b+)0H!CX+y8VcRoCl8sb8-0$K$ggMg! z(m#^Es@67p=iMxM-%fnG1k*4aRn%;qwjfHUo1M~;uK^5&EE|FZw#{l(cASNJwnjur zsgkL;C_e`8z;DAw_d0SnLr`;;cSiYTIgNV0bM+cNnKwdfFw9gTcmy3rBry_hlUw(% zF`T+R=9Hiy)k|`zgorTe>)0k!&3t3Q&y?<5&&dwXez5vGE;(O}?#)us0SB6B6j*jlsbp_VJO)&7k9ac4H(@JGqO`6Df zdR~07Dwc^^ZZ}fwflF?LVC*_X>-If-CY$vKnbT`CEfpA#95&w*o3d#j%5F#JfGWH6+7Vdm;}7sZF02t zs=|>A>v7CXe~a$E%sQIW>)!gt14o7(ksnGH%wPJPwWL-dx34_r`*6M)+xa+GP;&EW zsvqiJ&?!Vr-N_R9NKNC`eH z@nRICw;ZUsZWg>8wMZhS?;ZdhEDU{=6>-wp6{OGIke;@4za&3bd;V&hpa=(u+h`g} zbs5+0wC@mXBOjqquJ@;2@)=)(4Nq%K)ExL{A50j%Sx*7dJiH&^o%Jt1qkHG%yqEHD z1#ka|0kvORT{xSWqrEhKn0#(RUTore^XM)}@%6UFfp3jmr&U&wavL`cW7YVOLp3AK z;KH}Zv-UvJ#>623{Ykx4yP@G4k7Pm5&yFzHNqR)*iWoMtA-S^k&JabjSaULUBeszl zmxV!>wShyG8U>HaRpd$HM+oab=r1VEsEk_ACWlYaF-(XPg`>9@8E@jXUmgO3%Ys)W za|b3O*P5K7pUIk*R_3eNag;I%PRiFFY5dlV33N%vR<(1r!Rk9fw`Rl|=5LR|wNam| zU=91^7#s{|KT{yvpRXV2dMTS)eb8yDw*5$llmBcWf6@2vmSufWe8HvBIM zs^1ySYi`nx9$Hb$h)Er*8lnU1KX#TLy9RZLVhtufw~yCKTMH)2eN%7(pZ$O=*}VSz z7s3AZSmtHLUU7^{*zsJ{TXD+`^S#%)arHRsertnmzKb%WBPGlT^*cPqBWDn4l&!5r z=lp4dADrmleS_nUqrMO1ji~J7>$U1UbnU$LPryxOEjl)7{!{~&UpVoDgg%|Q?p*AXL06 zUQ`_ik4FSAX7&!=-`ZPr9OW)~Tz)$CNs-Wb!f-gC{R@z>Qf|${X%I{Mu6z|=h4MLe zIt7_le>>j$V&l8tmt6Y_oCxbas9Df_#LveR60|f-#0ERTqltQbqc)W=592&jB6^c& z35g+8p($8O0t5+o>EtR~ENxefklC0O;dk&7Ood*_al7jcr1OTD0|Z<#gGsG{5EJs! zoUeEmj4tCLO(|b>4Fz&JKXI6r9!${PpA{H=(VWC5dW6#`rsRl9?Ds-EcfnnOEU~c~ z7Z9NG+`PG{uQU?I<=pUMH{RIYi_Q>D^vrQpq0ERxFDCuyJ1!U9aKc`Ot}>PqIL)^r z{dOZY^SzgUhq+WxMCc~;UDC5-GOM>^OkPz0d3My5aJU&l!-%by&x<(T8*J}kkBDkX zAvbGu#h9WQE<wh6s4Sqzks@w0};+L#uU$lAZctEO6JA z@6xRB-0;b<^m9_(Uz7)vrGl_K_6BmiQocm(?*>zje-A^D|MmY7_n&#(fBtd!L3{^u zWM*!0{4+Z{8`l#`#ofinLpYoRHkj9RY_I~v0oTu|SJJN%p8>0#Cz&&agI|7~M0uaY z-qqg8t^@Wx?$DbXt*i|?>?g7vVRviL(Mc?b82s&^KeOC}9cNgMGGmuzk9`EhcxcW| zj*EDnq4T=nGoo!!nT*5nUuYPOTx*4B?tX=w37H$W-|_BuF{?R7ga!F ziA{2wi?|^r>+UXIx7=M9Miy~aKUzphGK@;sK^Q1eXm7pw_3e6VY~V}%aS8h)oC#x3 zXMES+PKwJRpE{XhafOhCtB#bs&T(SS1qoh?j>55YF>uXG5DI26n z3VcWSaVk&Jp+B*+cM^^YEOgbl%zA}&i4q;H{-dhJa!AOLHEM6B@>ROx=7rZ1zGM}# z8Y}DEHJt1onBw}om!#k6d^Qok7Ab3b16$CHLVR}1H2|3XsQ4)M-Ppv~Er<#x47rWFW-OYH_1h0A8WcBO0AU&fc(nQWuxk0tz@Y+)56B}t|d1R#;fzUek z7G%+nHn4@o+pb5bpi+MN41JHk%YE;{ASYsZ*d^#7sb=fBx-b7LT9VSBw+k@Q3B}>w zS2sGG^JE*xRgbKoF52G$rh+(n^O0q|4*-R_pzdy9!by%TneLV`PI%0WEcJM`aY8;8L38H=IRZz_C60XYm!LCqn!;(JN zJ2UbzTAu0&Mc4xAtP-H`0!NaT?6n~TwU2b;MhBvxc`3LU%WWoUAu{@~2j0$|+Ng1g z5?{8(ANA&-D+&h0cjgC{&qNM!0VxkCki`#>rfj-?{P=+*@k7KV{8*mDZ4nrNjtps6 zivw-9auoVZ$D#i1eC|K2gf~Ke?-hHAVd1-D3eXW z+;2k49s@{EJX|~#El#^cd>r3zjTUbyyY#7%-<8X^#o!8^KDZ8@72Cb=uz8#>ngDTD zffhaI6GB^ZryESHCQF*G?bvsMg>)LrO64j3UJ*>6(aaNACZ%14IN5|7Jrevqw}y3B z=vntMrAQD-FwUkONe=Aste|UM!dJ(fK=G2CJ85)cOle$*@E27J~h2|$DKs&V~gGc>VZFMD+ zh=uh9oaiAO{~R;+tbMWu+$-{U2qFbwd)z7@R-z<*m#!X59`mz=$9j0I8FT%hl2s6t zo$<=Hb(;N!Kzj4c1NepKVb1kqX&b$*b2PxM@*|Pb81IMWPoy_~O|d7xkBTlN#0x6x ScI^^wF{^5{CB!5okp2&YO69cx literal 0 HcmV?d00001 diff --git a/sound/weapons/mortar_whistle.ogg b/sound/weapons/mortar_whistle.ogg new file mode 100644 index 0000000000000000000000000000000000000000..2d7e19d85da0634d4c2c424c22769f302ec4bf64 GIT binary patch literal 6885 zcmai12|SeD_kS$e(-=#mhDH%1dX23{DP$c~hOs7vu?u5q6*7d7Wk?L!MvN_ENfK>j z-;Jf-@Y*V*QdCO+JL7%d-~0dl|DWIQ`P}Dz?sLz*=iGD7_nhb46YlPo5GVBKbI5OV z5V`YI0*5q5h#$$>GmtgKpuKlOWV8>^ zZ9V-x_MafRqkKG_t=a5RCMZ=EjH-&NiW*Acgzq^|e-bf}crFOd;?1#Tb1Pc!m^BB) z2WBv4sFv`)BmxA%An1%NS~%6s1WlvlDO}8;7_&w#DzO=q*cOCKJf`)p4yEoY4nf>d zxB`D-!JLU#57r$apGeBZdLBP`7sVTAF^T1W`em=nxuTjP?{ht9IlirSTOeQ;9b=g& zF+8htj**E*fbKey)FyM6N)k{k&b=m}+J=fWQ+->QdR*&maY3TiJB6A)JwfG~0h}3T z*xIGy5s%}Qz#i;8_0NuVjqJp${+z&n`)t;aG)k+lq_aaCDvJm z?CzI6@kz--RHI+bz|zW`0G?n+n-JniNbpEVs9i>sLw%@SeU!s!l;c{|Sw!@o?Q7`7 z8mqBYM{z*8d$8%#==|L~^8di*bCILVI3ZV-Nl^SLyU{5HCPi*u6`omj9;J1@oeZT; zh7fxR@F_RzG*GT*X3_s?Zg%O!|K4;w+7uxjV9OT)$QJ>!26)*QBqd(9h1($DQysig z3rXE5Q2j;VVbF|%^xG+B-Ji|2{pAFf+aX8?gKP;vwgYS6l?O>0Hi6nBf#xH?6fBGU z=O==V7odntwp+SaIGyPZe&JJPX!&4rKC{ zjM;*{c72(1#Sg^5D3+2XU;Dsnli#1PC^=2-d4in+J7UMPydUs8g3&iu>icef*4)3t zM+f-r>?oo&`x+`Vk;hp~rbs4LI_RcwYA&V?T_~N9XoxF`Jc*Z-rv+VOYmR~-GK`Jl zzdAOQH&I-e5~tXqP~D~4sl@8ap7m%g+Gzs4l6`CCXBr3$Fd&XwcALRRVR4g?7*Y zsND|?8f38jpALYa$4Nq_>^x$DS02V|4C9pvR@(nLVgPkm-F#3T7&Z-pBq3-Ia55Pd zM@rH=r)|rJnUmd;hvmt8jv(KKsR?1X?hZ=QmDjFM!9EjOnZzrI>zhR;$Q?*TZGBpF z%4GH+A4q%LkOc&VW7;s!5u_fI_FVlQ41YGI4J%Je9WX&Frz6zRaz${LX==fMNqZp$ zVH%fR2zQAs2b&;X@CxSjC5dzBh(VCE5MBTsMZx!==aTRpm{}wqhrLU+?7{L$kvlLv z*^w|b4Qbhfet{%+>CRFk`*al`2=$l)ym|`it_BcH9-8!*?M+oT6_Ya+HRu&1j))WeN9J3<)E+~n7@L(QVWdvOB8Xr?Alg|G>_UikYXlo+s41XY znvaPS2z7+9FTRBI(5WDTqYZIvjbJBn)nO!RYBh8U!QwnJ91N&unZ&dAgC`U`Gd;cX zi|LsPbb1NB&X-B3M!}m~g`FaOnFz^-I>xX;*wpE|o z3FcZ?_8mQYFp=h-2~J8c&!U$uFwX6JR<@vLK?rqBBTgJ}wA+4e;y|LqNJ2jSU4vq0 z6A*-X)#`_QsDgBSsR;<#jB>$Hm$o(jUhkK!0qa`RtHA}8Li{go0&H-wup!!^lP9x} zGyEV2#3M5=W(iYlK?T9^?@)zS7#^9xCG zb`s~EM`7ZyUlChzm@0zRHwQVUqo3MEW&m^v|sa~LKP>?njgn4nw5EPa(*GxxNj0IPPE zaJG!u3<_X%J2C}_D^E+ocTrPWtRfR}Cg{2poEbP34p$Y0xA(y?sdyg^a4Ntm1?QvO zYVTlH8w|4-WS^?M*4o>vycGzSqajRjRkae{=P+|SaGvEX;Uz5+4v9dxrME^A(~CuL z@YQB!2I9(@L-+(haPfUKoOyZqFU_63lv|n3%ze6a>uC!7n?3Fjx~vQh{uY;|MsJtm$o zQWsW{U#|-*UqUj|L!${@x_olAJyiJi{JTu#4b8i|jli2PN@BI*0-w7wZml?!vx7s)NjkBnvCHQX_@+_{706 zz`v>s3p$t{Ab@%=FA{V#$^eUi$Gt^?IW#SZMWEmXAV|?4R7CeITm!Eq=YpKc30-96 zOdOUsk79^!MNv}lKpar1gd_xP*J8~gQ0x~`02)3TAus@|R{LYP@)ld~3K<&HxlCgO zfVg%p(;Ei}-rWx%=+zcp=pNTj15J4ZzoNP;TZwQKFk?I>TFf~PGfzFnhi=ILHBJ$N zReFG*EUW&A2L$lh3JBPFB&(waCjP51`PYd5|52g@)LA0d;BVcE*vYq9l^ep@pDsRs z7U>zApZ}=Y|5d&Jr;&qqIe^?hJ4mNlfEW73yVKg}AbN+O5=%#zFevn%Wq=d&NRgw_ zZwkr4J$c7)SOqzN5;PjX2ShZ*9(Owsk5`nVrL$7UkUdTr@aC1HG4WnNiWVQOW{4$f zRM!|yW7^+P1|f$7pU&|b(Ri?=Wz@M0Q#gPJ@riIL0|8|34UX=ujIL!m$JYY;gABoR zzM;Xi7lbCy`9tBx_X48R3ag*?PqKY21Bz`uwzXLo13d6WE( z^;$qP+fXf3a=Ixwi3D@rFM^N58dVXEC0h`~6bwzw67T(n>Kt!zBHIOrc~(ZT#wjFU z8z7a{hID}&C5jJHfyt;v=x~T3+JGQ3HyX;l_qY#piko`|t|}lT@PZsT;K>ES$ZbN& zF}6Z*QF=tavle7~>P#DNxKKhu%?-gfs*krgz6wT>QQR^yEgWJ=;gO=}F8s0eMEw(f zEd!eH<^`Aol7^s^t*G6*GqH)nH@79hl0{PBsiG7BUkIAy2;T;U%WjE@iE&FTcs9)? ztM5uKd_Kc1$0oBnKEBPX3O9Sqz94g#scn*37i5;0;Zw5y;;JfLeLcNB<9+>oy#s9u zXhr4y8md8C1RwrhjNABneNj-??)CTEq>C4hnD~^=zqNe7BE9OKdSjYl&9m25ZI7qw zv!uJ;0Z_b%cC}RGn*-EJKPg+mUsrJVsaY$R{RHQhz76sX*H&xamCY`=^{VONSZ(E@ z&ix#j?p7^w8T({(;B#+RzUMSlcy~_SYb5oVE9#ilEE@@&AzeAB9ri)`kS}FsMdKA> z{fE;=Q;x?kucn&=_|-D+_7~A_rbN{!obK5L45!a2C{5EN4PJMAGIM*2pKhy^>LWMc zT}R|*NEsctxJjE>s<+&;?}CqGGN-enwUQxi3P$HRXwxp%Sez~}zxF9$kL znGJi5V~ekSwT#_Z>gnQJNbETNbyVBXv03o*D9k8eY_a2Xi18ZjQhNx8@{>J_PpDn% z!yHWqW#4M51mw}9Q#Du68X0D#Gy0dcl8-=LP8o-S=kIpc-}1AEhYdA+Gwx9h4ov>( zI;*GG@ZL${dbPO1?NWXB$9(!zOPs>K^2*N@eYag$ON>n$w`k<$J~FS!*V&c46Ze2q zBh}k#B==6|ZQZx4OUMiQwnyhzC&YKCE@(CBFY1JCJll|oIUC`$=N;vt@io=)(EPQl zTan~eY{*5qacNElD#-WNEC+Yw`s8IX_u@SkreDs~7Okww#+7lle?1)0d@^?E{wqHN zT+fmiH+0%W|3l1-iuGrlYpir;gU4e-De~RW*jwMn5pTIr%e$Hphkn%bX64O&k7i!E ztV{LoTKf^mG(=p?uUI@9^=fY7@R`$jTT&|yTb*N`f1T8jQ2vOAxMNkLS+5c~tG=VC zT7P#f=C(~YX8|_(!ljiDhNH!n#u?vU;`}?Q+_$XD_uZ6WG~|KEdoQvvhpIeNU-Ei7 zK0R@HHlq-RusW5hkTx?SyZUZ8~u(%)LQI*lH((Vmr$jSx=Byp+iqvSd%SKo zuWpju9l3KJ$UfJO5j+zi&vpNH3!HDSxaI@fsyNQ1-l_i68%v)S>vj!hr44uY|6Du2 z;+9^$aBH2KkT6kx=Xzc6O?mMPPh|@QEXeL;t)Xi@>z)}{RD88_+IJ^gx1WaF^Uv~q zdwO5FP(7PyAL=Xh@!XlNGp}F9{B+#qOMw#;u+LByt$xHSH@+6#6F*Zocsx(4msVm_ z{HdaGx9g-c2UGA-eAp?0X%saFK3gE={Ve$N4*`a0H4n5ta+`0^Da#ajf)^D#T3 zH6EC0Jrd+@mQ&r` zOTWztR2`k-u#T(BW=}XYc0kN&bVL z+iek1H{_XBA1acpe=j+?r>1Kf+Z7KB+k5G*zn4dq!AU*M0J|vf^kg1OpRH=S*ma@g z)ZN^aD?sR$5HF`PZD@!sRUt~0?Jk+#TNNpS~g{N^omAI*%n0@@Z z8q#Q#F=JOpT9RKK7u}bBwix##By6=Z?n=wlzL>Qbln*>3Pofqx_#b7;cFD!;ikao0Mwp^dnOVGueH{jI zIwri~Cqf)fbb48bHFxZ6nz-`u{hg-6SJI7F{C}yQ?d%WQzDkM+X?NWE(RadTQEJ0;R(sor&%%b!FQrx#lY90zaZjH> z{bU>w>Z;=R^xVOCNZi$`;eWz}zE^DjtW{(W0(-yxFh;ELkkZV%Demi@b&VQMh45!_ z>qiRe#3$uFY8a};cSO05jifPuJS5Zz-l^O+tdMhTfez(l>c5Yfggbo?8FLTn*nL|d zcWK-!+@w_(>t>o2&fBbG7Md@So-7ijkz=YWGM(@{ z?;h=3syaUt!mT>e&}pRarcPn_&hgVKFWWR6SbEx8$15Q{({J)!cXF98m<#i*A71FoHcQK`_rAO^O+BLTn&0(C6#XtI9b@a^< zxgtef(a4NB;&@&3rFm%!C~1csmu66GgUK{;VsxF4Q4FdD>F=^*JN6kJE}K@pHa~8y zbFNtXjB1g%FA#a$3XiQ>hnir~A08YT9a&gIWfZk%DkemROk7u;q~_~mh0!2g%4lNzSx~&@pAt=x8b)vmcJ?2 zgdZ{FH7p%pwD1fG81&ol*ISQU;2$#5+J!`AJ?{|Dt6aAnIG-}N;^UQ2oll-DG(EfH zr3}}PUOi!UmiE5T)&u83}r%Yq*mUSiT>Kc!&5J>!x%MMki=W$WV-Rk zsnmdo7xEh)`}*_OGp@gJcYt}NV9cuUw(~kANA^NU+xqd!)`}YgQ-MbtU=DMF&95#vH0@n%g?aR~LH`Wt1 z61P=Lr6IWHx%Be7P}o@0;2T5P`X7uYMHRI338{+~Pd^>bnxsyQTpUn3mHJM|W5rGvew+7>b_}GP@8h-k`mJe=7-#s50OuIO6|Z8-LM*C-amg(`uosldsWe% zJ#>wQ@Oi#lTWucJUlo|@pZ>r}u@~G+tfpTW8*|g+Rk`FLGDZxu>8Rh;Ury@$^mYI1 z@78;A`e-W6qda81DNl&urR}rsM@5xk!yIcF*_zgQ<(@$cwqey-w~o~9oN3OUl>S`# zXl)oqwii4=G!;>a+S3!s;+M#u3#vktxSsYf8pw`fl|FW_e%>V!Z literal 0 HcmV?d00001 diff --git a/tgui/src/interfaces/centcom_podlauncher.ract b/tgui/src/interfaces/centcom_podlauncher.ract index 7f779ec3..64ea1d4e 100644 --- a/tgui/src/interfaces/centcom_podlauncher.ract +++ b/tgui/src/interfaces/centcom_podlauncher.ract @@ -1,23 +1,29 @@ - To use this, simply spawn the atoms you want in one of the four Centcom Supplypod Bays. Items in the bay will then be launched inside your supplypod, one turf-full at a time! You can optionally use the following buttons to configure how the supplypod acts. + To use this, simply spawn the atoms you want in one of the five Centcom Supplypod Bays. Items in the bay will then be launched inside your supplypod, one turf-full at a time! You can optionally use the following buttons to configure how the supplypod acts. - - Bay #1 - Bay #2 - Bay #3 - Bay #4 + + + + Bay #1 + Bay #2 + Bay #3 + Bay #4 + ERT Bay - - Teleport to Centcom's Supplypod Loading Bay - Teleport Back to {{data.oldArea ? data.oldArea : "where you were"}} + + + + {{data.bay}} + {{data.oldArea ? data.oldArea : "where you were"}} - - Clone and Launch + + + + Launch Clones @@ -27,101 +33,126 @@ tooltip='Instead of launching everything in the bay at once, this will launch one random turf of items at a time.'>Random + + - Custom Size - Adminbus - + Custom Size + Adminbus + + - Custom Damage - Gib - + Custom Damage + Gib + + + + + Stun + Delimb + Yeet Organs + + + + + Bluespace + Stealth + Quiet Landing + Reverse Mode + Missile Mode + Any Descent Angle + Machine Gun Mode + Specific Target + + + + + Custom Name/Desc + Alert Ghosts + - - Stun - Delimb - Bluespace - Stealth - Quiet Landing - Reverse Mode - Missile Mode - Any Descent Angle - Machine Gun Mode - Specific Target - Custom Name/Desc - - Custom Landing Sound - Custom Opening Sound - Custom Leaving Sound - Admin Sound Volume - + Custom Falling Sound + Custom Landing Sound + Custom Opening Sound + Custom Leaving Sound + Admin Sound Volume + + - Custom Landing Time - Custom Opening Time - Custom Leaving Time - + Custom Falling Duration + Custom Landing Time + Custom Opening Time + Custom Leaving Time + + Standard - Advanced - Syndicate - Deathsquad - Cult Pod - Missile - Syndicate Missile - Supply Crate - HONK - Fruit~ - Invisible - Gondola (alive) - + Advanced + Syndicate + Deathsquad + Cult Pod + Missile + Syndicate Missile + Supply Crate + HONK + Fruit~ + Invisible + Gondola (alive) + Show Contents (See-Through Pod)! + + - - + Refresh Pod Bay - - - - Enter Launch Mode + Enter Launch Mode + Clear Selected Bay