mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-30 07:27:57 +01:00
Adds a new logging system and a logging view (#13115)
* Super early initial commit * Why do I keep comitting this * in between * In between * Sort fix. Transfer fix. HTML and more * Scrolling + define values change * Search fixes and time input fixes * Minor tweaks. Fuel tank inclusion. Fixes * derp * Extra logging to fuel tank * minor stuff * add the message to admins for fueltanks * Don't keep mob/atom references + fixes * line fixes? * Review improvements * pois comment
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
#define ATTACK_LOG "Attack"
|
||||
#define DEFENSE_LOG "Defense"
|
||||
#define CONVERSION_LOG "Conversion"
|
||||
#define SAY_LOG "Say"
|
||||
#define EMOTE_LOG "Emote"
|
||||
#define MISC_LOG "Misc"
|
||||
+22
-13
@@ -274,7 +274,7 @@ Proc for attack log creation, because really why not
|
||||
This is always put in the attack log.
|
||||
*/
|
||||
|
||||
/proc/add_attack_logs(mob/user, mob/target, what_done, custom_level)
|
||||
/proc/add_attack_logs(atom/user, target, what_done, custom_level)
|
||||
if(islist(target)) // Multi-victim adding
|
||||
var/list/targets = target
|
||||
for(var/mob/M in targets)
|
||||
@@ -282,24 +282,33 @@ This is always put in the attack log.
|
||||
return
|
||||
|
||||
var/user_str = key_name_log(user) + COORD(user)
|
||||
var/target_str = key_name_log(target) + COORD(target)
|
||||
|
||||
if(istype(user))
|
||||
user.create_attack_log("<font color='red'>Attacked [target_str]: [what_done]</font>")
|
||||
if(istype(target))
|
||||
target.create_attack_log("<font color='orange'>Attacked by [user_str]: [what_done]</font>")
|
||||
var/target_str
|
||||
if(isatom(target))
|
||||
var/atom/AT = target
|
||||
target_str = key_name_log(AT) + COORD(AT)
|
||||
else
|
||||
target_str = target
|
||||
var/mob/MU = user
|
||||
var/mob/MT = target
|
||||
if(istype(MU))
|
||||
MU.create_log(ATTACK_LOG, what_done, target, get_turf(user))
|
||||
MU.create_attack_log("<font color='red'>Attacked [target_str]: [what_done]</font>")
|
||||
if(istype(MT))
|
||||
MT.create_log(DEFENSE_LOG, what_done, user, get_turf(MT))
|
||||
MT.create_attack_log("<font color='orange'>Attacked by [user_str]: [what_done]</font>")
|
||||
log_attack(user_str, target_str, what_done)
|
||||
|
||||
var/loglevel = ATKLOG_MOST
|
||||
if(!isnull(custom_level))
|
||||
loglevel = custom_level
|
||||
else if(istype(target))
|
||||
if(istype(user) && !user.ckey && !target.ckey) // Attacks between NPCs are only shown to admins with ATKLOG_ALL
|
||||
loglevel = ATKLOG_ALL
|
||||
else if(!user.ckey || !target.ckey || (user.ckey == target.ckey)) // Player v NPC combat is de-prioritized. Also no self-harm, nobody cares
|
||||
loglevel = ATKLOG_ALMOSTALL
|
||||
else if(istype(MT))
|
||||
if(istype(MU))
|
||||
if(!MU.ckey && !MT.ckey) // Attacks between NPCs are only shown to admins with ATKLOG_ALL
|
||||
loglevel = ATKLOG_ALL
|
||||
else if(!MU.ckey || !MT.ckey || (MU.ckey == MT.ckey)) // Player v NPC combat is de-prioritized. Also no self-harm, nobody cares
|
||||
loglevel = ATKLOG_ALMOSTALL
|
||||
else
|
||||
var/area/A = get_area(target)
|
||||
var/area/A = get_area(MT)
|
||||
if(A && A.hide_attacklogs)
|
||||
loglevel = ATKLOG_ALMOSTALL
|
||||
if(isLivingSSD(target)) // Attacks on SSDs are shown to admins with any log level except ATKLOG_NONE. Overrides custom level
|
||||
|
||||
+15
-1
@@ -50,10 +50,24 @@
|
||||
return "[date_portion]T[time_portion]"
|
||||
|
||||
/proc/gameTimestamp(format = "hh:mm:ss", wtime=null)
|
||||
if(!wtime)
|
||||
if(wtime == null)
|
||||
wtime = world.time
|
||||
return time2text(wtime - GLOB.timezoneOffset, format)
|
||||
|
||||
// max hh:mm:ss supported
|
||||
/proc/timeStampToNum(timestamp)
|
||||
var/list/splits = text2numlist(timestamp, ":")
|
||||
. = 0
|
||||
var/split_len = length(splits)
|
||||
for(var/i = 1 to length(splits))
|
||||
switch(split_len - i)
|
||||
if(2)
|
||||
. += splits[i] HOURS
|
||||
if(1)
|
||||
. += splits[i] MINUTES
|
||||
if(0)
|
||||
. += splits[i] SECONDS
|
||||
|
||||
/* This is used for displaying the "station time" equivelent of a world.time value
|
||||
Calling it with no args will give you the current time, but you can specify a world.time-based value as an argument
|
||||
- You can use this, for example, to do "This will expire at [station_time_at(world.time + 500)]" to display a "station time" expiration date
|
||||
|
||||
@@ -1895,8 +1895,15 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
|
||||
|
||||
#undef DELTA_CALC
|
||||
|
||||
// This proc gets a list of all "points of interest" (poi's) that can be used by admins to track valuable mobs or atoms (such as the nuke disk).
|
||||
/proc/getpois(mobs_only=0,skip_mindless=0)
|
||||
/*
|
||||
* This proc gets a list of all "points of interest" (poi's) that can be used by admins to track valuable mobs or atoms (such as the nuke disk).
|
||||
* @param mobs_only if set to TRUE it won't include locations to the returned list
|
||||
* @param skip_mindless if set to TRUE it will skip mindless mobs
|
||||
* @param force_include_bots if set to TRUE it will include bots even if skip_mindless is set to TRUE
|
||||
* @param force_include_cameras if set to TRUE it will include camera eyes even if skip_mindless is set to TRUE
|
||||
* @return returns a list with the found points of interest
|
||||
*/
|
||||
/proc/getpois(mobs_only = FALSE, skip_mindless = FALSE, force_include_bots = FALSE, force_include_cameras = FALSE)
|
||||
var/list/mobs = sortmobs()
|
||||
var/list/names = list()
|
||||
var/list/pois = list()
|
||||
@@ -1904,7 +1911,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
|
||||
|
||||
for(var/mob/M in mobs)
|
||||
if(skip_mindless && (!M.mind && !M.ckey))
|
||||
if(!isbot(M) && !istype(M, /mob/camera/))
|
||||
if(!(force_include_bots && isbot(M)) && !(force_include_cameras && istype(M, /mob/camera)))
|
||||
continue
|
||||
if(M.client && M.client.holder && M.client.holder.fakekey) //stealthmins
|
||||
continue
|
||||
|
||||
@@ -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."
|
||||
@@ -189,6 +189,7 @@ GLOBAL_LIST_EMPTY(all_cults)
|
||||
C.Grant(cult_mind.current)
|
||||
SEND_SOUND(cult_mind.current, 'sound/ambience/antag/bloodcult.ogg')
|
||||
cult_mind.current.create_attack_log("<span class='danger'>Has been converted to the cult!</span>")
|
||||
cult_mind.current.create_log(CONVERSION_LOG, "converted to the cult")
|
||||
if(jobban_isbanned(cult_mind.current, ROLE_CULTIST) || jobban_isbanned(cult_mind.current, ROLE_SYNDICATE))
|
||||
replace_jobbanned_player(cult_mind.current, ROLE_CULTIST)
|
||||
update_cult_icons_added(cult_mind)
|
||||
|
||||
@@ -267,6 +267,7 @@
|
||||
SSticker.mode.abductors -= abductor_mind
|
||||
abductor_mind.special_role = null
|
||||
abductor_mind.current.create_attack_log("<span class='danger'>No longer abductor</span>")
|
||||
abductor_mind.current.create_log(CONVERSION_LOG, "No longer abductor")
|
||||
if(issilicon(abductor_mind.current))
|
||||
to_chat(abductor_mind.current, "<span class='userdanger'>You have been turned into a robot! You are no longer an abductor.</span>")
|
||||
else
|
||||
@@ -281,4 +282,4 @@
|
||||
/datum/game_mode/proc/update_abductor_icons_removed(datum/mind/alien_mind)
|
||||
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_ABDUCTOR]
|
||||
hud.leave_hud(alien_mind.current)
|
||||
set_antag_hud(alien_mind.current, null)
|
||||
set_antag_hud(alien_mind.current, null)
|
||||
@@ -68,6 +68,7 @@ proc/issyndicate(mob/living/M as mob)
|
||||
for(var/datum/objective/nuclear/O in operative_mind.objectives)
|
||||
operative_mind.objectives -= O
|
||||
operative_mind.current.create_attack_log("<span class='danger'>No longer nuclear operative</span>")
|
||||
operative_mind.current.create_log(CONVERSION_LOG, "No longer nuclear operative")
|
||||
if(issilicon(operative_mind.current))
|
||||
to_chat(operative_mind.current, "<span class='userdanger'>You have been turned into a robot! You are no longer a Syndicate operative.</span>")
|
||||
else
|
||||
|
||||
@@ -244,6 +244,7 @@
|
||||
rev_mind.current.Stun(5)
|
||||
to_chat(rev_mind.current, "<span class='danger'><FONT size = 3> You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill the heads to win the revolution!</FONT></span>")
|
||||
rev_mind.current.create_attack_log("<font color='red'>Has been converted to the revolution!</font>")
|
||||
rev_mind.current.create_log(CONVERSION_LOG, "converted to the revolution")
|
||||
rev_mind.special_role = SPECIAL_ROLE_REV
|
||||
update_rev_icons_added(rev_mind)
|
||||
if(jobban_isbanned(rev_mind.current, ROLE_REV) || jobban_isbanned(rev_mind.current, ROLE_SYNDICATE))
|
||||
@@ -262,7 +263,7 @@
|
||||
revolutionaries -= rev_mind
|
||||
rev_mind.special_role = null
|
||||
rev_mind.current.create_attack_log("<font color='red'>Has renounced the revolution!</font>")
|
||||
|
||||
rev_mind.current.create_log(CONVERSION_LOG, "renounced the revolution")
|
||||
if(beingborged)
|
||||
to_chat(rev_mind.current, "<span class='danger'><FONT size = 3>The frame's firmware detects and deletes your neural reprogramming! You remember nothing[remove_head ? "." : " but the name of the one who flashed you."]</FONT></span>")
|
||||
message_admins("[key_name_admin(rev_mind.current)] [ADMIN_QUE(rev_mind.current,"?")] ([ADMIN_FLW(rev_mind.current,"FLW")]) has been borged while being a [remove_head ? "leader" : " member"] of the revolution.")
|
||||
|
||||
@@ -158,6 +158,7 @@ Made by Xhuis
|
||||
new_thrall_mind.special_role = SPECIAL_ROLE_SHADOWLING_THRALL
|
||||
update_shadow_icons_added(new_thrall_mind)
|
||||
new_thrall_mind.current.create_attack_log("<span class='danger'>Became a thrall</span>")
|
||||
new_thrall_mind.current.create_log(CONVERSION_LOG, "Became a thrall")
|
||||
new_thrall_mind.current.add_language("Shadowling Hivemind")
|
||||
new_thrall_mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/lesser_shadow_walk(null))
|
||||
new_thrall_mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadow_vision/thrall(null))
|
||||
@@ -179,6 +180,7 @@ Made by Xhuis
|
||||
return 0 //If there is no mind, the mind isn't a thrall, or the mind's mob isn't alive, return
|
||||
shadowling_thralls.Remove(thrall_mind)
|
||||
thrall_mind.current.create_attack_log("<span class='danger'>Dethralled</span>")
|
||||
thrall_mind.current.create_log(CONVERSION_LOG, "Dethralled")
|
||||
thrall_mind.special_role = null
|
||||
update_shadow_icons_removed(thrall_mind)
|
||||
for(var/obj/effect/proc_holder/spell/S in thrall_mind.spell_list)
|
||||
@@ -236,6 +238,7 @@ Made by Xhuis
|
||||
update_shadow_icons_removed(ling_mind)
|
||||
shadows.Remove(ling_mind)
|
||||
ling_mind.current.create_attack_log("<span class='danger'>Deshadowlinged</span>")
|
||||
ling_mind.current.create_log(CONVERSION_LOG, "Deshadowlinged")
|
||||
ling_mind.special_role = null
|
||||
for(var/obj/effect/proc_holder/spell/S in ling_mind.spell_list)
|
||||
ling_mind.RemoveSpell(S)
|
||||
|
||||
@@ -348,6 +348,7 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
SSticker.mode.vampires -= vampire_mind
|
||||
vampire_mind.special_role = null
|
||||
vampire_mind.current.create_attack_log("<span class='danger'>De-vampired</span>")
|
||||
vampire_mind.current.create_log(CONVERSION_LOG, "De-vampired")
|
||||
if(vampire_mind.vampire)
|
||||
vampire_mind.vampire.remove_vampire_powers()
|
||||
QDEL_NULL(vampire_mind.vampire)
|
||||
|
||||
@@ -109,6 +109,7 @@ GLOBAL_VAR_INIT(summon_magic_triggered, FALSE)
|
||||
|
||||
H.mind.add_antag_datum(/datum/antagonist/survivalist/guns)
|
||||
H.create_attack_log("<font color='red'>was made into a survivalist, and trusts no one!</font>")
|
||||
H.create_log(CONVERSION_LOG, "was made into a survivalist")
|
||||
|
||||
var/gun_type = pick(GLOB.summoned_guns)
|
||||
var/obj/item/gun/G = new gun_type(get_turf(H))
|
||||
@@ -130,6 +131,7 @@ GLOBAL_VAR_INIT(summon_magic_triggered, FALSE)
|
||||
|
||||
H.mind.add_antag_datum(/datum/antagonist/survivalist/magic)
|
||||
H.create_attack_log("<font color='red'>was made into a survivalist, and trusts no one!</font>")
|
||||
H.create_log(CONVERSION_LOG, "was made into a survivalist")
|
||||
|
||||
var/magic_type = pick(GLOB.summoned_magic)
|
||||
var/lucky = FALSE
|
||||
@@ -166,4 +168,4 @@ GLOBAL_VAR_INIT(summon_magic_triggered, FALSE)
|
||||
if(summon_type == SUMMON_MAGIC)
|
||||
give_magic(H)
|
||||
else
|
||||
give_guns(H)
|
||||
give_guns(H)
|
||||
@@ -69,9 +69,6 @@
|
||||
to_chat(user, "<span class='cultlarge'>\"Come now, do not capture your fellow's soul.\"</span>")
|
||||
return ..()
|
||||
|
||||
M.create_attack_log("<font color='orange'>Has had their soul captured with [src.name] by [key_name(user)]</font>")
|
||||
user.create_attack_log("<font color='red'>Used the [src.name] to capture the soul of [key_name(M)]</font>")
|
||||
|
||||
if(optional)
|
||||
if(!M.ckey)
|
||||
to_chat(user, "<span class='warning'>They have no soul!</span>")
|
||||
@@ -353,7 +350,7 @@
|
||||
|
||||
/obj/item/soulstone/proc/get_shade_type()
|
||||
return /mob/living/simple_animal/shade/cult
|
||||
|
||||
|
||||
/obj/item/soulstone/anybody/get_shade_type()
|
||||
return /mob/living/simple_animal/shade
|
||||
|
||||
|
||||
@@ -837,6 +837,7 @@
|
||||
else
|
||||
user.mind.AddSpell(S)
|
||||
to_chat(user, "<span class='notice'>you rapidly read through the arcane book. Suddenly you realize you understand [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)
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
SSticker.mode.wizards -= wizard_mind
|
||||
wizard_mind.special_role = null
|
||||
wizard_mind.current.create_attack_log("<span class='danger'>De-wizarded</span>")
|
||||
wizard_mind.current.create_log(CONVERSION_LOG, "De-wizarded")
|
||||
wizard_mind.current.spellremove(wizard_mind.current)
|
||||
wizard_mind.current.faction = list("Station")
|
||||
if(issilicon(wizard_mind.current))
|
||||
|
||||
@@ -276,6 +276,7 @@ About the new airlock wires panel:
|
||||
if(usr)
|
||||
shockedby += text("\[[time_stamp()]\] - [usr](ckey:[usr.ckey])")
|
||||
usr.create_attack_log("<font color='red'>Electrified the [name] at [x] [y] [z]</font>")
|
||||
add_attack_logs(usr, src, "Electrified")
|
||||
else
|
||||
shockedby += text("\[[time_stamp()]\] - EMP)")
|
||||
message = "The door is now electrified [duration == -1 ? "permanently" : "for [duration] second\s"]."
|
||||
@@ -763,6 +764,7 @@ About the new airlock wires panel:
|
||||
else if(activate) //electrify door for 30 seconds
|
||||
shockedby += text("\[[time_stamp()]\][usr](ckey:[usr.ckey])")
|
||||
usr.create_attack_log("<font color='red'>Electrified the [name] at [x] [y] [z]</font>")
|
||||
add_attack_logs(usr, src, "Electrified")
|
||||
to_chat(usr, "The door is now electrified for thirty seconds.")
|
||||
electrify(30)
|
||||
if("electrify_permanently")
|
||||
@@ -774,6 +776,7 @@ About the new airlock wires panel:
|
||||
else if(activate)
|
||||
shockedby += text("\[[time_stamp()]\][usr](ckey:[usr.ckey])")
|
||||
usr.create_attack_log("<font color='red'>Electrified the [name] at [x] [y] [z]</font>")
|
||||
add_attack_logs(usr, src, "Electrified")
|
||||
to_chat(usr, "The door is now electrified.")
|
||||
electrify(-1)
|
||||
if("open")
|
||||
|
||||
@@ -559,6 +559,7 @@
|
||||
animal_damage = user.obj_damage
|
||||
animal_damage = min(animal_damage, 20*user.environment_smash)
|
||||
user.create_attack_log("<font color='red'>attacked [name]</font>")
|
||||
add_attack_logs(user, src, "Attacked")
|
||||
attack_generic(user, animal_damage, user.melee_damage_type, "melee", play_soundeffect)
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -138,6 +138,7 @@
|
||||
|
||||
log_admin("[key_name(user)] EMPd a camera with a laser pointer")
|
||||
user.create_attack_log("[key_name(user)] EMPd a camera with a laser pointer")
|
||||
add_attack_logs(user, C, "EMPd with [src]")
|
||||
else
|
||||
outmsg = "<span class='info'>You missed the lens of [C] with [src].</span>"
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ GLOBAL_LIST_INIT(admin_verbs_admin, list(
|
||||
/client/proc/cmd_admin_subtle_message, /*send an message to somebody as a 'voice in their head'*/
|
||||
/client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/
|
||||
/client/proc/cmd_admin_check_contents, /*displays the contents of an instance*/
|
||||
/client/proc/cmd_admin_open_logging_view,
|
||||
/client/proc/getserverlogs, /*allows us to fetch server logs (diary) for other days*/
|
||||
/client/proc/jumptocoord, /*we ghost and jump to a coordinate*/
|
||||
/client/proc/Getmob, /*teleports a mob to our location*/
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
GLOBAL_LIST_INIT(open_logging_views, list())
|
||||
|
||||
/client/proc/cmd_admin_open_logging_view()
|
||||
set category = "Admin"
|
||||
set name = "Open Logging View"
|
||||
set desc = "Opens the detailed logging viewer"
|
||||
|
||||
if(!GLOB.open_logging_views[usr.client.ckey])
|
||||
GLOB.open_logging_views[usr.client.ckey] = new /datum/log_viewer()
|
||||
GLOB.open_logging_views[usr.client.ckey].show_ui(usr)
|
||||
@@ -885,7 +885,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
return
|
||||
|
||||
to_chat(usr, text("<span class='danger'>Attack Log for []</span>", mob))
|
||||
for(var/t in M.attack_log)
|
||||
for(var/t in M.attack_log_old)
|
||||
to_chat(usr, t)
|
||||
feedback_add_details("admin_verb","ATTL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
@@ -285,6 +285,7 @@
|
||||
|
||||
else //this looks ugly but it's better than a copy-pasted startgibbing proc override
|
||||
occupant.create_attack_log("Was gibbed by <b>an autogibber (\the [src])</b>")
|
||||
add_attack_logs(src, occupant, "gibbed")
|
||||
|
||||
occupant.emote("scream")
|
||||
playsound(get_turf(src), 'sound/goonstation/effects/gib.ogg', 50, 1)
|
||||
|
||||
@@ -53,7 +53,8 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
|
||||
var/turf/T
|
||||
if(ismob(body))
|
||||
T = get_turf(body) //Where is the body located?
|
||||
attack_log = body.attack_log //preserve our attack logs by copying them to our ghost
|
||||
attack_log_old = body.attack_log_old //preserve our attack logs by copying them to our ghost
|
||||
logs = body.logs.Copy()
|
||||
|
||||
var/mutable_appearance/MA = copy_appearance(body)
|
||||
if(body.mind && body.mind.name)
|
||||
@@ -431,7 +432,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
set name = "Orbit" // "Haunt"
|
||||
set desc = "Follow and orbit a mob."
|
||||
|
||||
var/list/mobs = getpois(skip_mindless=1)
|
||||
var/list/mobs = getpois(FALSE, TRUE, TRUE, TRUE)
|
||||
var/datum/async_input/A = input_autocomplete_async(usr, "Please, select a mob: ", mobs)
|
||||
A.on_close(CALLBACK(src, .proc/ManualFollow))
|
||||
|
||||
@@ -506,7 +507,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
set desc = "Teleport to a mob"
|
||||
|
||||
if(isobserver(usr)) //Make sure they're an observer!
|
||||
var/list/dest = getpois(mobs_only=1) //Fill list, prompt user with list
|
||||
var/list/dest = getpois(mobs_only=TRUE) //Fill list, prompt user with list
|
||||
var/datum/async_input/A = input_autocomplete_async(usr, "Enter a mob name: ", dest)
|
||||
A.on_close(CALLBACK(src, .proc/jump_to_mob))
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
var/mob/living/L = src
|
||||
L.say_log += "EMOTE: [input]" //say log too so it is easier on admins instead of having to merge the two with timestamps etc
|
||||
L.emote_log += input //emote only log if an admin wants to search just for emotes they don't have to sift through the say
|
||||
create_log(EMOTE_LOG, input) // TODO after #13047: Include the channel
|
||||
// Hearing gasp and such every five seconds is not good emotes were not global for a reason.
|
||||
// Maybe some people are okay with that.
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
|
||||
@@ -247,6 +247,7 @@
|
||||
set hidden = 1
|
||||
if(InCritical())
|
||||
create_attack_log("[src] has ["succumbed to death"] with [round(health, 0.1)] points of health!")
|
||||
create_log(MISC_LOG, "has succumbed to death with [round(health, 0.1)] points of health")
|
||||
adjustOxyLoss(health - HEALTH_THRESHOLD_DEAD)
|
||||
// super check for weird mobs, including ones that adjust hp
|
||||
// we don't want to go overboard and gib them, though
|
||||
|
||||
@@ -276,6 +276,7 @@ proc/get_radio_key_from_channel(var/channel)
|
||||
|
||||
//Log of what we've said, plain message, no spans or junk
|
||||
say_log += message
|
||||
create_log(SAY_LOG, message) // TODO after #13047: Include the channel
|
||||
log_say(message, src)
|
||||
return 1
|
||||
|
||||
@@ -361,6 +362,7 @@ proc/get_radio_key_from_channel(var/channel)
|
||||
|
||||
say_log += "whisper: [message]"
|
||||
log_whisper(message, src)
|
||||
create_log(SAY_LOG, "WHISPER: [message]")
|
||||
var/message_range = 1
|
||||
var/eavesdropping_range = 2
|
||||
var/watching_range = 5
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
to_chat(ghost, "<span class='ghostalert'>Your cyborg shell has been repaired, re-enter if you want to continue!</span> (Verbs -> Ghost -> Re-enter corpse)")
|
||||
ghost << sound('sound/effects/genetics.ogg')
|
||||
create_attack_log("revived, trigger reason: [reason]")
|
||||
create_log(MISC_LOG, "revived, trigger reason: [reason]")
|
||||
// diag_hud_set_status()
|
||||
// diag_hud_set_health()
|
||||
// update_health_hud()
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
else if(stat == UNCONSCIOUS)
|
||||
return 0
|
||||
create_attack_log("<font color='red'>Fallen unconscious at [atom_loc_line(get_turf(src))]</font>")
|
||||
add_attack_logs(src, null, "Fallen unconscious")
|
||||
log_game("[key_name(src)] fell unconscious at [atom_loc_line(get_turf(src))]")
|
||||
stat = UNCONSCIOUS
|
||||
if(updating)
|
||||
@@ -22,6 +23,7 @@
|
||||
else if(stat == CONSCIOUS)
|
||||
return 0
|
||||
create_attack_log("<font color='red'>Woken up at [atom_loc_line(get_turf(src))]</font>")
|
||||
add_attack_logs(src, null, "Woken up")
|
||||
log_game("[key_name(src)] woke up at [atom_loc_line(get_turf(src))]")
|
||||
stat = CONSCIOUS
|
||||
if(updating)
|
||||
@@ -45,6 +47,7 @@
|
||||
if(!can_be_revived())
|
||||
return 0
|
||||
create_attack_log("<font color='red'>Came back to life at [atom_loc_line(get_turf(src))]</font>")
|
||||
add_attack_logs(src, null, "Came back to life")
|
||||
log_game("[key_name(src)] came back to life at [atom_loc_line(get_turf(src))]")
|
||||
stat = CONSCIOUS
|
||||
GLOB.dead_mob_list -= src
|
||||
@@ -73,4 +76,4 @@
|
||||
return 1
|
||||
|
||||
/mob/living/proc/check_death_method()
|
||||
return TRUE
|
||||
return TRUE
|
||||
@@ -5,6 +5,7 @@
|
||||
computer_id = client.computer_id
|
||||
log_access_in(client)
|
||||
create_attack_log("<font color='red'>Logged in at [atom_loc_line(get_turf(src))]</font>")
|
||||
create_log(MISC_LOG, "Logged in")
|
||||
if(config.log_access)
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(M == src) continue
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
GLOB.player_list -= src
|
||||
log_access_out(src)
|
||||
create_attack_log("<font color='red'>Logged out at [atom_loc_line(get_turf(src))]</font>")
|
||||
create_log(MISC_LOG, "Logged out")
|
||||
// `holder` is nil'd out by now, so we check the `admin_datums` array directly
|
||||
//Only report this stuff if we are currently playing.
|
||||
if(GLOB.admin_datums[ckey] && SSticker && SSticker.current_state == GAME_STATE_PLAYING)
|
||||
|
||||
+10
-3
@@ -22,6 +22,7 @@
|
||||
for(var/datum/alternate_appearance/AA in viewing_alternate_appearances)
|
||||
AA.viewers -= src
|
||||
viewing_alternate_appearances = null
|
||||
logs.Cut()
|
||||
..()
|
||||
return QDEL_HINT_HARDDEL
|
||||
|
||||
@@ -1257,14 +1258,20 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
|
||||
return list() //must return list or IGNORE_ACCESS
|
||||
|
||||
/mob/proc/create_attack_log(text, collapse = TRUE)
|
||||
LAZYINITLIST(attack_log)
|
||||
create_log_in_list(attack_log, text, collapse, last_log)
|
||||
LAZYINITLIST(attack_log_old)
|
||||
create_log_in_list(attack_log_old, text, collapse, last_log)
|
||||
last_log = world.timeofday
|
||||
|
||||
/mob/proc/create_debug_log(text, collapse = TRUE)
|
||||
LAZYINITLIST(debug_log)
|
||||
create_log_in_list(debug_log, text, collapse, world.timeofday)
|
||||
|
||||
/mob/proc/create_log(log_type, what, target = null, turf/where = get_turf(src))
|
||||
LAZYINITLIST(logs[log_type])
|
||||
var/list/log_list = logs[log_type]
|
||||
var/datum/log_record/record = new(log_type, src, what, target, where, world.time)
|
||||
log_list.Add(record)
|
||||
|
||||
/proc/create_log_in_list(list/target, text, collapse = TRUE, last_log)//forgive me code gods for this shitcode proc
|
||||
//this proc enables lovely stuff like an attack log that looks like this: "[18:20:29-18:20:45]21x John Smith attacked Andrew Jackson with a crowbar."
|
||||
//That makes the logs easier to read, but because all of this is stored in strings, weird things have to be used to get it all out.
|
||||
@@ -1406,4 +1413,4 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
|
||||
|
||||
///Force set the mob nutrition
|
||||
/mob/proc/set_nutrition(change)
|
||||
nutrition = max(0, change)
|
||||
nutrition = max(0, change)
|
||||
@@ -33,8 +33,11 @@
|
||||
var/computer_id = null
|
||||
var/lastattacker = null
|
||||
var/lastattacked = null
|
||||
var/list/attack_log = list( )
|
||||
var/list/attack_log_old = list( )
|
||||
var/list/debug_log = null
|
||||
|
||||
var/list/logs = list() // Logs for each log type defined in __DEFINES/logs.dm
|
||||
|
||||
var/last_log = 0
|
||||
var/obj/machinery/machine = null
|
||||
var/other_mobs = null
|
||||
@@ -208,4 +211,4 @@
|
||||
var/list/tkgrabbed_objects = list() // Assoc list of items to TK grabs
|
||||
|
||||
var/forced_look = null // This can either be a numerical direction or a soft object reference (UID). It makes the mob always face towards the selected thing.
|
||||
var/registered_z
|
||||
var/registered_z
|
||||
@@ -51,6 +51,7 @@
|
||||
user.visible_message("<span class='danger'>[user] zaps [user.p_them()]self with [src].</span>")
|
||||
playsound(user, fire_sound, 50, 1)
|
||||
user.create_attack_log("<b>[key_name(user)]</b> zapped [user.p_them()]self with a <b>[src]</b>")
|
||||
add_attack_logs(null, user, "zapped [user.p_them()]self with a [src]")
|
||||
|
||||
/////////////////////////////////////
|
||||
//WAND OF DEATH
|
||||
|
||||
@@ -263,12 +263,14 @@
|
||||
return
|
||||
|
||||
M.create_attack_log("<font color='orange'>[key_name(M)] became [new_mob.real_name].</font>")
|
||||
new_mob.attack_log = M.attack_log
|
||||
add_attack_logs(null, M, "became [new_mob.real_name]")
|
||||
|
||||
new_mob.a_intent = INTENT_HARM
|
||||
if(M.mind)
|
||||
M.mind.transfer_to(new_mob)
|
||||
else
|
||||
new_mob.attack_log_old = M.attack_log_old.Copy()
|
||||
new_mob.logs = M.logs.Copy()
|
||||
new_mob.key = M.key
|
||||
|
||||
to_chat(new_mob, "<B>Your form morphs into that of a [randomize].</B>")
|
||||
@@ -344,4 +346,4 @@
|
||||
to_chat(target, "<span class='notice'>You get splatted by [src].</span>")
|
||||
M.Weaken(slip_weaken)
|
||||
M.Stun(slip_stun)
|
||||
. = ..()
|
||||
. = ..()
|
||||
@@ -16,7 +16,7 @@
|
||||
. = ..()
|
||||
if(. && obj_integrity > 0)
|
||||
if(tank_volume && (damage_flag == "bullet" || damage_flag == "laser"))
|
||||
boom()
|
||||
boom(FALSE, TRUE)
|
||||
|
||||
/obj/structure/reagent_dispensers/attackby(obj/item/I, mob/user, params)
|
||||
if(I.is_refillable())
|
||||
@@ -43,7 +43,7 @@
|
||||
/obj/structure/reagent_dispensers/deconstruct(disassembled = TRUE)
|
||||
if(!(flags & NODECONSTRUCT))
|
||||
if(!disassembled)
|
||||
boom()
|
||||
boom(FALSE, TRUE)
|
||||
else
|
||||
qdel(src)
|
||||
|
||||
@@ -85,15 +85,19 @@
|
||||
if(!QDELETED(src)) //wasn't deleted by the projectile's effects.
|
||||
if(!P.nodamage && ((P.damage_type == BURN) || (P.damage_type == BRUTE)))
|
||||
message_admins("[key_name_admin(P.firer)] triggered a fueltank explosion with [P.name] at [COORD(loc)] ")
|
||||
add_attack_logs(P.firer, src, "shot with [P.name]")
|
||||
log_game("[key_name(P.firer)] triggered a fueltank explosion with [P.name] at [COORD(loc)]")
|
||||
investigate_log("[key_name(P.firer)] triggered a fueltank explosion with [P.name] at [COORD(loc)]", INVESTIGATE_BOMB)
|
||||
boom()
|
||||
|
||||
/obj/structure/reagent_dispensers/fueltank/boom(rigtrigger = FALSE) // Prevent case where someone who rigged the tank is blamed for the explosion when the rig isn't what triggered the explosion
|
||||
/obj/structure/reagent_dispensers/fueltank/boom(rigtrigger = FALSE, log_attack = FALSE) // Prevent case where someone who rigged the tank is blamed for the explosion when the rig isn't what triggered the explosion
|
||||
if(rigtrigger) // If the explosion is triggered by an assembly holder
|
||||
message_admins("A fueltank, last rigged by [lastrigger], was triggered at [COORD(loc)]") // Then admin is informed of the last person who rigged the fuel tank
|
||||
log_game("A fueltank, last rigged by [lastrigger], triggered at [COORD(loc)]")
|
||||
add_attack_logs(lastrigger, src, "rigged fuel tank exploded")
|
||||
investigate_log("A fueltank, last rigged by [lastrigger], triggered at [COORD(loc)]", INVESTIGATE_BOMB)
|
||||
if(log_attack)
|
||||
add_attack_logs(usr, src, "blew up", ATKLOG_FEW)
|
||||
if(reagents)
|
||||
reagents.set_reagent_temp(1000) //uh-oh
|
||||
qdel(src)
|
||||
@@ -140,6 +144,7 @@
|
||||
if(istype(H.a_left, /obj/item/assembly/igniter) || istype(H.a_right, /obj/item/assembly/igniter))
|
||||
msg_admin_attack("[key_name_admin(user)] rigged [src.name] with [I.name] for explosion (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)", ATKLOG_FEW)
|
||||
log_game("[key_name(user)] rigged [src.name] with [I.name] for explosion at [COORD(loc)]")
|
||||
add_attack_logs(user, src, "rigged fuel tank")
|
||||
investigate_log("[key_name(user)] rigged [src.name] with [I.name] for explosion at [COORD(loc)]", INVESTIGATE_BOMB)
|
||||
|
||||
lastrigger = "[key_name(user)]"
|
||||
@@ -163,6 +168,7 @@ obj/structure/reagent_dispensers/fueltank/welder_act(mob/user, obj/item/I)
|
||||
user.visible_message("<span class='danger'>[user] catastrophically fails at refilling [user.p_their()] [I]!</span>", "<span class='userdanger'>That was stupid of you.</span>")
|
||||
message_admins("[key_name_admin(user)] triggered a fueltank explosion at [COORD(loc)]")
|
||||
log_game("[key_name(user)] triggered a fueltank explosion at [COORD(loc)]")
|
||||
add_attack_logs(user, src, "hit with lit welder")
|
||||
investigate_log("[key_name(user)] triggered a fueltank explosion at [COORD(loc)]", INVESTIGATE_BOMB)
|
||||
boom()
|
||||
else
|
||||
|
||||
@@ -221,6 +221,7 @@
|
||||
|
||||
user.visible_message("<span class='notice'>[user] wraps [target].</span>")
|
||||
user.create_attack_log("<font color='blue'>Has used [name] on [target]</font>")
|
||||
add_attack_logs(user, target, "used [name]")
|
||||
|
||||
if(amount <= 0 && !src.loc) //if we used our last wrapping paper, drop a cardboard tube
|
||||
new /obj/item/c_tube( get_turf(user) )
|
||||
|
||||
@@ -216,6 +216,7 @@
|
||||
deal_damage(damage)
|
||||
visible_message("<span class='danger'>[user]</span> [user.attacktext] [src]!")
|
||||
user.create_attack_log("<font color='red'>attacked [src.name]</font>")
|
||||
add_attack_logs(user, src, "attacked")
|
||||
return TRUE
|
||||
|
||||
/obj/spacepod/attack_alien(mob/user)
|
||||
|
||||
@@ -243,6 +243,7 @@
|
||||
qdel(src)
|
||||
src.visible_message("<span class='danger'>[M] has [M.attacktext] [src]!</span>")
|
||||
M.create_attack_log("<font color='red'>attacked [src.name]</font>")
|
||||
add_attack_logs(M, src, "attacked")
|
||||
|
||||
/obj/tram/bullet_act(var/obj/item/projectile/proj)
|
||||
if(prob(proj.damage))
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "code\__DEFINES\language.dm"
|
||||
#include "code\__DEFINES\layers.dm"
|
||||
#include "code\__DEFINES\lighting.dm"
|
||||
#include "code\__DEFINES\logs.dm"
|
||||
#include "code\__DEFINES\machines.dm"
|
||||
#include "code\__DEFINES\math.dm"
|
||||
#include "code\__DEFINES\MC.dm"
|
||||
@@ -263,6 +264,8 @@
|
||||
#include "code\datums\gas_mixture.dm"
|
||||
#include "code\datums\holocall.dm"
|
||||
#include "code\datums\hud.dm"
|
||||
#include "code\datums\log_record.dm"
|
||||
#include "code\datums\log_viewer.dm"
|
||||
#include "code\datums\mind.dm"
|
||||
#include "code\datums\mixed.dm"
|
||||
#include "code\datums\mutable_appearance.dm"
|
||||
@@ -1213,6 +1216,7 @@
|
||||
#include "code\modules\admin\verbs\gimmick_team.dm"
|
||||
#include "code\modules\admin\verbs\honksquad.dm"
|
||||
#include "code\modules\admin\verbs\infiltratorteam_syndicate.dm"
|
||||
#include "code\modules\admin\verbs\logging_view.dm"
|
||||
#include "code\modules\admin\verbs\map_template_loadverb.dm"
|
||||
#include "code\modules\admin\verbs\mapping.dm"
|
||||
#include "code\modules\admin\verbs\massmodvar.dm"
|
||||
|
||||
Reference in New Issue
Block a user