diff --git a/code/__HELPERS/AStar.dm b/code/__HELPERS/AStar.dm
index c038e2e2e2..5e03d9b350 100644
--- a/code/__HELPERS/AStar.dm
+++ b/code/__HELPERS/AStar.dm
@@ -101,7 +101,10 @@ Actual Adjacent procs :
//sanitation
var/turf/end = get_turf(_end)
var/turf/start = get_turf(caller)
- if((!start)||(start.z != end.z)||(start == end)) //no pathfinding between z levels
+ if(!start || !end)
+ stack_trace("Invalid A* start or destination")
+ return 0
+ if( start.z != end.z || start == end ) //no pathfinding between z levels
return 0
if(maxnodes)
//if start turf is farther than maxnodes from end turf, no need to do anything
diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm
index 54dd2a982c..fed283adcd 100644
--- a/code/__HELPERS/_lists.dm
+++ b/code/__HELPERS/_lists.dm
@@ -20,6 +20,35 @@
#define LAZYLEN(L) length(L)
#define LAZYCLEARLIST(L) if(L) L.Cut()
#define SANITIZE_LIST(L) ( islist(L) ? L : list() )
+#define reverseList(L) reverseRange(L.Copy())
+
+// binary search sorted insert
+// IN: Object to be inserted
+// LIST: List to insert object into
+// TYPECONT: The typepath of the contents of the list
+// COMPARE: The variable on the objects to compare
+#define BINARY_INSERT(IN, LIST, TYPECONT, COMPARE) \
+ var/__BIN_CTTL = length(LIST);\
+ if(!__BIN_CTTL) {\
+ LIST += IN;\
+ } else {\
+ var/__BIN_LEFT = 1;\
+ var/__BIN_RIGHT = __BIN_CTTL;\
+ var/__BIN_MID = (__BIN_LEFT + __BIN_RIGHT) >> 1;\
+ var/##TYPECONT/__BIN_ITEM;\
+ while(__BIN_LEFT < __BIN_RIGHT) {\
+ __BIN_ITEM = LIST[__BIN_MID];\
+ if(__BIN_ITEM.##COMPARE <= IN.##COMPARE) {\
+ __BIN_LEFT = __BIN_MID + 1;\
+ } else {\
+ __BIN_RIGHT = __BIN_MID;\
+ };\
+ __BIN_MID = (__BIN_LEFT + __BIN_RIGHT) >> 1;\
+ };\
+ __BIN_ITEM = LIST[__BIN_MID];\
+ __BIN_MID = __BIN_ITEM.##COMPARE > IN.##COMPARE ? __BIN_MID : __BIN_MID + 1;\
+ LIST.Insert(__BIN_MID, IN);\
+ }
//Returns a list in plain english as a string
/proc/english_list(list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" )
@@ -460,8 +489,18 @@
return l
. = l.Copy()
for(var/i = 1 to l.len)
- if(islist(.[i]))
- .[i] = .(.[i])
+ var/key = .[i]
+ if(isnum(key))
+ // numbers cannot ever be associative keys
+ continue
+ var/value = .[key]
+ if(islist(value))
+ value = deepCopyList(value)
+ .[key] = value
+ if(islist(key))
+ key = deepCopyList(key)
+ .[i] = key
+ .[key] = value
//takes an input_key, as text, and the list of keys already used, outputting a replacement key in the format of "[input_key] ([number_of_duplicates])" if it finds a duplicate
//use this for lists of things that might have the same name, like mobs or objects, that you plan on giving to a player as input
diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm
index 92f7b21bb7..ac17df5773 100644
--- a/code/__HELPERS/_logging.dm
+++ b/code/__HELPERS/_logging.dm
@@ -44,6 +44,7 @@
WRITE_LOG(GLOB.world_game_log, "ADMINPRIVATE: [text]")
/proc/log_adminsay(text)
+ GLOB.admin_log.Add(text)
if (CONFIG_GET(flag/log_adminchat))
WRITE_LOG(GLOB.world_game_log, "ADMINPRIVATE: ASAY: [text]")
@@ -103,6 +104,10 @@
//reusing the PDA option because I really don't think news comments are worth a config option
WRITE_LOG(GLOB.world_pda_log, "COMMENT: [text]")
+/proc/log_telecomms(text)
+ if (CONFIG_GET(flag/log_telecomms))
+ WRITE_LOG(GLOB.world_telecomms_log, "TCOMMS: [text]")
+
/proc/log_chat(text)
if (CONFIG_GET(flag/log_pda))
//same thing here
@@ -134,7 +139,9 @@
/* Log to both DD and the logfile. */
/proc/log_world(text)
+#ifdef USE_CUSTOM_ERROR_HANDLER
WRITE_LOG(GLOB.world_runtime_log, text)
+#endif
SEND_TEXT(world.log, text)
/* Log to the logfile only. */
@@ -157,19 +164,100 @@
/* Helper procs for building detailed log lines */
-/proc/datum_info_line(datum/D)
- if(!istype(D))
- return
- if(!ismob(D))
- return "[D] ([D.type])"
- var/mob/M = D
- return "[M] ([M.ckey]) ([M.type])"
+/proc/key_name(whom, include_link = null, include_name = TRUE)
+ var/mob/M
+ var/client/C
+ var/key
+ var/ckey
+ var/fallback_name
-/proc/atom_loc_line(atom/A)
+ if(!whom)
+ return "*null*"
+ if(istype(whom, /client))
+ C = whom
+ M = C.mob
+ key = C.key
+ ckey = C.ckey
+ else if(ismob(whom))
+ M = whom
+ C = M.client
+ key = M.key
+ ckey = M.ckey
+ else if(istext(whom))
+ key = whom
+ ckey = ckey(whom)
+ C = GLOB.directory[ckey]
+ if(C)
+ M = C.mob
+ else if(istype(whom,/datum/mind))
+ var/datum/mind/mind = whom
+ key = mind.key
+ ckey = ckey(key)
+ if(mind.current)
+ M = mind.current
+ if(M.client)
+ C = M.client
+ else
+ fallback_name = mind.name
+ else // Catch-all cases if none of the types above match
+ var/swhom = null
+
+ if(istype(whom, /atom))
+ var/atom/A = whom
+ swhom = "[A.name]"
+ else if(istype(whom, /datum))
+ swhom = "[whom]"
+
+ if(!swhom)
+ swhom = "*invalid*"
+
+ return "\[[swhom]\]"
+
+ . = ""
+
+ if(!ckey)
+ include_link = FALSE
+
+ if(key)
+ if(C && C.holder && C.holder.fakekey && !include_name)
+ if(include_link)
+ . += ""
+ . += "Administrator"
+ else
+ if(include_link)
+ . += ""
+ . += key
+ if(!C)
+ . += "\[DC\]"
+
+ if(include_link)
+ . += ""
+ else
+ . += "*no key*"
+
+ if(include_name)
+ if(M)
+ if(M.real_name)
+ . += "/([M.real_name])"
+ else if(M.name)
+ . += "/([M.name])"
+ else if(fallback_name)
+ . += "/([fallback_name])"
+
+ return .
+
+/proc/key_name_admin(whom, include_name = TRUE)
+ return key_name(whom, TRUE, include_name)
+
+/proc/loc_name(atom/A)
if(!istype(A))
- return
- var/turf/T = get_turf(A)
+ return "(INVALID LOCATION)"
+
+ var/turf/T = A
+ if (!istype(T))
+ T = get_turf(A)
+
if(istype(T))
- return "[A.loc] [COORD(T)] ([A.loc.type])"
+ return "([AREACOORD(T)])"
else if(A.loc)
- return "[A.loc] (0, 0, 0) ([A.loc.type])"
+ return "(UNKNOWN (?, ?, ?))"
diff --git a/code/__HELPERS/areas.dm b/code/__HELPERS/areas.dm
index 3e9a26b261..f05bf6f3e1 100644
--- a/code/__HELPERS/areas.dm
+++ b/code/__HELPERS/areas.dm
@@ -3,7 +3,8 @@
// Gets an atmos isolated contained space
// Returns an associative list of turf|dirs pairs
// The dirs are connected turfs in the same space
-// break_if_found is a typecache of turf types to return false if found
+// break_if_found is a typecache of turf/area types to return false if found
+// Please keep this proc type agnostic. If you need to restrict it do it elsewhere or add an arg.
/proc/detect_room(turf/origin, list/break_if_found)
if(origin.blocks_air)
return list(origin)
@@ -13,10 +14,6 @@
var/list/found_turfs = list(origin)
while(found_turfs.len)
var/turf/sourceT = found_turfs[1]
- if(break_if_found[sourceT.type])
- return FALSE
- if (istype(sourceT.loc, /area/shuttle))
- return FALSE
found_turfs.Cut(1, 2)
var/dir_flags = checked_turfs[sourceT]
for(var/dir in GLOB.alldirs)
@@ -29,18 +26,24 @@
checked_turfs[checkT] |= turn(dir, 180)
.[sourceT] |= dir
.[checkT] |= turn(dir, 180)
+ if(break_if_found[checkT.type] || break_if_found[checkT.loc.type])
+ return FALSE
var/static/list/cardinal_cache = list("[NORTH]"=TRUE, "[EAST]"=TRUE, "[SOUTH]"=TRUE, "[WEST]"=TRUE)
if(!cardinal_cache["[dir]"] || checkT.blocks_air || !CANATMOSPASS(sourceT, checkT))
continue
found_turfs += checkT // Since checkT is connected, add it to the list to be processed
/proc/create_area(mob/creator)
- var/static/blacklisted_turfs = typecacheof(/turf/open/space)
- var/static/blacklisted_areas = typecacheof(list(
- /area/space,
+ // Passed into the above proc as list/break_if_found
+ var/static/area_or_turf_fail_types = typecacheof(list(
+ /turf/open/space,
/area/shuttle,
))
- var/list/turfs = detect_room(get_turf(creator), blacklisted_turfs)
+ // Ignore these areas and dont let people expand them. They can expand into them though
+ var/static/blacklisted_areas = typecacheof(list(
+ /area/space,
+ ))
+ var/list/turfs = detect_room(get_turf(creator), area_or_turf_fail_types)
if(!turfs)
to_chat(creator, "The new area must be completely airtight and not a part of a shuttle.")
return
@@ -50,7 +53,7 @@
var/list/areas = list("New Area" = /area)
for(var/i in 1 to turfs.len)
var/area/place = get_area(turfs[i])
- if(blacklisted_areas[place.type] || istype(place, /area/shuttle))
+ if(blacklisted_areas[place.type])
continue
if(!place.requires_power || place.noteleport || place.hidden)
continue // No expanding powerless rooms etc
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index 13f415823c..c590c844eb 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -350,7 +350,7 @@
/proc/flick_overlay(image/I, list/show_to, duration)
for(var/client/C in show_to)
C.images += I
- addtimer(CALLBACK(GLOBAL_PROC, /.proc/remove_images_from_clients, I, show_to), duration, TIMER_CLIENT_TIME)
+ addtimer(CALLBACK(GLOBAL_PROC, /proc/remove_images_from_clients, I, show_to), duration, TIMER_CLIENT_TIME)
/proc/flick_overlay_view(image/I, atom/target, duration) //wrapper for the above, flicks to everyone who can see the target atom
var/list/viewing = list()
diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm
index aed2e9c749..d2cb3baa6a 100644
--- a/code/__HELPERS/icons.dm
+++ b/code/__HELPERS/icons.dm
@@ -1027,15 +1027,17 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
return 0
//For creating consistent icons for human looking simple animals
-/proc/get_flat_human_icon(icon_id, datum/job/J, datum/preferences/prefs, dummy_key, showDirs = GLOB.cardinals)
+/proc/get_flat_human_icon(icon_id, datum/job/J, datum/preferences/prefs, dummy_key, showDirs = GLOB.cardinals, outfit_override = null)
var/static/list/humanoid_icon_cache = list()
if(!icon_id || !humanoid_icon_cache[icon_id])
var/mob/living/carbon/human/dummy/body = generate_or_wait_for_human_dummy(dummy_key)
if(prefs)
- prefs.copy_to(body)
+ prefs.copy_to(body,TRUE,FALSE)
if(J)
- J.equip(body, TRUE, FALSE)
+ J.equip(body, TRUE, FALSE, outfit_override = outfit_override)
+ else if (outfit_override)
+ body.equipOutfit(outfit_override,visualsOnly = TRUE)
var/icon/out_icon = icon('icons/effects/effects.dmi', "nothing")
diff --git a/code/__HELPERS/level_traits.dm b/code/__HELPERS/level_traits.dm
index b73a0aa83d..55ee069321 100644
--- a/code/__HELPERS/level_traits.dm
+++ b/code/__HELPERS/level_traits.dm
@@ -14,4 +14,4 @@
#define is_away_level(z) SSmapping.level_trait(z, ZTRAIT_AWAY)
// If true, the singularity cannot strip away asteroid turf on this Z
-#define is_planet_level(z) (GLOB.z_is_planet["z"])
+#define is_planet_level(z) SSmapping.level_trait(z, ZTRAIT_PLANET)
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index 51f0a28bd2..7d46553be1 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -266,65 +266,6 @@ GLOBAL_LIST_EMPTY(species_list)
else
return "unknown"
-/*
-Proc for attack log creation, because really why not
-1 argument is the actor
-2 argument is the target of action
-3 is the description of action(like punched, throwed, or any other verb)
-4 is the tool with which the action was made(usually item) 4 and 5 are very similar(5 have "by " before it, that it) and are separated just to keep things in a bit more in order
-5 is additional information, anything that needs to be added
-*/
-
-/proc/add_logs(mob/user, mob/target, what_done, object=null, addition=null)
- var/turf/attack_location = get_turf(target)
-
- var/is_mob_user = user && ismob(user)
- var/is_mob_target = target && ismob(target)
-
- var/mob/living/living_target
-
- if(target && isliving(target))
- living_target = target
-
- var/hp =" "
- if(living_target)
- hp = " (NEWHP: [living_target.health]) "
-
- var/starget = "NON-EXISTENT SUBJECT"
- if(target)
- if(is_mob_target && target.key)
- starget = "[target.name]([target.key])"
- else
- starget = "[target.name]"
-
- var/ssource = "NON-EXISTENT USER" //How!?
- if(user)
- if(is_mob_user && user.key)
- ssource = "[user.name]([user.key])"
- else
- ssource = "[user.name]"
-
- var/sobject = ""
- if(object)
- sobject = "[object]"
- if(addition)
- addition = " [addition]"
-
- var/sattackloc = ""
- if(attack_location)
- sattackloc = "([attack_location.x],[attack_location.y],[attack_location.z])"
-
- if(is_mob_user)
- var/message = "has [what_done] [starget][(sobject||addition) ? " with ":""][sobject][addition][hp][sattackloc]"
- user.log_message(message, INDIVIDUAL_ATTACK_LOG)
-
- if(is_mob_target)
- var/message = "has been [what_done] by [ssource][(sobject||addition) ? " with ":""][sobject][addition][hp][sattackloc]"
- target.log_message(message, INDIVIDUAL_ATTACK_LOG)
-
- log_attack("[ssource] [what_done] [starget][(sobject||addition) ? " with ":""][sobject][addition][hp][sattackloc]")
-
-
/proc/do_mob(mob/user , mob/target, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks = null)
if(!user || !target)
return 0
@@ -573,42 +514,6 @@ Proc for attack log creation, because really why not
else
to_chat(M, message)
-
-/proc/log_talk(mob/user,message,logtype)
- var/turf/say_turf = get_turf(user)
-
- var/sayloc = ""
- if(say_turf)
- sayloc = "([say_turf.x],[say_turf.y],[say_turf.z])"
-
-
- var/logmessage = "[message] [sayloc]"
-
- switch(logtype)
-
- if(LOGDSAY)
- log_dsay(logmessage)
- if(LOGSAY)
- log_say(logmessage)
- if(LOGWHISPER)
- log_whisper(logmessage)
- if(LOGEMOTE)
- log_emote(logmessage)
- if(LOGPDA)
- log_pda(logmessage)
- if(LOGCHAT)
- log_chat(logmessage)
- if(LOGCOMMENT)
- log_comment(logmessage)
- if(LOGASAY)
- log_adminsay(logmessage)
- if(LOGOOC)
- log_ooc(logmessage)
- log_looc(logmessage) //CITADEL EDIT, logging LOOC because why not
- else
- warning("Invalid speech logging type detected. [logtype]. Defaulting to say")
- log_say(logmessage)
-
//Used in chemical_mob_spawn. Generates a random mob based on a given gold_core_spawnable value.
/proc/create_random_mob(spawn_location, mob_class = HOSTILE_SPAWN)
var/static/list/mob_spawn_meancritters = list() // list of possible hostile mobs
diff --git a/code/__HELPERS/radiation.dm b/code/__HELPERS/radiation.dm
index 93dcdb4b0e..a570ab43ba 100644
--- a/code/__HELPERS/radiation.dm
+++ b/code/__HELPERS/radiation.dm
@@ -1,26 +1,24 @@
// A special GetAllContents that doesn't search past things with rad insulation
-// The protection var only protects the things inside from being affected.
-// The protecting object itself will get returned still.
+// Components which return COMPONENT_BLOCK_RADIATION prevent further searching into that object's contents. The object itself will get returned still.
// The ignore list makes those objects never return at all
/proc/get_rad_contents(atom/location)
+ var/static/list/ignored_things = typecacheof(list(
+ /mob/dead,
+ /mob/camera,
+ /obj/effect,
+ /obj/docking_port,
+ /atom/movable/lighting_object,
+ /obj/item/projectile,
+ ))
var/list/processing_list = list(location)
. = list()
while(processing_list.len)
- var/static/list/ignored_things = typecacheof(list(
- /mob/dead,
- /mob/camera,
- /obj/effect,
- /obj/docking_port,
- /atom/movable/lighting_object,
- /obj/item/projectile
- ))
var/atom/thing = processing_list[1]
processing_list -= thing
if(ignored_things[thing.type])
continue
. += thing
- var/datum/component/rad_insulation/insulation = thing.GetComponent(/datum/component/rad_insulation)
- if(insulation && insulation.protects)
+ if(SEND_SIGNAL(thing, COMSIG_ATOM_RAD_PROBE) & COMPONENT_BLOCK_RADIATION)
continue
processing_list += thing.contents
@@ -43,5 +41,5 @@
log = TRUE
if(log)
var/turf/_source_T = isturf(source) ? source : get_turf(source)
- log_game("Radiation pulse with intensity: [intensity] and range modifier: [range_modifier] in [AREACOORD(_source_T)] ")
+ log_game("Radiation pulse with intensity: [intensity] and range modifier: [range_modifier] in [loc_name(_source_T)] ")
return TRUE
\ No newline at end of file
diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm
index e86c57ac24..84d4a40135 100644
--- a/code/__HELPERS/roundend.dm
+++ b/code/__HELPERS/roundend.dm
@@ -194,7 +194,7 @@
send2irc("Server", "Round just ended.")
- if(length(CONFIG_GET(keyed_string_list/cross_server)))
+ if(length(CONFIG_GET(keyed_list/cross_server)))
send_news_report()
CHECK_TICK
@@ -271,6 +271,10 @@
var/list/parts = list()
var/station_evacuated = EMERGENCY_ESCAPED_OR_ENDGAMED
+ if(GLOB.round_id)
+ var/statspage = CONFIG_GET(string/roundstatsurl)
+ var/info = statspage ? "[GLOB.round_id]" : GLOB.round_id
+ parts += "[GLOB.TAB]Round ID: [info]"
parts += "[GLOB.TAB]Shift Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]"
parts += "[GLOB.TAB]Station Integrity: [mode.station_was_nuked ? "Destroyed" : "[popcount["station_integrity"]]%"]"
var/total_players = GLOB.joined_player_list.len
@@ -518,10 +522,20 @@
return objective_parts.Join("
")
/datum/controller/subsystem/ticker/proc/save_admin_data()
+ if(IsAdminAdvancedProcCall())
+ to_chat(usr, "Admin rank DB Sync blocked: Advanced ProcCall detected.")
+ return
if(CONFIG_GET(flag/admin_legacy_system)) //we're already using legacy system so there's nothing to save
return
else if(load_admins(TRUE)) //returns true if there was a database failure and the backup was loaded from
return
+ sync_ranks_with_db()
+ var/list/sql_admins = list()
+ for(var/datum/admins/A in GLOB.protected_admins)
+ var/sql_ckey = sanitizeSQL(A.owner.ckey)
+ var/sql_rank = sanitizeSQL(A.rank.name)
+ sql_admins = list(list("ckey" = "'[sql_ckey]'", "rank" = "'[sql_rank]'"))
+ SSdbcore.MassInsert(format_table_name("admin"), sql_admins, duplicate_key = TRUE)
var/datum/DBQuery/query_admin_rank_update = SSdbcore.NewQuery("UPDATE [format_table_name("player")] p INNER JOIN [format_table_name("admin")] a ON p.ckey = a.ckey SET p.lastadminrank = a.rank")
query_admin_rank_update.Execute()
qdel(query_admin_rank_update)
@@ -543,3 +557,29 @@
file_data["admins"]["[i]"] = A.rank.name
fdel(json_file)
WRITE_FILE(json_file, json_encode(file_data))
+
+/datum/controller/subsystem/ticker/proc/update_everything_flag_in_db()
+ for(var/datum/admin_rank/R in GLOB.admin_ranks)
+ var/list/flags = list()
+ if(R.include_rights == R_EVERYTHING)
+ flags += "flags"
+ if(R.exclude_rights == R_EVERYTHING)
+ flags += "exclude_flags"
+ if(R.can_edit_rights == R_EVERYTHING)
+ flags += "can_edit_flags"
+ if(!flags.len)
+ continue
+ var/sql_rank = sanitizeSQL(R.name)
+ var/flags_to_check = flags.Join(" != [R_EVERYTHING] AND ") + " != [R_EVERYTHING]"
+ var/datum/DBQuery/query_check_everything_ranks = SSdbcore.NewQuery("SELECT flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")] WHERE rank = '[sql_rank]' AND ([flags_to_check])")
+ if(!query_check_everything_ranks.Execute())
+ qdel(query_check_everything_ranks)
+ return
+ if(query_check_everything_ranks.NextRow()) //no row is returned if the rank already has the correct flag value
+ var/flags_to_update = flags.Join(" = [R_EVERYTHING], ") + " = [R_EVERYTHING]"
+ var/datum/DBQuery/query_update_everything_ranks = SSdbcore.NewQuery("UPDATE [format_table_name("admin_ranks")] SET [flags_to_update] WHERE rank = '[sql_rank]'")
+ if(!query_update_everything_ranks.Execute())
+ qdel(query_update_everything_ranks)
+ return
+ qdel(query_update_everything_ranks)
+ qdel(query_check_everything_ranks)
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index f7aac6123e..be20918485 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -372,80 +372,6 @@ Turf and target are separate in case you want to teleport some distance from a t
return "[round(units * 0.000001, 0.001)] MJ"
return "[round(units * 0.000000001, 0.0001)] GJ"
-/proc/key_name(whom, include_link = null, include_name = 1)
- var/mob/M
- var/client/C
- var/key
- var/ckey
- var/fallback_name
-
- if(!whom)
- return "*null*"
- if(istype(whom, /client))
- C = whom
- M = C.mob
- key = C.key
- ckey = C.ckey
- else if(ismob(whom))
- M = whom
- C = M.client
- key = M.key
- ckey = M.ckey
- else if(istext(whom))
- key = whom
- ckey = ckey(whom)
- C = GLOB.directory[ckey]
- if(C)
- M = C.mob
- else if(istype(whom,/datum/mind))
- var/datum/mind/mind = whom
- key = mind.key
- ckey = ckey(key)
- if(mind.current)
- M = mind.current
- if(M.client)
- C = M.client
- else
- fallback_name = mind.name
- else
- return "*invalid*"
-
- . = ""
-
- if(!ckey)
- include_link = 0
-
- if(key)
- if(C && C.holder && C.holder.fakekey && !include_name)
- if(include_link)
- . += ""
- . += "Administrator"
- else
- if(include_link)
- . += ""
- . += key
- if(!C)
- . += "\[DC\]"
-
- if(include_link)
- . += ""
- else
- . += "*no key*"
-
- if(include_name)
- if(M)
- if(M.real_name)
- . += "/([M.real_name])"
- else if(M.name)
- . += "/([M.name])"
- else if(fallback_name)
- . += "/([fallback_name])"
-
- return .
-
-/proc/key_name_admin(whom, include_name = 1)
- return key_name(whom, 1, include_name)
-
/proc/get_mob_by_ckey(key)
if(!key)
return
@@ -651,14 +577,9 @@ Turf and target are separate in case you want to teleport some distance from a t
//Takes: Area type as a text string from a variable.
//Returns: Instance for the area in the world.
/proc/get_area_instance_from_text(areatext)
- var/areainstance = null
if(istext(areatext))
areatext = text2path(areatext)
- for(var/V in GLOB.sortedAreas)
- var/area/A = V
- if(A.type == areatext)
- areainstance = V
- return areainstance
+ return GLOB.areas_by_type[areatext]
//Takes: Area type as text string or as typepath OR an instance of the area.
//Returns: A list of all areas of that type in the world.
@@ -1349,7 +1270,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
var/ready_to_die = FALSE
/mob/dview/Initialize() //Properly prevents this mob from gaining huds or joining any global lists
- return
+ return INITIALIZE_HINT_NORMAL
/mob/dview/Destroy(force = FALSE)
if(!ready_to_die)
@@ -1538,6 +1459,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
/obj/item/reagent_containers/food/snacks/soup,
/obj/item/reagent_containers/food/snacks/grown,
/obj/item/reagent_containers/food/snacks/grown/mushroom,
+ /obj/item/reagent_containers/food/snacks/grown/nettle, // base type
/obj/item/reagent_containers/food/snacks/deepfryholder
)
blocked |= typesof(/obj/item/reagent_containers/food/snacks/customizable)
@@ -1545,7 +1467,10 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
return pick(typesof(/obj/item/reagent_containers/food/snacks) - blocked)
/proc/get_random_drink()
- return pick(subtypesof(/obj/item/reagent_containers/food/drinks))
+ var/list/blocked = list(/obj/item/reagent_containers/food/drinks/soda_cans,
+ /obj/item/reagent_containers/food/drinks/bottle
+ )
+ return pick(subtypesof(/obj/item/reagent_containers/food/drinks) - blocked)
//For these two procs refs MUST be ref = TRUE format like typecaches!
/proc/weakref_filter_list(list/things, list/refs)