diff --git a/baystation12.dme b/baystation12.dme index bbdcaa38ead..1c4a43d0743 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -174,6 +174,7 @@ #include "code\datums\diseases\advance\symptoms\weight.dm" #include "code\datums\helper_datums\construction_datum.dm" #include "code\datums\helper_datums\events.dm" +#include "code\datums\helper_datums\getrev.dm" #include "code\datums\helper_datums\global_iterator.dm" #include "code\datums\helper_datums\teleport.dm" #include "code\datums\helper_datums\topic_input.dm" diff --git a/code/ZAS/Turf.dm b/code/ZAS/Turf.dm index 331c00dd37e..2dfcfcdf812 100644 --- a/code/ZAS/Turf.dm +++ b/code/ZAS/Turf.dm @@ -45,6 +45,45 @@ air_master.connect(sim, src) +/* + Simple heuristic for determining if removing the turf from it's zone may possibly partition the zone (A very bad thing). + Instead of analyzing the entire zone, we only check the nearest 3x3 turfs surrounding the src turf. + This implementation may produce false positives but it (hopefully) will not produce any false negatives. +*/ + +/turf/simulated/proc/can_safely_remove_from_zone() + #ifdef ZLEVELS + return 1 //not sure how to generalize this to multiz at the moment. + #else + + if(!zone) return 0 + + var/check_dirs = get_zone_neighbours(src) + var/unconnected_dirs = check_dirs + + for(var/dir in list(NORTHWEST, NORTHEAST, SOUTHEAST, SOUTHWEST)) + + //for each pair of "adjacent" cardinals (e.g. NORTH and WEST, but not NORTH and SOUTH) + if((dir & check_dirs) == dir) + //check that they are connected by the corner turf + var/connected_dirs = get_zone_neighbours(get_step(src, dir)) + if(connected_dirs && (dir & turn(connected_dirs, 180)) == dir) + unconnected_dirs &= ~dir //they are, so unflag the cardinals in question + + //it is safe to remove src from the zone if all cardinals are connected by corner turfs + return !unconnected_dirs + + #endif + +//helper for can_safely_remove_from_zone() +/turf/simulated/proc/get_zone_neighbours(turf/simulated/T) + . = 0 + if(istype(T) && T.zone) + for(var/dir in cardinal) + var/turf/simulated/other = get_step(T, dir) + if(istype(other) && other.zone == T.zone && !(other.c_airblock(T) & AIR_BLOCKED) && get_dist(src, other) <= 1) + . |= dir + /turf/simulated/update_air_properties() if(zone && zone.invalid) @@ -60,7 +99,7 @@ if(zone) var/zone/z = zone - if(s_block & ZONE_BLOCKED) //Hacky, but prevents normal airlocks from rebuilding zones all the time + if(can_safely_remove_from_zone()) //Helps normal airlocks avoid rebuilding zones all the time z.remove(src) else z.rebuild() diff --git a/code/__HELPERS/logging.dm b/code/__HELPERS/logging.dm index 69d01e3d358..50f55703d34 100644 --- a/code/__HELPERS/logging.dm +++ b/code/__HELPERS/logging.dm @@ -81,3 +81,15 @@ /proc/log_misc(text) diary << "\[[time_stamp()]]MISC: [text][log_end]" + +//pretty print a direction bitflag, can be useful for debugging. +/proc/print_dir(var/dir) + var/list/comps = list() + if(dir & NORTH) comps += "NORTH" + if(dir & SOUTH) comps += "SOUTH" + if(dir & EAST) comps += "EAST" + if(dir & WEST) comps += "WEST" + if(dir & UP) comps += "UP" + if(dir & DOWN) comps += "DOWN" + + return english_list(comps, nothing_text="0", and_text="|", comma_text="|") diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm index 478700d5f82..216a45ee1c3 100644 --- a/code/__HELPERS/type2type.dm +++ b/code/__HELPERS/type2type.dm @@ -70,19 +70,19 @@ /proc/list2text(list/ls, sep) if (ls.len <= 1) // Early-out code for empty or singleton lists. return ls.len ? ls[1] : "" - + var/l = ls.len // Made local for sanic speed. var/i = 0 // Incremented every time a list index is accessed. - + if (sep <> null) // Macros expand to long argument lists like so: sep, ls[++i], sep, ls[++i], sep, ls[++i], etc... #define S1 sep, ls[++i] #define S4 S1, S1, S1, S1 #define S16 S4, S4, S4, S4 #define S64 S16, S16, S16, S16 - + . = "[ls[++i]]" // Make sure the initial element is converted to text. - + // Having the small concatenations come before the large ones boosted speed by an average of at least 5%. if (l-1 & 0x01) // 'i' will always be 1 here. . = text("[][][]", ., S1) // Append 1 element if the remaining elements are not a multiple of 2. @@ -111,7 +111,7 @@ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64) - + #undef S64 #undef S16 #undef S4 @@ -122,9 +122,9 @@ #define S4 S1, S1, S1, S1 #define S16 S4, S4, S4, S4 #define S64 S16, S16, S16, S16 - + . = "[ls[++i]]" // Make sure the initial element is converted to text. - + if (l-1 & 0x01) // 'i' will always be 1 here. . += S1 // Append 1 element if the remaining elements are not a multiple of 2. if (l-i & 0x02) @@ -145,7 +145,7 @@ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64) - + #undef S64 #undef S16 #undef S4 @@ -165,11 +165,11 @@ proc/tg_list2text(list/list, glue=",") var/delim_len = length(delimiter) if (delim_len < 1) return list(text) - + . = list() var/last_found = 1 var/found - + do found = findtext(text, delimiter, last_found, 0) . += copytext(text, last_found, found) @@ -181,11 +181,11 @@ proc/tg_list2text(list/list, glue=",") var/delim_len = length(delimiter) if (delim_len < 1) return list(text) - + . = list() var/last_found = 1 var/found - + do found = findtextEx(text, delimiter, last_found, 0) . += copytext(text, last_found, found) @@ -325,3 +325,47 @@ proc/tg_list2text(list/list, glue=",") . = 0 else . = max(0, min(255, 138.5177312231 * log(temp - 10) - 305.0447927307)) + +// Very ugly, BYOND doesn't support unix time and rounding errors make it really hard to convert it to BYOND time. +// returns "YYYY-MM-DD" by default +/proc/unix2date(timestamp, seperator = "-") + if(timestamp < 0) + return 0 //Do not accept negative values + + var/const/dayInSeconds = 86400 //60secs*60mins*24hours + var/const/daysInYear = 365 //Non Leap Year + var/const/daysInLYear = daysInYear + 1//Leap year + var/days = round(timestamp / dayInSeconds) //Days passed since UNIX Epoc + var/year = 1970 //Unix Epoc begins 1970-01-01 + var/tmpDays = days + 1 //If passed (timestamp < dayInSeconds), it will return 0, so add 1 + var/monthsInDays = list() //Months will be in here ***Taken from the PHP source code*** + var/month = 1 //This will be the returned MONTH NUMBER. + var/day //This will be the returned day number. + + while(tmpDays > daysInYear) //Start adding years to 1970 + year++ + if(isLeap(year)) + tmpDays -= daysInLYear + else + tmpDays -= daysInYear + + if(isLeap(year)) //The year is a leap year + monthsInDays = list(-1,30,59,90,120,151,181,212,243,273,304,334) + else + monthsInDays = list(0,31,59,90,120,151,181,212,243,273,304,334) + + var/mDays = 0; + var/monthIndex = 0; + + for(var/m in monthsInDays) + monthIndex++ + if(tmpDays > m) + mDays = m + month = monthIndex + + day = tmpDays - mDays //Setup the date + + return "[year][seperator][((month < 10) ? "0[month]" : month)][seperator][((day < 10) ? "0[day]" : day)]" + +/proc/isLeap(y) + return ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0)) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index adaab0540a3..c7a12321eb4 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -95,6 +95,7 @@ var/list/gamemode_cache = list() var/banappeals var/wikiurl var/forumurl + var/githuburl //Alert level description var/alert_desc_green = "All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced." @@ -395,6 +396,9 @@ var/list/gamemode_cache = list() if ("forumurl") config.forumurl = value + if ("githuburl") + config.githuburl = value + if ("guest_jobban") config.guest_jobban = 1 diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm new file mode 100644 index 00000000000..da4192df257 --- /dev/null +++ b/code/datums/helper_datums/getrev.dm @@ -0,0 +1,39 @@ +var/global/datum/getrev/revdata = new() + +/datum/getrev + var/revision + var/date + var/showinfo + +/datum/getrev/New() + var/list/head_log = file2list(".git/logs/HEAD", "\n") + for(var/line=head_log.len, line>=1, line--) + if(head_log[line]) + var/list/last_entry = text2list(head_log[line], " ") + if(last_entry.len < 2) continue + revision = last_entry[2] + // Get date/time + if(last_entry.len >= 5) + var/unix_time = text2num(last_entry[5]) + if(unix_time) + date = unix2date(unix_time) + break + world.log << "Running revision:" + world.log << date + world.log << revision + return + +client/verb/showrevinfo() + set category = "OOC" + set name = "Show Server Revision" + set desc = "Check the current server code revision" + + if(revdata.revision) + src << "Server revision: [revdata.date]" + if(config.githuburl) + src << "[revdata.revision]" + else + src << revdata.revision + else + src << "Revision unknown" + return diff --git a/code/game/machinery/kitchen/smartfridge.dm b/code/game/machinery/kitchen/smartfridge.dm index 9bfa0e1c5dd..9016836274a 100644 --- a/code/game/machinery/kitchen/smartfridge.dm +++ b/code/game/machinery/kitchen/smartfridge.dm @@ -204,7 +204,7 @@ item_quants[O.name]++ else item_quants[O.name] = 1 - user.visible_message("[user] has added \the [O] to \the [src].", "You add \the [O] to \the [src].") + user.visible_message("[user] has added \the [O] to \the [src].", "You add \the [O] to \the [src].") nanomanager.update_uis(src) diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 1d585c9c894..76df8968edc 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -91,7 +91,7 @@ REAGENT SCANNER if (!(istype(usr, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") usr << "\red You don't have the dexterity to do this!" return - user.visible_message(" [user] has analyzed [M]'s vitals."," You have analyzed [M]'s vitals.") + user.visible_message(" [user] has analyzed [M]'s vitals."," You have analyzed [M]'s vitals.") if (!istype(M, /mob/living/carbon) || (ishuman(M) && (M:species.flags & IS_SYNTHETIC))) //these sensors are designed for organic life diff --git a/code/modules/clothing/spacesuits/rig/rig.dm b/code/modules/clothing/spacesuits/rig/rig.dm index 7cbd14cb21c..81df901b38b 100644 --- a/code/modules/clothing/spacesuits/rig/rig.dm +++ b/code/modules/clothing/spacesuits/rig/rig.dm @@ -20,7 +20,7 @@ armor = list(melee = 40, bullet = 5, laser = 20,energy = 5, bomb = 35, bio = 100, rad = 20) min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE max_heat_protection_temperature = SPACE_SUIT_MAX_HEAT_PROTECTION_TEMPERATURE - siemens_coefficient = 0.1 + siemens_coefficient = 0.2 permeability_coefficient = 0.1 unacidable = 1 diff --git a/code/modules/clothing/spacesuits/rig/suits/ert.dm b/code/modules/clothing/spacesuits/rig/suits/ert.dm index 70c21d51089..c46b019a4d2 100644 --- a/code/modules/clothing/spacesuits/rig/suits/ert.dm +++ b/code/modules/clothing/spacesuits/rig/suits/ert.dm @@ -29,8 +29,8 @@ desc = "A suit worn by the engineering division of a NanoTrasen Emergency Response Team. Has orange highlights. Armoured and space ready." suit_type = "ERT engineer" icon_state = "ert_engineer_rig" - - glove_type = /obj/item/clothing/gloves/rig/ert_engineer + armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 100, rad = 100) + siemens_coefficient = 0 initial_modules = list( /obj/item/rig_module/ai_container, @@ -39,10 +39,6 @@ /obj/item/rig_module/device/rcd ) -/obj/item/clothing/gloves/rig/ert_engineer - name = "insulated gauntlets" - siemens_coefficient = 0 - /obj/item/weapon/rig/ert/medical name = "ERT-M suit control module" desc = "A suit worn by the medical division of a NanoTrasen Emergency Response Team. Has white highlights. Armoured and space ready." diff --git a/code/modules/events/viral_infection.dm b/code/modules/events/viral_infection.dm index 639cea4d5e9..2eb6121f083 100644 --- a/code/modules/events/viral_infection.dm +++ b/code/modules/events/viral_infection.dm @@ -1,3 +1,5 @@ +/var/global/list/event_viruses = list() // so that event viruses are kept around for admin logs, rather than being GCed + datum/event/viral_infection var/list/viruses = list() @@ -40,10 +42,30 @@ datum/event/viral_infection/start() if(!candidates.len) return candidates = shuffle(candidates)//Incorporating Donkie's list shuffle + var/list/used_viruses = list() + var/list/used_candidates = list() severity = max(EVENT_LEVEL_MUNDANE, severity - 1) var/actual_severity = severity * rand(1, 3) while(actual_severity > 0 && candidates.len) var/datum/disease2/disease/D = pick(viruses) infect_mob(candidates[1], D.getcopy()) + used_candidates += candidates[1] candidates.Remove(candidates[1]) actual_severity-- + used_viruses |= D + + event_viruses |= used_viruses + var/list/used_viruses_links = list() + var/list/used_viruses_text = list() + for(var/datum/disease2/disease/D in used_viruses) + used_viruses_links += "[D.name()]" + used_viruses_text += D.name() + + var/list/used_candidates_links = list() + var/list/used_candidates_text = list() + for(var/mob/M in used_candidates) + used_candidates_links += key_name_admin(M) + used_candidates_text += key_name(M) + + log_admin("Virus event affecting [english_list(used_candidates_text)] started; Viruses: [english_list(used_viruses_text)]") + message_admins("Virus event affecting [english_list(used_candidates_links)] started; Viruses: [english_list(used_viruses_links)]") diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 79dc2cc657a..a38c6e6b9ac 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -1365,11 +1365,11 @@ var/obj/item/clothing/glasses/welding/O = glasses if(!O.up) found_welder = 1 - else if(istype(head, /obj/item/clothing/head/welding)) + if(!found_welder && istype(head, /obj/item/clothing/head/welding)) var/obj/item/clothing/head/welding/O = head if(!O.up) found_welder = 1 - else if(istype(back, /obj/item/weapon/rig)) + if(!found_welder && istype(back, /obj/item/weapon/rig)) var/obj/item/weapon/rig/O = back if(O.helmet && O.helmet == head && (O.helmet.body_parts_covered & EYES)) if((O.offline && O.offline_vision_restriction == 1) || (!O.offline && O.vision_restriction == 1)) diff --git a/code/modules/mob/typing_indicator.dm b/code/modules/mob/typing_indicator.dm index 203159f3c68..147edb1afe3 100644 --- a/code/modules/mob/typing_indicator.dm +++ b/code/modules/mob/typing_indicator.dm @@ -5,14 +5,17 @@ mob/var/typing mob/var/last_typed mob/var/last_typed_time -var/global/image/typing_indicator +mob/var/obj/effect/decal/typing_indicator /mob/proc/set_typing_indicator(var/state) if(!typing_indicator) - typing_indicator = image('icons/mob/talk.dmi',null,"typing") + typing_indicator = new + typing_indicator.icon = 'icons/mob/talk.dmi' + typing_indicator.icon_state = "typing" - if(client) + if(client && !stat) + typing_indicator.invisibility = invisibility if(client.prefs.toggles & SHOW_TYPING) overlays -= typing_indicator else diff --git a/code/modules/shuttles/shuttle_emergency.dm b/code/modules/shuttles/shuttle_emergency.dm index 5215400a4e1..ea572e8fb43 100644 --- a/code/modules/shuttles/shuttle_emergency.dm +++ b/code/modules/shuttles/shuttle_emergency.dm @@ -62,7 +62,11 @@ if (istype(user, /obj/machinery/computer/shuttle_control/emergency)) //if we were given a command by an emergency shuttle console if (emergency_shuttle.autopilot) emergency_shuttle.autopilot = 0 - world << "\blue Alert: The shuttle autopilot has been overridden. Launch sequence initiated!" + world << "Alert: The shuttle autopilot has been overridden. Launch sequence initiated!" + + if(usr) + log_admin("[key_name(usr)] has overridden the shuttle autopilot and activated launch sequence") + message_admins("[key_name_admin(usr)] has overridden the shuttle autopilot and activated launch sequence") ..(user) @@ -72,7 +76,11 @@ if (istype(user, /obj/machinery/computer/shuttle_control/emergency)) //if we were given a command by an emergency shuttle console if (emergency_shuttle.autopilot) emergency_shuttle.autopilot = 0 - world << "\blue Alert: The shuttle autopilot has been overridden. Bluespace drive engaged!" + world << "Alert: The shuttle autopilot has been overridden. Bluespace drive engaged!" + + if(usr) + log_admin("[key_name(usr)] has overridden the shuttle autopilot and forced immediate launch") + message_admins("[key_name_admin(usr)] has overridden the shuttle autopilot and forced immediate launch") ..(user) @@ -82,7 +90,11 @@ if (istype(user, /obj/machinery/computer/shuttle_control/emergency)) //if we were given a command by an emergency shuttle console if (emergency_shuttle.autopilot) emergency_shuttle.autopilot = 0 - world << "\blue Alert: The shuttle autopilot has been overridden. Launch sequence aborted!" + world << "Alert: The shuttle autopilot has been overridden. Launch sequence aborted!" + + if(usr) + log_admin("[key_name(usr)] has overridden the shuttle autopilot and cancelled launch sequence") + message_admins("[key_name_admin(usr)] has overridden the shuttle autopilot and cancelled launch sequence") ..(user) @@ -102,8 +114,8 @@ authorized = initial(authorized) //returns 1 if the ID was accepted and a new authorization was added, 0 otherwise -/obj/machinery/computer/shuttle_control/emergency/proc/read_authorization(var/ident) - if (!ident) +/obj/machinery/computer/shuttle_control/emergency/proc/read_authorization(var/obj/item/ident) + if (!ident || !istype(ident)) return 0 if (authorized.len >= req_authorizations) return 0 //don't need any more @@ -112,33 +124,35 @@ var/auth_name var/dna_hash - if(istype(ident, /obj/item/weapon/card/id)) - var/obj/item/weapon/card/id/ID = ident - access = ID.access - auth_name = "[ID.registered_name] ([ID.assignment])" - dna_hash = ID.dna_hash + var/obj/item/weapon/card/id/ID = ident.GetID() - if(istype(ident, /obj/item/device/pda)) - var/obj/item/device/pda/PDA = ident - access = PDA.id.access - auth_name = "[PDA.id.registered_name] ([PDA.id.assignment])" - dna_hash = PDA.id.dna_hash + if(!ID) + return + + access = ID.access + auth_name = "[ID.registered_name] ([ID.assignment])" + dna_hash = ID.dna_hash if (!access || !istype(access)) return 0 //not an ID if (dna_hash in authorized) - src.visible_message("[src] buzzes. That ID has already been scanned.") + src.visible_message("\The [src] buzzes. That ID has already been scanned.") return 0 if (!(access_heads in access)) - src.visible_message("[src] buzzes, rejecting [ident].") + src.visible_message("\The [src] buzzes, rejecting [ident].") return 0 - src.visible_message("[src] beeps as it scans [ident].") + src.visible_message("\The [src] beeps as it scans [ident].") authorized[dna_hash] = auth_name if (req_authorizations - authorized.len) - world << "\blue Alert: [req_authorizations - authorized.len] authorization\s needed to override the shuttle autopilot." + world << "Alert: [req_authorizations - authorized.len] authorization\s needed to override the shuttle autopilot." + + if(usr) + log_admin("[key_name(usr)] has inserted [ID] into the shuttle control computer - [req_authorizations - authorized.len] authorisation\s needed") + message_admins("[key_name_admin(usr)] has inserted [ID] into the shuttle control computer - [req_authorizations - authorized.len] authorisation\s needed") + return 1 @@ -146,7 +160,7 @@ /obj/machinery/computer/shuttle_control/emergency/attackby(obj/item/weapon/W as obj, mob/user as mob) if (istype(W, /obj/item/weapon/card/emag) && !emagged) - user << "\blue You short out the [src]'s authorization protocols." + user << "You short out \the [src]'s authorization protocols." emagged = 1 return diff --git a/config/example/config.txt b/config/example/config.txt index cc5af6a013b..7648a51a889 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -180,6 +180,9 @@ GUEST_BAN ## Wiki address # WIKIURL http://example.com +## GitHub address +# GITHUBURL https://github.com/example-user/example-repository + ## Ban appeals URL - usually for a forum or wherever people should go to contact your admins. # BANAPPEALS http://example.com diff --git a/html/changelogs/HarpyEagle-ERTERigFix.yml b/html/changelogs/HarpyEagle-ERTERigFix.yml new file mode 100644 index 00000000000..fa888cba462 --- /dev/null +++ b/html/changelogs/HarpyEagle-ERTERigFix.yml @@ -0,0 +1,18 @@ +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment + +author: HarpyEagle +delete-after: True + +changes: + - bugfix: "Fixes Engineer ERT gloves not being insulated." diff --git a/html/changelogs/PsiOmegaDelta-ServerRevision.yml b/html/changelogs/PsiOmegaDelta-ServerRevision.yml new file mode 100644 index 00000000000..56581748c1c --- /dev/null +++ b/html/changelogs/PsiOmegaDelta-ServerRevision.yml @@ -0,0 +1,5 @@ +author: PsiOmegaDelta +delete-after: True + +changes: + - rscadd: "You can now review the server revision date and hash by using the 'Show Server Revision' verb in the OOC category."