diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql index 19521d79686..99c51c205f1 100644 --- a/SQL/paradise_schema.sql +++ b/SQL/paradise_schema.sql @@ -268,6 +268,7 @@ CREATE TABLE `player` ( `atklog` smallint(4) DEFAULT '0', `fuid` BIGINT(20) NULL DEFAULT NULL, `fupdate` SMALLINT(4) NULL DEFAULT 0, + `afk_watch` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `ckey` (`ckey`) ) ENGINE=InnoDB AUTO_INCREMENT=32446 DEFAULT CHARSET=latin1; diff --git a/SQL/paradise_schema_prefixed.sql b/SQL/paradise_schema_prefixed.sql index ff4026c7d00..c64317084d7 100644 --- a/SQL/paradise_schema_prefixed.sql +++ b/SQL/paradise_schema_prefixed.sql @@ -267,6 +267,7 @@ CREATE TABLE `SS13_player` ( `atklog` smallint(4) DEFAULT '0', `fuid` BIGINT(20) NULL DEFAULT NULL, `fupdate` SMALLINT(4) NULL DEFAULT 0, + `afk_watch` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `ckey` (`ckey`) ) ENGINE=InnoDB AUTO_INCREMENT=32446 DEFAULT CHARSET=latin1; diff --git a/SQL/updates/7-8.sql b/SQL/updates/7-8.sql new file mode 100644 index 00000000000..16bc90b7a50 --- /dev/null +++ b/SQL/updates/7-8.sql @@ -0,0 +1,2 @@ +# Add afk_watch which gives users the option to make use of the AFK watcher subsystem +ALTER TABLE `player` ADD `afk_watch` tinyint(1) NOT NULL DEFAULT '0'; diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 9f2556df3a4..b491bc6e354 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -315,7 +315,7 @@ #define INVESTIGATE_BOMB "bombs" // The SQL version required by this version of the code -#define SQL_VERSION 7 +#define SQL_VERSION 8 // Vending machine stuff #define CAT_NORMAL 1 diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 3f155fa8031..5792aff1725 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -72,6 +72,11 @@ var/assistantlimit = 0 //enables assistant limiting var/assistantratio = 2 //how many assistants to security members + // The AFK subsystem will not be activated if any of the below config values are equal or less than 0 + var/warn_afk_minimum = 0 // How long till you get a warning while being AFK + var/auto_cryo_afk = 0 // How long till you get put into cryo when you're AFK + var/auto_despawn_afk = 0 // How long till you actually despawn in cryo when you're AFK (Not ssd so not automatic) + var/auto_cryo_ssd_mins = 0 var/ssd_warning = 0 @@ -314,6 +319,13 @@ if("shadowling_max_age") config.shadowling_max_age = text2num(value) + if("warn_afk_minimum") + config.warn_afk_minimum = text2num(value) + if("auto_cryo_afk") + config.auto_cryo_afk = text2num(value) + if("auto_despawn_afk") + config.auto_despawn_afk = text2num(value) + if("auto_cryo_ssd_mins") config.auto_cryo_ssd_mins = text2num(value) if("ssd_warning") diff --git a/code/controllers/subsystem/afk.dm b/code/controllers/subsystem/afk.dm new file mode 100644 index 00000000000..9f409fd35b4 --- /dev/null +++ b/code/controllers/subsystem/afk.dm @@ -0,0 +1,81 @@ +#define AFK_WARNED 1 +#define AFK_CRYOD 2 + +SUBSYSTEM_DEF(afk) + name = "AFK Watcher" + wait = 300 + flags = SS_BACKGROUND + var/list/afk_players = list() // Associative list. ckey as key and AFK state as value + + +/datum/controller/subsystem/afk/Initialize() + if(config.warn_afk_minimum <= 0 || config.auto_cryo_afk <= 0 || config.auto_despawn_afk <= 0) + flags |= SS_NO_FIRE + +/datum/controller/subsystem/afk/fire() + var/list/toRemove = list() + for(var/mob/living/carbon/human/H in GLOB.living_mob_list) + if(!H.ckey) // Useless non ckey creatures + continue + + var/turf/T + // Only players and players with the AFK watch enabled + // No dead, unconcious, restrained, people without jobs, people on other Z levels than the station or antags + if(!H.client || !H.client.prefs.afk_watch || !H.mind || \ + H.stat || H.restrained() || !H.job || H.mind.special_role || \ + !is_station_level((T = get_turf(H)).z)) // Assign the turf as last. Small optimization + if(afk_players[H.ckey]) + toRemove += H.ckey + continue + + var/mins_afk = round(H.client.inactivity / 600) + if(mins_afk < config.warn_afk_minimum) + if(afk_players[H.ckey]) + toRemove += H.ckey + continue + + if(!afk_players[H.ckey]) + afk_players[H.ckey] = AFK_WARNED + warn(H, "You are AFK for [mins_afk] minutes. You will be cryod after [config.auto_cryo_afk] total minutes and fully despawned after [config.auto_despawn_afk] total minutes. Please move or click in game if you want to avoid being despawned.") + else + var/area/A = T.loc // Turfs loc is the area + if(afk_players[H.ckey] == AFK_WARNED) + if(mins_afk >= config.auto_cryo_afk && A.can_get_auto_cryod) + if(A.fast_despawn) + toRemove += H.ckey + warn(H, "You are have been despawned after being AFK for [mins_afk] minutes. You have been despawned instantly due to you being in a secure area.") + msg_admins(H, mins_afk, T, "forcefully despawned", "AFK in a fast despawn area") + force_cryo_human(H) + else if(cryo_ssd(H)) + afk_players[H.ckey] = AFK_CRYOD + msg_admins(H, mins_afk, T, "put into cryostorage") + warn(H, "You are AFK for [mins_afk] minutes and have been moved to cryostorage. After being AFK for [config.auto_despawn_afk] total minutes you will be fully despawned. Please eject yourself (right click, eject) out of the cryostorage if you want to avoid being despawned.") + + else if(mins_afk >= config.auto_despawn_afk) + var/obj/machinery/cryopod/P = H.loc + msg_admins(H, mins_afk, T, "forcefully despawned") + warn(H, "You are have been despawned after being AFK for [mins_afk] minutes.") + toRemove += H.ckey + P.despawn_occupant() + + removeFromWatchList(toRemove) + +/datum/controller/subsystem/afk/proc/warn(mob/living/carbon/human/H, text) + to_chat(H, text) + SEND_SOUND(H, 'sound/effects/adminhelp.ogg') + if(H.client) + window_flash(H.client) + +/datum/controller/subsystem/afk/proc/msg_admins(mob/living/carbon/human/H, mins_afk, turf/location, action, info) + log_admin("[key_name(H)] has been [action] by the AFK Watcher subsystem after being AFK for [mins_afk] minutes.[info ? " Extra info:" + info : ""]") + message_admins("[key_name_admin(H)] at ([get_area(location).name] [ADMIN_JMP(location)]) has been [action] by the AFK Watcher subsystem after being AFK for [mins_afk] minutes.[info ? " Extra info:" + info : ""]") + +/datum/controller/subsystem/afk/proc/removeFromWatchList(list/toRemove) + for(var/C in toRemove) + for(var/i in 1 to afk_players.len) + if(afk_players[i] == C) + afk_players.Cut(i, i + 1) + break + +#undef AFK_WARNED +#undef AFK_CRYOD \ No newline at end of file diff --git a/code/controllers/subsystem/input.dm b/code/controllers/subsystem/input.dm index fa46e50f779..f379deec72b 100644 --- a/code/controllers/subsystem/input.dm +++ b/code/controllers/subsystem/input.dm @@ -33,25 +33,22 @@ SUBSYSTEM_DEF(input) "default" = list( "Tab" = "\".winset \\\"input.focus=true?map.focus=true input.background-color=[COLOR_INPUT_DISABLED]:input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"", "O" = "ooc", - "T" = "say", - "M" = "me", - "F3" = "say", + "T" = ".say", + "M" = ".me", "Back" = "\".winset \\\"input.focus=true input.text=\\\"\\\"\\\"\"", // This makes it so backspace can remove default inputs "Any" = "\"KeyDown \[\[*\]\]\"", "Any+UP" = "\"KeyUp \[\[*\]\]\"", ), "old_default" = list( "Tab" = "\".winset \\\"mainwindow.macro=old_hotkeys map.focus=true input.background-color=[COLOR_INPUT_DISABLED]\\\"\"", - "Ctrl+T" = "say", + "Ctrl+T" = ".say", "Ctrl+O" = "ooc", - "F3" = "say", ), "old_hotkeys" = list( "Tab" = "\".winset \\\"mainwindow.macro=old_default input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"", "O" = "ooc", - "T" = "say", - "M" = "me", - "F3" = "say", + "T" = ".say", + "M" = ".me", "Back" = "\".winset \\\"input.focus=true input.text=\\\"\\\"\\\"\"", // This makes it so backspace can remove default inputs "Any" = "\"KeyDown \[\[*\]\]\"", "Any+UP" = "\"KeyUp \[\[*\]\]\"", @@ -118,6 +115,8 @@ SUBSYSTEM_DEF(input) /datum/controller/subsystem/input/fire() var/list/clients = GLOB.clients // Let's sing the list cache song + if(listclearnulls(clients)) // clear nulls before we run keyloop + log_world("Found a null in clients list!") for(var/i in 1 to clients.len) var/client/C = clients[i] C.keyLoop() diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index 91af56437cf..7fe8696b325 100644 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -1400,10 +1400,12 @@ var/list/ghostteleportlocs = list() name = "\improper Prison Wing" icon_state = "sec_prison_perma" fast_despawn = TRUE + can_get_auto_cryod = FALSE /area/security/prison name = "\improper Prison Wing" icon_state = "sec_prison" + can_get_auto_cryod = FALSE /area/security/prison/prison_break() for(var/obj/structure/closet/secure_closet/brig/temp_closet in src) @@ -1432,14 +1434,17 @@ var/list/ghostteleportlocs = list() /area/security/execution name = "\improper Execution" icon_state = "execution" + can_get_auto_cryod = FALSE /area/security/processing name = "\improper Prisoner Processing" icon_state = "prisonerprocessing" + can_get_auto_cryod = FALSE /area/security/interrogation name = "\improper Interrogation" icon_state = "interrogation" + can_get_auto_cryod = FALSE /area/security/seceqstorage name = "\improper Security Equipment Storage" @@ -1456,6 +1461,7 @@ var/list/ghostteleportlocs = list() /area/security/interrogationobs name = "\improper Interrogation Observation" icon_state = "security" + can_get_auto_cryod = FALSE /area/security/evidence name = "\improper Evidence Room" @@ -1464,6 +1470,7 @@ var/list/ghostteleportlocs = list() /area/security/prisonlockers name = "\improper Prisoner Lockers" icon_state = "sec_prison_lockers" + can_get_auto_cryod = FALSE /area/security/medbay name = "\improper Security Medbay" @@ -1472,6 +1479,7 @@ var/list/ghostteleportlocs = list() /area/security/prisonershuttle name = "\improper Security Prisoner Shuttle" icon_state = "security" + can_get_auto_cryod = FALSE /area/security/warden name = "\improper Warden's Office" diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 638fe29ab6d..486dbdc8b55 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -64,6 +64,7 @@ 'sound/ambience/ambigen12.ogg','sound/ambience/ambigen14.ogg') var/fast_despawn = FALSE + var/can_get_auto_cryod = TRUE /area/Initialize(mapload) GLOB.all_areas += src diff --git a/code/game/atoms.dm b/code/game/atoms.dm index c52df8c7912..757f036c691 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -361,7 +361,7 @@ fingerprintshidden += text("\[[time_stamp()]\] (Wearing gloves). Real name: [], Key: []",H.real_name, H.key) fingerprintslast = H.ckey return 0 - if(!( fingerprints )) + if(!fingerprints) if(fingerprintslast != H.ckey) //Add the list if it does not exist. if(!fingerprintshidden) diff --git a/code/game/gamemodes/nuclear/pinpointer.dm b/code/game/gamemodes/nuclear/pinpointer.dm index bfc30780b81..07ee2219157 100644 --- a/code/game/gamemodes/nuclear/pinpointer.dm +++ b/code/game/gamemodes/nuclear/pinpointer.dm @@ -165,10 +165,13 @@ var/targetitem = input("Select item to search for.", "Item Mode Select","") as null|anything in item_names if(!targetitem) return - var/list/obj/item/target_candidates = get_all_of_type(item_paths[targetitem], subtypes = TRUE) - for(var/obj/item/candidate in target_candidates) - if(!is_admin_level(candidate.loc.z)) - target = candidate + + var/list/target_candidates = get_all_of_type(item_paths[targetitem], subtypes = TRUE) + for(var/obj/item/candidate in target_candidates) + if(!is_admin_level((get_turf(candidate)).z)) + target = candidate + break + if(!target) to_chat(usr, "Failed to locate [targetitem]!") return diff --git a/code/game/gamemodes/vampire/vampire_powers.dm b/code/game/gamemodes/vampire/vampire_powers.dm index 5eb4b3f0242..de956b9e7cb 100644 --- a/code/game/gamemodes/vampire/vampire_powers.dm +++ b/code/game/gamemodes/vampire/vampire_powers.dm @@ -261,8 +261,10 @@ for(var/mob/living/carbon/C in hearers(4)) if(C == user) continue - if(ishuman(C) && (C:l_ear || C:r_ear) && istype((C:l_ear || C:r_ear), /obj/item/clothing/ears/earmuffs)) - continue + if(ishuman(C)) + var/mob/living/carbon/human/H = C + if(istype(H.l_ear, /obj/item/clothing/ears/earmuffs) || istype(H.r_ear, /obj/item/clothing/ears/earmuffs)) + continue if(!affects(C)) continue to_chat(C, "You hear a ear piercing shriek and your senses dull!") diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm index 9245f5174ce..045819c365b 100644 --- a/code/modules/admin/IsBanned.dm +++ b/code/modules/admin/IsBanned.dm @@ -108,7 +108,7 @@ world/IsBanned(key, address, computer_id, check_ipintel = TRUE) var/appealmessage = "" if(config.banappeals) appealmessage = " You may appeal it at [config.banappeals]." - expires = " This is a permanent ban.[appealmessage]" + expires = " This ban does not expire automatically and must be appealed.[appealmessage]" var/desc = "\nReason: You, or another user of this computer or connection ([pckey]) is banned from playing here. The ban reason is:\n[reason]\nThis ban was applied by [ackey] on [bantime].[expires]" diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index ffa33df033f..85d835651e3 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1015,14 +1015,14 @@ return AddBan(M.ckey, M.computer_id, reason, usr.ckey, 0, 0, M.lastKnownIP) to_chat(M, "You have been banned by [usr.client.ckey].\nReason: [reason].") - to_chat(M, "This is a permanent ban.") + to_chat(M, "This ban does not expire automatically and must be appealed.") if(config.banappeals) to_chat(M, "To try to resolve this matter head to [config.banappeals]") else to_chat(M, "No ban appeals URL has been set.") - ban_unban_log_save("[usr.client.ckey] has permabanned [M.ckey]. - Reason: [reason] - This is a permanent ban.") - log_admin("[key_name(usr)] has banned [M.ckey].\nReason: [reason]\nThis is a permanent ban.") - message_admins("[key_name_admin(usr)] has banned [M.ckey].\nReason: [reason]\nThis is a permanent ban.") + ban_unban_log_save("[usr.client.ckey] has permabanned [M.ckey]. - Reason: [reason] - This ban does not expire automatically and must be appealed.") + log_admin("[key_name(usr)] has banned [M.ckey].\nReason: [reason]\nThis ban does not expire automatically and must be appealed.") + message_admins("[key_name_admin(usr)] has banned [M.ckey].\nReason: [reason]\nThis ban does not expire automatically and must be appealed.") feedback_inc("ban_perma",1) DB_ban_record(BANTYPE_PERMA, M, -1, reason) diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm index e09fc89736a..3c8b293ea28 100644 --- a/code/modules/client/preference/preferences.dm +++ b/code/modules/client/preference/preferences.dm @@ -93,6 +93,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts var/clientfps = 0 var/atklog = ATKLOG_ALL var/fuid // forum userid + var/afk_watch = FALSE // If the player wants to be kept track of by the AFK system //ghostly preferences var/ghost_anonsay = 0 @@ -439,6 +440,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts dat += "

