This commit is contained in:
Poojawa
2018-09-11 00:54:07 -05:00
parent 49467dbd72
commit 0e510e8c34
11 changed files with 224 additions and 221 deletions
+4 -1
View File
@@ -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
+41 -2
View File
@@ -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
+100 -12
View File
@@ -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)
. += "<a href='?priv_msg=[C.findStealthKey()]'>"
. += "Administrator"
else
if(include_link)
. += "<a href='?priv_msg=[ckey]'>"
. += key
if(!C)
. += "\[DC\]"
if(include_link)
. += "</a>"
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 (?, ?, ?))"
+13 -10
View File
@@ -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, "<span class='warning'>The new area must be completely airtight and not a part of a shuttle.</span>")
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
+1 -1
View File
@@ -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()
+5 -3
View File
@@ -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")
+1 -1
View File
@@ -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)
-95
View File
@@ -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 = "<font color='red'>has [what_done] [starget][(sobject||addition) ? " with ":""][sobject][addition][hp][sattackloc]</font>"
user.log_message(message, INDIVIDUAL_ATTACK_LOG)
if(is_mob_target)
var/message = "<font color='orange'>has been [what_done] by [ssource][(sobject||addition) ? " with ":""][sobject][addition][hp][sattackloc]</font>"
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
+11 -13
View File
@@ -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
+41 -1
View File
@@ -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 ? "<a href='?action=openLink&link=[url_encode(statspage)][GLOB.round_id]'>[GLOB.round_id]</a>" : GLOB.round_id
parts += "[GLOB.TAB]Round ID: <b>[info]</b>"
parts += "[GLOB.TAB]Shift Duration: <B>[DisplayTimeText(world.time - SSticker.round_start_time)]</B>"
parts += "[GLOB.TAB]Station Integrity: <B>[mode.station_was_nuked ? "<span class='redtext'>Destroyed</span>" : "[popcount["station_integrity"]]%"]</B>"
var/total_players = GLOB.joined_player_list.len
@@ -518,10 +522,20 @@
return objective_parts.Join("<br>")
/datum/controller/subsystem/ticker/proc/save_admin_data()
if(IsAdminAdvancedProcCall())
to_chat(usr, "<span class='admin prefix'>Admin rank DB Sync blocked: Advanced ProcCall detected.</span>")
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)
+7 -82
View File
@@ -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)
. += "<a href='?priv_msg=[C.findStealthKey()]'>"
. += "Administrator"
else
if(include_link)
. += "<a href='?priv_msg=[ckey]'>"
. += key
if(!C)
. += "\[DC\]"
if(include_link)
. += "</a>"
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)