mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-22 19:47:22 +01:00
Merge remote-tracking branch 'refs/remotes/ParadiseSS13/master' into wizloadouts
This commit is contained in:
@@ -31,7 +31,7 @@
|
||||
|
||||
/datum/proc/vv_get_var(var_name)
|
||||
switch(var_name)
|
||||
if("attack_log", "debug_log")
|
||||
if("attack_log_old", "debug_log")
|
||||
return debug_variable(var_name, vars[var_name], 0, src, sanitize = FALSE)
|
||||
if("vars")
|
||||
return debug_variable(var_name, list(), 0, src)
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/datum/log_record
|
||||
var/log_type // Type of log
|
||||
var/raw_time // When did this happen?
|
||||
var/what // What happened
|
||||
var/who // Who did it
|
||||
var/target // Who/what was targeted (can be a string)
|
||||
var/turf/where // Where did it happen
|
||||
|
||||
/datum/log_record/New(_log_type, _who, _what, _target, _where, _raw_time)
|
||||
log_type = _log_type
|
||||
|
||||
who = get_subject_text(_who)
|
||||
what = _what
|
||||
target = get_subject_text(_target)
|
||||
if(!_where)
|
||||
_where = get_turf(_who)
|
||||
where = _where
|
||||
if(!_raw_time)
|
||||
_raw_time = world.time
|
||||
raw_time = _raw_time
|
||||
|
||||
/datum/log_record/proc/get_subject_text(subject)
|
||||
if(ismob(subject) || isclient(subject) || istype(subject, /datum/mind))
|
||||
return key_name_admin(subject)
|
||||
if(isatom(subject))
|
||||
var/atom/A = subject
|
||||
return A.name
|
||||
if(istype(subject, /datum))
|
||||
var/datum/D = subject
|
||||
return D.type
|
||||
return subject
|
||||
|
||||
/proc/compare_log_record(datum/log_record/A, datum/log_record/B)
|
||||
var/time_diff = A.raw_time - B.raw_time
|
||||
if(!time_diff) // Same time
|
||||
return cmp_text_asc(A.log_type, B.log_type)
|
||||
return time_diff
|
||||
@@ -0,0 +1,232 @@
|
||||
#define ALL_LOGS list(ATTACK_LOG, DEFENSE_LOG, CONVERSION_LOG, SAY_LOG, EMOTE_LOG, MISC_LOG)
|
||||
|
||||
/datum/log_viewer
|
||||
var/time_from = 0
|
||||
var/time_to = 4 HOURS // 4 Hours should be enough. INFINITY would screw the UI up
|
||||
var/list/selected_mobs = list() // The mobs in question
|
||||
var/list/selected_log_types = list() // The log types being searched for
|
||||
|
||||
var/list/log_records = list() // Found and sorted records
|
||||
|
||||
/datum/log_viewer/proc/clear_all()
|
||||
selected_mobs.Cut()
|
||||
selected_log_types.Cut()
|
||||
time_from = initial(time_from)
|
||||
time_to = initial(time_to)
|
||||
log_records.Cut()
|
||||
return
|
||||
|
||||
/datum/log_viewer/proc/search()
|
||||
log_records.Cut() // Empty the old results
|
||||
var/list/invalid_mobs = list()
|
||||
for(var/i in selected_mobs)
|
||||
var/mob/M = i
|
||||
if(!M || QDELETED(M))
|
||||
invalid_mobs |= M
|
||||
continue
|
||||
for(var/log_type in selected_log_types)
|
||||
var/list/logs = M.logs[log_type]
|
||||
var/len_logs = length(logs)
|
||||
if(len_logs)
|
||||
var/start_index = get_earliest_log_index(logs)
|
||||
if(!start_index) // No log found that matches the starting time criteria
|
||||
continue
|
||||
var/end_index = get_latest_log_index(logs)
|
||||
if(!end_index) // No log found that matches the end time criteria
|
||||
continue
|
||||
log_records.Add(logs.Copy(start_index, end_index + 1))
|
||||
|
||||
if(invalid_mobs.len)
|
||||
to_chat(usr, "<span class='warning'>The search criteria contained invalid mobs. They have been removed from the criteria.</span>")
|
||||
for(var/i in invalid_mobs)
|
||||
selected_mobs -= i // Cleanup
|
||||
|
||||
log_records = sortTim(log_records, /proc/compare_log_record)
|
||||
|
||||
/** Binary search like implementation to find the earliest log
|
||||
* Returns the index of the earliest log using the time_from value for the given list of logs.
|
||||
* It will return 0 if no log after time_from is found
|
||||
*/
|
||||
/datum/log_viewer/proc/get_earliest_log_index(list/logs)
|
||||
if(!time_from)
|
||||
return 1
|
||||
var/start = 1
|
||||
var/end = length(logs)
|
||||
var/mid
|
||||
do
|
||||
mid = round_down((end + start) / 2)
|
||||
var/datum/log_record/L = logs[mid]
|
||||
if(L.raw_time >= time_from)
|
||||
end = mid
|
||||
else
|
||||
start = mid
|
||||
while(end - start > 1)
|
||||
var/datum/log_record/L = logs[end]
|
||||
if(L.raw_time >= time_from) // Check if there is atleast one valid log
|
||||
return end
|
||||
return 0
|
||||
|
||||
/** Binary search like implementation to find the latest log
|
||||
* Returns the index of the latest log using the time_to value (1 second is added to prevent rounding weirdness) for the given list of logs.
|
||||
* It will return 0 if no log before time_to + 10 is found
|
||||
*/
|
||||
/datum/log_viewer/proc/get_latest_log_index(list/logs)
|
||||
if(world.time < time_to)
|
||||
return length(logs)
|
||||
|
||||
var/end = length(logs)
|
||||
var/start = 1
|
||||
var/mid
|
||||
var/max_time = time_to + 10
|
||||
do
|
||||
mid = round((end + start) / 2 + 0.5)
|
||||
var/datum/log_record/L = logs[mid]
|
||||
if(L.raw_time >= max_time)
|
||||
end = mid
|
||||
else
|
||||
start = mid
|
||||
while(end - start > 1)
|
||||
var/datum/log_record/L = logs[start]
|
||||
if(L.raw_time < max_time) // Check if there is atleast one valid log
|
||||
return start
|
||||
return 0
|
||||
|
||||
/datum/log_viewer/proc/add_mob(mob/user, mob/M)
|
||||
if(!M || !user)
|
||||
return
|
||||
selected_mobs |= M
|
||||
|
||||
show_ui(user)
|
||||
|
||||
/datum/log_viewer/proc/show_ui(mob/user)
|
||||
var/all_log_types = ALL_LOGS
|
||||
var/trStyleTop = "border-top:2px solid; border-bottom:2px solid; padding-top: 5px; padding-bottom: 5px;"
|
||||
var/trStyle = "border-top:1px solid; border-bottom:1px solid; padding-top: 5px; padding-bottom: 5px;"
|
||||
var/dat
|
||||
dat += "<head><style>.adminticket{border:2px solid} td{border:1px solid grey;} th{border:1px solid grey;} span{float:left;width:150px;}</style></head>"
|
||||
dat += "<div style='height:15vh'>"
|
||||
dat += "<span>Time Search Range:</span> <a href='?src=[UID()];start_time=1'>[gameTimestamp(wtime = time_from)]</a>"
|
||||
dat += " To: <a href='?src=[UID()];end_time=1'>[gameTimestamp(wtime = time_to)]</a>"
|
||||
dat += "<BR>"
|
||||
|
||||
dat += "<span>Mobs being used:</span>"
|
||||
for(var/i in selected_mobs)
|
||||
var/mob/M = i
|
||||
dat += "<a href='?src=[UID()];remove_mob=\ref[M]'>[M.name]</a>"
|
||||
dat += "<a href='?src=[UID()];add_mob=1'>Add Mob</a>"
|
||||
dat += "<a href='?src=[UID()];clear_mobs=1'>Clear All Mobs</a>"
|
||||
dat += "<BR>"
|
||||
|
||||
dat += "<span>Log Types:</span>"
|
||||
for(var/i in all_log_types)
|
||||
var/log_type = i
|
||||
var/enabled = (log_type in selected_log_types)
|
||||
var/text
|
||||
var/style
|
||||
if(enabled)
|
||||
text = "<b>[log_type]</b>"
|
||||
style = "background: [get_logtype_color(i)]"
|
||||
else
|
||||
text = log_type
|
||||
|
||||
dat += "<a href='?src=[UID()];toggle_log_type=[log_type]' style='[style]'>[text]</a>"
|
||||
|
||||
dat += "<BR>"
|
||||
dat += "<a href='?src=[UID()];clear_all=1'>Clear All Settings</a>"
|
||||
dat += "<a href='?src=[UID()];search=1'>Search</a>"
|
||||
dat += "</div>"
|
||||
|
||||
// Search results
|
||||
var/tdStyleTime = "width:80px; text-align:center;"
|
||||
var/tdStyleType = "width:80px; text-align:center;"
|
||||
var/tdStyleWho = "width:300px; text-align:center;"
|
||||
var/tdStyleWhere = "width:150px; text-align:center;"
|
||||
dat += "<div style='overflow-y: auto; max-height:76vh;'>"
|
||||
dat += "<table style='width:100%; border: 1px solid;'>"
|
||||
dat += "<tr style='[trStyleTop]'><th style='[tdStyleTime]'>When</th><th style='[tdStyleType]'>Type</th><th style='[tdStyleWho]'>Who</th><th>What</th><th>Target</th><th style='[tdStyleWhere]'>Where</th></tr>"
|
||||
for(var/i in log_records)
|
||||
var/datum/log_record/L = i
|
||||
var/time = gameTimestamp(wtime = L.raw_time - 9.99) // The time rounds up for some reason. Will result in weird filtering results
|
||||
|
||||
dat +="<tr style='[trStyle]'><td style='[tdStyleTime]'>[time]</td><td style='[tdStyleType]background: [get_logtype_color(L.log_type)]'>[L.log_type]</td>\
|
||||
<td style='[tdStyleWho]'>[L.who]</td><td style='background: [get_logtype_color(L.log_type)];'>[L.what]</td>\
|
||||
<td style='[tdStyleWho]'>[L.target]</td><td style='[tdStyleWhere]'>[ADMIN_COORDJMP(L.where)]</td></tr>"
|
||||
|
||||
dat += "</table>"
|
||||
dat += "</div>"
|
||||
|
||||
var/datum/browser/popup = new(user, "Log viewer", "Log viewer", 1400, 600)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/datum/log_viewer/Topic(href, href_list)
|
||||
if(href_list["start_time"])
|
||||
var/input = input(usr, "hh:mm:ss", "Start time", "00:00:00") as text|null
|
||||
if(!input)
|
||||
return
|
||||
var/res = timeStampToNum(input)
|
||||
if(res < 0)
|
||||
to_chat(usr, "<span class='warning'>'[input]' is an invalid input value.</span>")
|
||||
return
|
||||
time_from = res
|
||||
show_ui(usr)
|
||||
return
|
||||
if(href_list["end_time"])
|
||||
var/input = input(usr, "hh:mm:ss", "End time", "04:00:00") as text|null
|
||||
if(!input)
|
||||
return
|
||||
var/res = timeStampToNum(input)
|
||||
if(res < 0)
|
||||
to_chat(usr, "<span class='warning'>'[input]' is an invalid input value.</span>")
|
||||
return
|
||||
time_to = res
|
||||
|
||||
show_ui(usr)
|
||||
return
|
||||
if(href_list["search"])
|
||||
search(usr)
|
||||
show_ui(usr)
|
||||
return
|
||||
if(href_list["clear_all"])
|
||||
clear_all(usr)
|
||||
show_ui(usr)
|
||||
return
|
||||
if(href_list["clear_mobs"])
|
||||
selected_mobs.Cut()
|
||||
show_ui(usr)
|
||||
return
|
||||
if(href_list["add_mob"])
|
||||
var/list/mobs = getpois(TRUE, TRUE)
|
||||
var/datum/async_input/A = input_autocomplete_async(usr, "Please, select a mob: ", mobs)
|
||||
A.on_close(CALLBACK(src, .proc/add_mob, usr))
|
||||
return
|
||||
if(href_list["remove_mob"])
|
||||
var/mob/M = locate(href_list["remove_mob"])
|
||||
if(M)
|
||||
selected_mobs -= M
|
||||
show_ui(usr)
|
||||
return
|
||||
if(href_list["toggle_log_type"])
|
||||
var/log_type = href_list["toggle_log_type"]
|
||||
if(log_type in selected_log_types)
|
||||
selected_log_types -= log_type
|
||||
else
|
||||
selected_log_types += log_type
|
||||
show_ui(usr)
|
||||
return
|
||||
|
||||
/datum/log_viewer/proc/get_logtype_color(log_type)
|
||||
switch(log_type)
|
||||
if(ATTACK_LOG)
|
||||
return "darkred"
|
||||
if(DEFENSE_LOG)
|
||||
return "chocolate"
|
||||
if(CONVERSION_LOG)
|
||||
return "indigo"
|
||||
if(SAY_LOG)
|
||||
return "teal"
|
||||
if(EMOTE_LOG)
|
||||
return "deepskyblue"
|
||||
if(MISC_LOG)
|
||||
return "gray"
|
||||
return "slategray"
|
||||
@@ -105,6 +105,14 @@
|
||||
current.mind = null
|
||||
leave_all_huds() //leave all the huds in the old body, so it won't get huds if somebody else enters it
|
||||
|
||||
for(var/log_type in current.logs) // Copy the old logs
|
||||
var/list/logs = current.logs[log_type]
|
||||
if(new_character.logs[log_type])
|
||||
new_character.logs[log_type] += logs.Copy() // Append the old ones
|
||||
new_character.logs[log_type] = sortTim(new_character.logs[log_type], /proc/compare_log_record) // Sort them on time
|
||||
else
|
||||
new_character.logs[log_type] = logs.Copy() // Just copy them
|
||||
|
||||
SSnanoui.user_transferred(current, new_character)
|
||||
|
||||
if(new_character.mind) //remove any mind currently in our new body's mind variable
|
||||
|
||||
@@ -241,7 +241,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
|
||||
before_cast(targets)
|
||||
invocation()
|
||||
if(user && user.ckey)
|
||||
user.create_attack_log("<font color='red'>[key_name(user)] cast the spell [name].</font>")
|
||||
add_attack_logs(user, null, "cast the spell [name]")
|
||||
spawn(0)
|
||||
if(charge_type == "recharge" && recharge)
|
||||
start_recharge()
|
||||
|
||||
@@ -141,6 +141,7 @@
|
||||
else
|
||||
user.mind.AddSpell(S)
|
||||
to_chat(user, "<span class='notice'>You flip through the pages. Your understanding of the boundaries of reality increases. You can cast [spellname]!</span>")
|
||||
user.create_log(MISC_LOG, "learned the spell [spellname] ([S])")
|
||||
user.create_attack_log("<font color='orange'>[key_name(user)] learned the spell [spellname] ([S]).</font>")
|
||||
onlearned(user)
|
||||
|
||||
@@ -164,4 +165,4 @@
|
||||
/obj/item/spellbook/oneuse/mime/greaterwall
|
||||
spell = /obj/effect/proc_holder/spell/targeted/forcewall/mime
|
||||
spellname = "Invisible Greater Wall"
|
||||
desc = "It contains illustrations of the great walls of human history."
|
||||
desc = "It contains illustrations of the great walls of human history."
|
||||
Reference in New Issue
Block a user