General Settings

" if(user.client.holder) dat += "Adminhelp sound: [(sound & SOUND_ADMINHELP)?"On":"Off"]
" + dat += "AFK Cryoing: [(afk_watch) ? "Yes" : "No"]
" dat += "Ambient Occlusion: [toggles & AMBIENT_OCCLUSION ? "Enabled" : "Disabled"]
" dat += "Attack Animations: [(show_ghostitem_attack) ? "Yes" : "No"]
" if(unlock_content) @@ -1977,6 +1979,9 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts if("winflash") windowflashing = !windowflashing + if("afk_watch") + afk_watch = !afk_watch + if("UIcolor") var/UI_style_color_new = input(user, "Choose your UI color, dark colors are not recommended!", UI_style_color) as color|null if(!UI_style_color_new) return diff --git a/code/modules/client/preference/preferences_mysql.dm b/code/modules/client/preference/preferences_mysql.dm index 90a4bed6f14..cdbfe2afb2f 100644 --- a/code/modules/client/preference/preferences_mysql.dm +++ b/code/modules/client/preference/preferences_mysql.dm @@ -19,7 +19,8 @@ exp, clientfps, atklog, - fuid + fuid, + afk_watch FROM [format_table_name("player")] WHERE ckey='[C.ckey]'"} ) @@ -52,6 +53,7 @@ clientfps = text2num(query.item[17]) atklog = text2num(query.item[18]) fuid = text2num(query.item[19]) + afk_watch = text2num(query.item[20]) //Sanitize ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor)) @@ -72,6 +74,7 @@ clientfps = sanitize_integer(clientfps, 0, 1000, initial(clientfps)) atklog = sanitize_integer(atklog, 0, 100, initial(atklog)) fuid = sanitize_integer(fuid, 0, 10000000, initial(fuid)) + afk_watch = sanitize_integer(afk_watch, 0, 1, initial(afk_watch)) return 1 /datum/preferences/proc/save_preferences(client/C) @@ -90,7 +93,7 @@ UI_style_alpha='[UI_style_alpha]', be_role='[sanitizeSQL(list2params(be_special))]', default_slot='[default_slot]', - toggles='[num2text(toggles, 7)]', + toggles='[num2text(toggles, Ceiling(log(10, (TOGGLES_TOTAL))))]', atklog='[atklog]', sound='[sound]', randomslot='[randomslot]', @@ -101,7 +104,8 @@ windowflashing='[windowflashing]', ghost_anonsay='[ghost_anonsay]', clientfps='[clientfps]', - atklog='[atklog]' + atklog='[atklog]', + afk_watch='[afk_watch]' WHERE ckey='[C.ckey]'"} ) diff --git a/code/modules/food_and_drinks/drinks/drinks/bottle.dm b/code/modules/food_and_drinks/drinks/drinks/bottle.dm index 8a88cac3461..cd50dcedb71 100644 --- a/code/modules/food_and_drinks/drinks/drinks/bottle.dm +++ b/code/modules/food_and_drinks/drinks/drinks/bottle.dm @@ -256,6 +256,7 @@ desc = "Full of vitamins and deliciousness!" icon_state = "orangejuice" item_state = "carton" + throwforce = 0 isGlass = 0 list_reagents = list("orangejuice" = 100) @@ -264,6 +265,7 @@ desc = "It's cream. Made from milk. What else did you think you'd find in there?" icon_state = "cream" item_state = "carton" + throwforce = 0 isGlass = 0 list_reagents = list("cream" = 100) @@ -272,6 +274,7 @@ desc = "Well, at least it LOOKS like tomato juice. You can't tell with all that redness." icon_state = "tomatojuice" item_state = "carton" + throwforce = 0 isGlass = 0 list_reagents = list("tomatojuice" = 100) @@ -280,6 +283,7 @@ desc = "Sweet-sour goodness." icon_state = "limejuice" item_state = "carton" + throwforce = 0 isGlass = 0 list_reagents = list("limejuice" = 100) @@ -288,6 +292,7 @@ desc = "Soothing milk." icon_state = "milk" item_state = "carton" + throwforce = 0 isGlass = 0 list_reagents = list("milk" = 100) diff --git a/code/modules/keybindings/bindings_client.dm b/code/modules/keybindings/bindings_client.dm index 75c30f232b5..e3925aa5283 100644 --- a/code/modules/keybindings/bindings_client.dm +++ b/code/modules/keybindings/bindings_client.dm @@ -22,8 +22,11 @@ if("F2") // Screenshot. Hold shift to choose a name and location to save in ooc() return + if("F3") + mob.say_wrapper() + return if("F4") - mob.me_verb() + mob.me_wrapper() return if("F12") // Toggles minimal HUD mob.button_pressed_F12() diff --git a/code/modules/keybindings/bindings_robot.dm b/code/modules/keybindings/bindings_robot.dm index a6b3cd3f21e..f9b39dc7351 100644 --- a/code/modules/keybindings/bindings_robot.dm +++ b/code/modules/keybindings/bindings_robot.dm @@ -10,6 +10,11 @@ cycle_modules() return if("Q") - uneq_active() - return + if(!(client.prefs.toggles & AZERTY)) + uneq_active() + return + if("A") + if(client.prefs.toggles & AZERTY) + uneq_active() + return return ..() \ No newline at end of file diff --git a/code/modules/keybindings/setup.dm b/code/modules/keybindings/setup.dm index ad87622b709..cc76256386e 100644 --- a/code/modules/keybindings/setup.dm +++ b/code/modules/keybindings/setup.dm @@ -43,4 +43,4 @@ var/key = macro_set[k] var/command = macro_set[key] winset(src, "[setname]-\ref[key]", "parent=[setname];name=[key];command=[command]") - winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=default") + winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=old_default") diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index c0e8badf35d..0c40ca76ea6 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -671,9 +671,9 @@ if(!restrained()) var/t1 = round(text2num(param)) if(isnum(t1)) - if(t1 <= 5 && (!r_hand || !l_hand)) + if(t1 <= 5 && t1 >= 1 && (!r_hand || !l_hand)) message = "[src] raises [t1] finger\s." - else if(t1 <= 10 && (!r_hand && !l_hand)) + else if(t1 <= 10 && t1 >= 1 && (!r_hand && !l_hand)) message = "[src] raises [t1] finger\s." m_type = 1 diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 80d644152f4..17fd47d560b 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -634,7 +634,7 @@ var/list/ai_verbs_default = list( return if(href_list["trackbot"]) - var/mob/living/simple_animal/bot/target = locate(href_list["trackbot"]) in GLOB.simple_animals + var/mob/living/simple_animal/bot/target = locate(href_list["trackbot"]) in GLOB.bots_list if(target) ai_actual_track(target) else @@ -642,7 +642,7 @@ var/list/ai_verbs_default = list( return if(href_list["callbot"]) //Command a bot to move to a selected location. - Bot = locate(href_list["callbot"]) in GLOB.simple_animals + Bot = locate(href_list["callbot"]) in GLOB.bots_list if(!Bot || Bot.remote_disabled || control_disabled) return //True if there is no bot found, the bot is manually emagged, or the AI is carded with wireless off. waypoint_mode = 1 @@ -650,7 +650,7 @@ var/list/ai_verbs_default = list( return if(href_list["interface"]) //Remotely connect to a bot! - Bot = locate(href_list["interface"]) in GLOB.simple_animals + Bot = locate(href_list["interface"]) in GLOB.bots_list if(!Bot || Bot.remote_disabled || control_disabled) return Bot.attack_ai(src) @@ -746,7 +746,7 @@ var/list/ai_verbs_default = list( d += "Query network status
" d += "" - for(var/mob/living/simple_animal/bot/Bot in GLOB.simple_animals) + for(var/mob/living/simple_animal/bot/Bot in GLOB.bots_list) if(is_ai_allowed(Bot.z) && !Bot.remote_disabled) //Only non-emagged bots on the allowed Z-level are detected! bot_area = get_area(Bot) d += "" diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 0c6ddf80fc6..131477d086e 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -1456,4 +1456,4 @@ var/list/robot_verbs_default = list( SEND_SIGNAL(src, COMSIG_MOB_UPDATE_SIGHT) sync_lighting_plane_alpha() - \ No newline at end of file + diff --git a/code/modules/mob/living/simple_animal/hostile/jungle_animals.dm b/code/modules/mob/living/simple_animal/hostile/jungle_animals.dm index 100225e0760..e34a5e0cb08 100644 --- a/code/modules/mob/living/simple_animal/hostile/jungle_animals.dm +++ b/code/modules/mob/living/simple_animal/hostile/jungle_animals.dm @@ -21,6 +21,7 @@ maxHealth = 50 health = 50 pixel_x = -16 + see_in_dark = 8 harm_intent_damage = 8 melee_damage_lower = 15 diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 4e486baba20..02cb948c5c9 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -693,9 +693,13 @@ var/list/slot_equipment_priority = list( \ msg = copytext(msg, 1, MAX_MESSAGE_LEN) msg = sanitize_simple(html_encode(msg), list("\n" = "
")) - - if(mind) + + var/combined = length(memory + msg) + if(mind && (combined < MAX_PAPER_MESSAGE_LEN)) mind.store_memory(msg) + else if(combined >= MAX_PAPER_MESSAGE_LEN) + to_chat(src, "Your brain can't hold that much information!") + return else to_chat(src, "The game appears to have misplaced your mind datum, so we can't show you your notes.") @@ -1366,5 +1370,19 @@ var/list/slot_equipment_priority = list( \ /mob/proc/sync_lighting_plane_alpha() if(hud_used) var/obj/screen/plane_master/lighting/L = hud_used.plane_masters["[LIGHTING_PLANE]"] - if (L) + if(L) L.alpha = lighting_alpha + + sync_nightvision_screen() //Sync up the overlay used for nightvision to the amount of see_in_dark a mob has. This needs to be called everywhere sync_lighting_plane_alpha() is. + +/mob/proc/sync_nightvision_screen() + var/obj/screen/fullscreen/see_through_darkness/S = screens["see_through_darkness"] + if(S) + var/suffix = "" + switch(see_in_dark) + if(3 to 8) + suffix = "_[see_in_dark]" + if(8 to INFINITY) + suffix = "_8" + + S.icon_state = "[initial(S.icon_state)][suffix]" diff --git a/code/modules/reagents/reagent_containers/glass_containers.dm b/code/modules/reagents/reagent_containers/glass_containers.dm index 17d68f7e607..1d6f46bf46c 100644 --- a/code/modules/reagents/reagent_containers/glass_containers.dm +++ b/code/modules/reagents/reagent_containers/glass_containers.dm @@ -73,7 +73,7 @@ if(user.a_intent == INTENT_HARM) M.visible_message("[user] splashes the contents of [src] onto [M]!", \ "[user] splashes the contents of [src] onto [M]!") - add_attack_logs(M, user, "Splashed with [name] containing [contained]", !!M.ckey ? null : ATKLOG_ALL) + add_attack_logs(user, M, "Splashed with [name] containing [contained]", !!M.ckey ? null : ATKLOG_ALL) if(!iscarbon(user)) M.LAssailant = null else @@ -90,11 +90,12 @@ if(!reagents || !reagents.total_volume) return // The drink might be empty after the delay, such as by spam-feeding M.visible_message("[user] feeds something to [M].", "[user] feeds something to you.") - add_attack_logs(M, user, "Fed with [name] containing [contained]", !!M.ckey ? null : ATKLOG_ALL) + add_attack_logs(user, M, "Fed with [name] containing [contained]", !!M.ckey ? null : ATKLOG_ALL) else to_chat(user, "You swallow a gulp of [src].") - reagents.reaction(M, INGEST) + var/fraction = min(5 / reagents.total_volume, 1) + reagents.reaction(M, INGEST, fraction) addtimer(CALLBACK(reagents, /datum/reagents.proc/trans_to, M, 5), 5) playsound(M.loc,'sound/items/drink.ogg', rand(10,50), 1) else diff --git a/config/example/config.txt b/config/example/config.txt index 87ed0ce5cf1..89b8767feab 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -85,6 +85,16 @@ LOG_WORLD_OUTPUT ## log admin warning messages LOG_ADMINWARN + +## Amount of minutes that a person has to be AFK before he will be warned by the AFK subsystem. Leave this 0 to prevent the subsystem from activating +WARN_AFK_MINIMUM 0 + +## Amount of minutes that a person has to be AFK before he will be cryod by the AFK subsystem. Leave this 0 to prevent the subsystem from activating +AUTO_CRYO_AFK 0 + +## Amount of minutes that a person has to be AFK before he will be despawned by the AFK subsystem. Leave this 0 to prevent the subsystem from activating +AUTO_DESPAWN_AFK 0 + ## probablities for game modes chosen in "secret" and "random" modes ## ## default probablity is 1, increase to make that mode more likely to be picked diff --git a/config/example/dbconfig.txt b/config/example/dbconfig.txt index fc1bced9d6a..2404119d52f 100644 --- a/config/example/dbconfig.txt +++ b/config/example/dbconfig.txt @@ -9,7 +9,7 @@ ## This value must be set to the version of the paradise schema in use. ## If this value does not match, the SQL database will not be loaded and an error will be generated. ## Roundstart will be delayed. -DB_VERSION 7 +DB_VERSION 8 ## Server the MySQL database can be found at. # Examples: localhost, 200.135.5.43, www.mysqldb.com, etc. diff --git a/html/changelogs/AutoChangeLog-pr-11484.yml b/html/changelogs/AutoChangeLog-pr-11484.yml new file mode 100644 index 00000000000..a6237397de8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11484.yml @@ -0,0 +1,4 @@ +author: "KasparoVy" +delete-after: True +changes: + - rscadd: "Re-adds the ability to see in the dark. Adds overlays for each level of darksight (>=8,7,6,5,4,3,<=2)." diff --git a/html/changelogs/AutoChangeLog-pr-11732.yml b/html/changelogs/AutoChangeLog-pr-11732.yml new file mode 100644 index 00000000000..8f44fc99dae --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11732.yml @@ -0,0 +1,4 @@ +author: "farie82" +delete-after: True +changes: + - rscadd: "Adds the AFK auto cryo system. By default it won't affect players unless they activate it themselves by setting the preference in their game preferences tab." diff --git a/html/changelogs/AutoChangeLog-pr-11825.yml b/html/changelogs/AutoChangeLog-pr-11825.yml new file mode 100644 index 00000000000..ca3de2da45c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11825.yml @@ -0,0 +1,4 @@ +author: "Ty-Omaha" +delete-after: True +changes: + - tweak: "Reworded permanent bans to non-expiring bans." diff --git a/html/changelogs/AutoChangeLog-pr-11836.yml b/html/changelogs/AutoChangeLog-pr-11836.yml new file mode 100644 index 00000000000..24758efc273 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11836.yml @@ -0,0 +1,4 @@ +author: "TheSardele" +delete-after: True +changes: + - tweak: "Lowers throwforce of drinking cartons from 15 to 0" diff --git a/html/changelogs/AutoChangeLog-pr-11851.yml b/html/changelogs/AutoChangeLog-pr-11851.yml new file mode 100644 index 00000000000..47a8eb82c03 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11851.yml @@ -0,0 +1,4 @@ +author: "Allfd" +delete-after: True +changes: + - tweak: "Panthers can now see in the dark." diff --git a/html/changelogs/AutoChangeLog-pr-11852.yml b/html/changelogs/AutoChangeLog-pr-11852.yml new file mode 100644 index 00000000000..5d94998f148 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11852.yml @@ -0,0 +1,4 @@ +author: "Couls" +delete-after: True +changes: + - bugfix: "fixes the runtime caused by running keyloop for clients" diff --git a/html/changelogs/AutoChangeLog-pr-11856.yml b/html/changelogs/AutoChangeLog-pr-11856.yml new file mode 100644 index 00000000000..cefc38d19db --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11856.yml @@ -0,0 +1,5 @@ +author: "Markolie" +delete-after: True +changes: + - bugfix: "Drinking from a beaker now only applies the effect of five units of the ingested chemical, instead of the entire volume of the beaker." + - bugfix: "Resolved an issue where beaker attack logs were reversed." diff --git a/html/changelogs/AutoChangeLog-pr-11861.yml b/html/changelogs/AutoChangeLog-pr-11861.yml new file mode 100644 index 00000000000..c430f657cbf --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11861.yml @@ -0,0 +1,4 @@ +author: "Couls" +delete-after: True +changes: + - bugfix: "Preferences not saving properly" diff --git a/html/changelogs/AutoChangeLog-pr-11867.yml b/html/changelogs/AutoChangeLog-pr-11867.yml new file mode 100644 index 00000000000..f18b03fc944 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11867.yml @@ -0,0 +1,4 @@ +author: "Couls" +delete-after: True +changes: + - rscadd: "Restore hotkey mode" diff --git a/html/changelogs/AutoChangeLog-pr-11872.yml b/html/changelogs/AutoChangeLog-pr-11872.yml new file mode 100644 index 00000000000..066c6bb27ea --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11872.yml @@ -0,0 +1,4 @@ +author: "Couls" +delete-after: True +changes: + - bugfix: "Q no longer drops items as a cyborg on AZERTY mode" diff --git a/html/changelogs/AutoChangeLog-pr-11873.yml b/html/changelogs/AutoChangeLog-pr-11873.yml new file mode 100644 index 00000000000..40626a2525b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11873.yml @@ -0,0 +1,4 @@ +author: "SteelSlayer" +delete-after: True +changes: + - bugfix: "The AI's robot control window now allows you to see and interact with available bots again" diff --git a/html/changelogs/AutoChangeLog-pr-11886.yml b/html/changelogs/AutoChangeLog-pr-11886.yml new file mode 100644 index 00000000000..e0d2c5fe116 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11886.yml @@ -0,0 +1,4 @@ +author: "TheSardele" +delete-after: True +changes: + - bugfix: "It is no longer possible to raise zero to -infinity fingers using the *signal emote" diff --git a/html/changelogs/AutoChangeLog-pr-11920.yml b/html/changelogs/AutoChangeLog-pr-11920.yml new file mode 100644 index 00000000000..224cb3173f7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11920.yml @@ -0,0 +1,4 @@ +author: "Couls" +delete-after: True +changes: + - bugfix: "typing indicators show up again" diff --git a/html/changelogs/AutoChangeLog-pr-11933.yml b/html/changelogs/AutoChangeLog-pr-11933.yml new file mode 100644 index 00000000000..29692d6a1d7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11933.yml @@ -0,0 +1,4 @@ +author: "and DominikPanic" +delete-after: True +changes: + - bugfix: "Limits IC notes" diff --git a/html/changelogs/AutoChangeLog-pr-11935.yml b/html/changelogs/AutoChangeLog-pr-11935.yml new file mode 100644 index 00000000000..2c480fcd02f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11935.yml @@ -0,0 +1,4 @@ +author: "Ty-Omaha" +delete-after: True +changes: + - tweak: "Gave plastic surgery to line 364 of atoms.dm" diff --git a/html/changelogs/AutoChangeLog-pr-11938.yml b/html/changelogs/AutoChangeLog-pr-11938.yml new file mode 100644 index 00000000000..80b8fe04530 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11938.yml @@ -0,0 +1,4 @@ +author: "farie82" +delete-after: True +changes: + - bugfix: "The syndicate can't use meta warfare no more. Advanced pinpointers no longer crash the server" diff --git a/html/changelogs/AutoChangeLog-pr-11946.yml b/html/changelogs/AutoChangeLog-pr-11946.yml new file mode 100644 index 00000000000..980f1fa2c52 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11946.yml @@ -0,0 +1,4 @@ +author: "TheSardele" +delete-after: True +changes: + - bugfix: "Earmuffs now properly protect you from vampire screeches no matter what you are wearing on your other ear" diff --git a/icons/mob/screen_full.dmi b/icons/mob/screen_full.dmi index 595b870a172..d1aa736b352 100644 Binary files a/icons/mob/screen_full.dmi and b/icons/mob/screen_full.dmi differ diff --git a/paradise.dme b/paradise.dme index aa90c6b58b7..270d843845c 100644 --- a/paradise.dme +++ b/paradise.dme @@ -198,6 +198,7 @@ #include "code\controllers\master.dm" #include "code\controllers\subsystem.dm" #include "code\controllers\verbs.dm" +#include "code\controllers\subsystem\afk.dm" #include "code\controllers\subsystem\air.dm" #include "code\controllers\subsystem\alarm.dm" #include "code\controllers\subsystem\assets.dm"

Name

Status

Location

Control

[Bot.hacked ? "(!) [Bot.name]" : Bot.name] ([Bot.model])