Merge remote-tracking branch 'origin/master' into hardsync-1.5
This commit is contained in:
@@ -80,8 +80,11 @@
|
||||
var/client/banned_client = banned_mob?.client
|
||||
var/banned_mob_guest_key = had_banned_mob && IsGuestKey(banned_mob.key)
|
||||
banned_mob = null
|
||||
var/sql_ckey = sanitizeSQL(ckey)
|
||||
var/datum/DBQuery/query_add_ban_get_ckey = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("player")] WHERE ckey = '[sql_ckey]'")
|
||||
var/datum/db_query/query_add_ban_get_ckey = SSdbcore.NewQuery({"
|
||||
SELECT 1
|
||||
FROM [format_table_name("player")]
|
||||
WHERE ckey = :ckey"},
|
||||
list("ckey" = ckey))
|
||||
if(!query_add_ban_get_ckey.warn_execute())
|
||||
qdel(query_add_ban_get_ckey)
|
||||
return
|
||||
@@ -122,10 +125,11 @@
|
||||
else
|
||||
adminwho += ", [C]"
|
||||
|
||||
reason = sanitizeSQL(reason)
|
||||
var/sql_a_ckey = sanitizeSQL(a_ckey)
|
||||
if(maxadminbancheck)
|
||||
var/datum/DBQuery/query_check_adminban_amt = SSdbcore.NewQuery("SELECT count(id) AS num FROM [format_table_name("ban")] WHERE (a_ckey = '[sql_a_ckey]') AND (bantype = 'ADMIN_PERMABAN' OR (bantype = 'ADMIN_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)")
|
||||
var/datum/db_query/query_check_adminban_amt = SSdbcore.NewQuery({"
|
||||
SELECT count(id) AS num FROM [format_table_name("ban")]
|
||||
WHERE (a_ckey = :a_ckey) AND (bantype = 'ADMIN_PERMABAN' OR (bantype = 'ADMIN_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)
|
||||
"}, list("a_ckey" = a_ckey))
|
||||
if(!query_check_adminban_amt.warn_execute())
|
||||
qdel(query_check_adminban_amt)
|
||||
return
|
||||
@@ -143,13 +147,15 @@
|
||||
computerid = "0"
|
||||
if(!ip)
|
||||
ip = "0.0.0.0"
|
||||
var/sql_job = sanitizeSQL(job)
|
||||
var/sql_computerid = sanitizeSQL(computerid)
|
||||
var/sql_ip = sanitizeSQL(ip)
|
||||
var/sql_a_computerid = sanitizeSQL(a_computerid)
|
||||
var/sql_a_ip = sanitizeSQL(a_ip)
|
||||
var/sql = "INSERT INTO [format_table_name("ban")] (`bantime`,`server_ip`,`server_port`,`round_id`,`bantype`,`reason`,`job`,`duration`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`) VALUES (Now(), INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', '[GLOB.round_id]', '[bantype_str]', '[reason]', '[sql_job]', [(duration)?"[duration]":"0"], Now() + INTERVAL [(duration>0) ? duration : 0] MINUTE, '[sql_ckey]', '[sql_computerid]', INET_ATON('[sql_ip]'), '[sql_a_ckey]', '[sql_a_computerid]', INET_ATON('[sql_a_ip]'), '[who]', '[adminwho]')"
|
||||
var/datum/DBQuery/query_add_ban = SSdbcore.NewQuery(sql)
|
||||
var/datum/db_query/query_add_ban = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("ban")] (`bantime`,`server_ip`,`server_port`,`round_id`,`bantype`,`reason`,`job`,`duration`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`)
|
||||
VALUES (Now(), INET_ATON(:internet_address), :port, :round_id, :bantype_str, :reason, :job, :duration, Now() + INTERVAL :expiration_time MINUTE, :ckey, :computerid, INET_ATON(:ip), :a_ckey, :a_computerid, INET_ATON(:a_ip), :who, :adminwho)
|
||||
"}, list("internet_address" = world.internet_address ? world.internet_address : 0,
|
||||
"port" = world.port, "round_id" = GLOB.round_id, "bantype_str" = bantype_str, "reason" = reason,
|
||||
"job" = job, "duration" = duration ? "[duration]":"0", "expiration_time" = (duration > 0) ? duration : 0,
|
||||
"ckey" = ckey, "computerid" = computerid, "ip" = ip,
|
||||
"a_ckey" = a_ckey, "a_computerid" = a_computerid, "a_ip" = a_ip, "who" = who, "adminwho" = adminwho
|
||||
))
|
||||
if(!query_add_ban.warn_execute())
|
||||
qdel(query_add_ban)
|
||||
return
|
||||
@@ -160,7 +166,7 @@
|
||||
var/datum/admin_help/AH = admin_ticket_log(ckey, msg)
|
||||
|
||||
if(announceinirc)
|
||||
send2irc("BAN ALERT","[a_key] applied a [bantype_str] on [bankey]")
|
||||
send2adminchat("BAN ALERT","[a_key] applied a [bantype_str] on [bankey]")
|
||||
|
||||
if(kickbannedckey)
|
||||
if(AH)
|
||||
@@ -212,11 +218,11 @@
|
||||
bantype_sql = "(bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now() ) )"
|
||||
else
|
||||
bantype_sql = "bantype = '[bantype_str]'"
|
||||
var/sql_ckey = sanitizeSQL(ckey)
|
||||
var/sql = "SELECT id FROM [format_table_name("ban")] WHERE ckey = '[sql_ckey]' AND [bantype_sql] AND (unbanned is null OR unbanned = false)"
|
||||
var/sql = "SELECT id FROM [format_table_name("ban")] WHERE ckey = :ckey AND [bantype_sql] AND (unbanned is null OR unbanned = false)"
|
||||
var/list/sql_args = list("ckey" = ckey)
|
||||
if(job)
|
||||
var/sql_job = sanitizeSQL(job)
|
||||
sql += " AND job = '[sql_job]'"
|
||||
sql += " AND job = :job"
|
||||
sql_args["job"] = job
|
||||
|
||||
if(!SSdbcore.Connect())
|
||||
return
|
||||
@@ -224,7 +230,7 @@
|
||||
var/ban_id
|
||||
var/ban_number = 0 //failsafe
|
||||
|
||||
var/datum/DBQuery/query_unban_get_id = SSdbcore.NewQuery(sql)
|
||||
var/datum/db_query/query_unban_get_id = SSdbcore.NewQuery(sql, sql_args)
|
||||
if(!query_unban_get_id.warn_execute())
|
||||
qdel(query_unban_get_id)
|
||||
return
|
||||
@@ -258,7 +264,7 @@
|
||||
to_chat(usr, "Cancelled")
|
||||
return
|
||||
|
||||
var/datum/DBQuery/query_edit_ban_get_details = SSdbcore.NewQuery("SELECT IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].ckey), ckey), duration, reason FROM [format_table_name("ban")] WHERE id = [banid]")
|
||||
var/datum/db_query/query_edit_ban_get_details = SSdbcore.NewQuery("SELECT IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].ckey), ckey), duration, reason FROM [format_table_name("ban")] WHERE id = [banid]")
|
||||
if(!query_edit_ban_get_details.warn_execute())
|
||||
qdel(query_edit_ban_get_details)
|
||||
return
|
||||
@@ -278,19 +284,17 @@
|
||||
return
|
||||
qdel(query_edit_ban_get_details)
|
||||
|
||||
reason = sanitizeSQL(reason)
|
||||
var/value
|
||||
|
||||
switch(param)
|
||||
if("reason")
|
||||
if(!value)
|
||||
value = input("Insert the new reason for [p_key]'s ban", "New Reason", "[reason]", null) as null|text
|
||||
value = sanitizeSQL(value)
|
||||
if(!value)
|
||||
to_chat(usr, "Cancelled")
|
||||
return
|
||||
|
||||
var/datum/DBQuery/query_edit_ban_reason = SSdbcore.NewQuery("UPDATE [format_table_name("ban")] SET reason = '[value]', edits = CONCAT(edits,'- [e_key] changed ban reason from <cite><b>\\\"[reason]\\\"</b></cite> to <cite><b>\\\"[value]\\\"</b></cite><BR>') WHERE id = [banid]")
|
||||
var/datum/db_query/query_edit_ban_reason = SSdbcore.NewQuery("UPDATE [format_table_name("ban")] SET reason = '[value]', edits = CONCAT(edits,'- [e_key] changed ban reason from <cite><b>\\\"[reason]\\\"</b></cite> to <cite><b>\\\"[value]\\\"</b></cite><BR>') WHERE id = [banid]")
|
||||
if(!query_edit_ban_reason.warn_execute())
|
||||
qdel(query_edit_ban_reason)
|
||||
return
|
||||
@@ -303,7 +307,7 @@
|
||||
to_chat(usr, "Cancelled")
|
||||
return
|
||||
|
||||
var/datum/DBQuery/query_edit_ban_duration = SSdbcore.NewQuery("UPDATE [format_table_name("ban")] SET duration = [value], edits = CONCAT(edits,'- [e_key] changed ban duration from [duration] to [value]<br>'), expiration_time = DATE_ADD(bantime, INTERVAL [value] MINUTE) WHERE id = [banid]")
|
||||
var/datum/db_query/query_edit_ban_duration = SSdbcore.NewQuery("UPDATE [format_table_name("ban")] SET duration = [value], edits = CONCAT(edits,'- [e_key] changed ban duration from [duration] to [value]<br>'), expiration_time = DATE_ADD(bantime, INTERVAL [value] MINUTE) WHERE id = [banid]")
|
||||
if(!query_edit_ban_duration.warn_execute())
|
||||
qdel(query_edit_ban_duration)
|
||||
return
|
||||
@@ -333,7 +337,7 @@
|
||||
var/ban_number = 0 //failsafe
|
||||
|
||||
var/p_key
|
||||
var/datum/DBQuery/query_unban_get_ckey = SSdbcore.NewQuery(sql)
|
||||
var/datum/db_query/query_unban_get_ckey = SSdbcore.NewQuery(sql)
|
||||
if(!query_unban_get_ckey.warn_execute())
|
||||
qdel(query_unban_get_ckey)
|
||||
return
|
||||
@@ -358,7 +362,7 @@
|
||||
var/unban_ip = owner.address
|
||||
|
||||
var/sql_update = "UPDATE [format_table_name("ban")] SET unbanned = 1, unbanned_datetime = Now(), unbanned_ckey = '[unban_ckey]', unbanned_computerid = '[unban_computerid]', unbanned_ip = INET_ATON('[unban_ip]') WHERE id = [id]"
|
||||
var/datum/DBQuery/query_unban = SSdbcore.NewQuery(sql_update)
|
||||
var/datum/db_query/query_unban = SSdbcore.NewQuery(sql_update)
|
||||
if(!query_unban.warn_execute())
|
||||
qdel(query_unban)
|
||||
return
|
||||
@@ -448,20 +452,28 @@
|
||||
|
||||
if(adminckey || playerckey || ip || cid)
|
||||
var/list/searchlist = list()
|
||||
var/list/searchlist_args = list()
|
||||
if(playerckey)
|
||||
searchlist += "ckey = '[sanitizeSQL(ckey(playerckey))]'"
|
||||
searchlist += "ckey = :playerckey"
|
||||
searchlist_args["playerckey"] = playerckey
|
||||
if(adminckey)
|
||||
searchlist += "a_ckey = '[sanitizeSQL(ckey(adminckey))]'"
|
||||
searchlist += "a_ckey = :adminckey"
|
||||
searchlist_args["adminckey"] = adminckey
|
||||
if(ip)
|
||||
searchlist += "ip = INET_ATON('[sanitizeSQL(ip)]')"
|
||||
searchlist += "ip = INET_ATON(:ip)"
|
||||
searchlist_args["ip"] = ip
|
||||
if(cid)
|
||||
searchlist += "computerid = '[sanitizeSQL(cid)]'"
|
||||
var/search = searchlist.Join(" AND ")
|
||||
searchlist += "computerid = :cid"
|
||||
searchlist_args["cid"] = cid
|
||||
var/search = searchlist.Join(" AND ") // x = x AND y = z
|
||||
var/bancount = 0
|
||||
var/bansperpage = 15
|
||||
var/pagecount = 0
|
||||
page = text2num(page)
|
||||
var/datum/DBQuery/query_count_bans = SSdbcore.NewQuery("SELECT COUNT(id) FROM [format_table_name("ban")] WHERE [search]")
|
||||
var/datum/db_query/query_count_bans = SSdbcore.NewQuery({"
|
||||
SELECT COUNT(id) FROM [format_table_name("ban")]
|
||||
WHERE [search]
|
||||
"}, searchlist_args)
|
||||
if(!query_count_bans.warn_execute())
|
||||
qdel(query_count_bans)
|
||||
return
|
||||
@@ -489,7 +501,11 @@
|
||||
output += "<th width='15%'><b>OPTIONS</b></th>"
|
||||
output += "</tr>"
|
||||
var/limit = " LIMIT [bansperpage * page], [bansperpage]"
|
||||
var/datum/DBQuery/query_search_bans = SSdbcore.NewQuery("SELECT id, bantime, bantype, reason, job, duration, expiration_time, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].ckey), ckey), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].a_ckey), a_ckey), unbanned, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].unbanned_ckey), unbanned_ckey), unbanned_datetime, edits, round_id FROM [format_table_name("ban")] WHERE [search] ORDER BY bantime DESC[limit]")
|
||||
|
||||
var/datum/db_query/query_search_bans = SSdbcore.NewQuery({"
|
||||
SELECT id, bantime, bantype, reason, job, duration, expiration_time, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].ckey), ckey), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].a_ckey), a_ckey), unbanned, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].unbanned_ckey), unbanned_ckey), unbanned_datetime, edits, round_id
|
||||
FROM [format_table_name("ban")]
|
||||
WHERE [search] ORDER BY bantime DESC[limit]"}, searchlist_args)
|
||||
if(!query_search_bans.warn_execute())
|
||||
qdel(query_search_bans)
|
||||
return
|
||||
|
||||
@@ -100,7 +100,18 @@
|
||||
if(computer_id)
|
||||
cidquery = " OR computerid = '[computer_id]' "
|
||||
|
||||
var/datum/DBQuery/query_ban_check = SSdbcore.NewQuery("SELECT IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].ckey), ckey), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].a_ckey), a_ckey), reason, expiration_time, duration, bantime, bantype, id, round_id FROM [format_table_name("ban")] WHERE (ckey = '[ckey]' [ipquery] [cidquery]) AND (bantype = 'PERMABAN' OR bantype = 'ADMIN_PERMABAN' OR ((bantype = 'TEMPBAN' OR bantype = 'ADMIN_TEMPBAN') AND expiration_time > Now())) AND isnull(unbanned)")
|
||||
var/datum/db_query/query_ban_check = SSdbcore.NewQuery({"
|
||||
SELECT IFNULL((SELECT byond_key
|
||||
FROM [format_table_name("player")]
|
||||
WHERE [format_table_name("player")].ckey = [format_table_name("ban")].ckey), ckey),
|
||||
IFNULL((SELECT byond_key FROM [format_table_name("player")]
|
||||
WHERE [format_table_name("player")].ckey = [format_table_name("ban")].a_ckey), a_ckey), reason, expiration_time, duration, bantime, bantype, id, round_id FROM [format_table_name("ban")]
|
||||
WHERE (ckey = :ckey [ipquery] [cidquery])
|
||||
AND (bantype = 'PERMABAN' OR bantype = 'ADMIN_PERMABAN' OR ((bantype = 'TEMPBAN' OR bantype = 'ADMIN_TEMPBAN')
|
||||
AND expiration_time > Now())) AND isnull(unbanned)
|
||||
"}, list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query_ban_check.Execute(async = TRUE))
|
||||
qdel(query_ban_check)
|
||||
key_cache[key] = 0
|
||||
|
||||
@@ -119,16 +119,12 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
set waitfor = FALSE
|
||||
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='admin prefix'>Admin rank DB Sync blocked: Advanced ProcCall detected.</span>")
|
||||
to_chat(usr, "<span class='admin prefix'>Admin rank DB Sync blocked: Advanced ProcCall detected.</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
var/list/sql_ranks = list()
|
||||
for(var/datum/admin_rank/R in GLOB.protected_ranks)
|
||||
var/sql_rank = sanitizeSQL(R.name)
|
||||
var/sql_flags = sanitizeSQL(R.include_rights)
|
||||
var/sql_exclude_flags = sanitizeSQL(R.exclude_rights)
|
||||
var/sql_can_edit_flags = sanitizeSQL(R.can_edit_rights)
|
||||
sql_ranks += list(list("rank" = "'[sql_rank]'", "flags" = "[sql_flags]", "exclude_flags" = "[sql_exclude_flags]", "can_edit_flags" = "[sql_can_edit_flags]"))
|
||||
sql_ranks += list(list("rank" = R.name, "flags" = R.include_rights, "exclude_flags" = R.exclude_rights, "can_edit_flags" = R.can_edit_rights))
|
||||
SSdbcore.MassInsert(format_table_name("admin_ranks"), sql_ranks, duplicate_key = TRUE)
|
||||
|
||||
//load our rank - > rights associations
|
||||
@@ -160,7 +156,7 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
if(!no_update)
|
||||
sync_ranks_with_db()
|
||||
else
|
||||
var/datum/DBQuery/query_load_admin_ranks = SSdbcore.NewQuery("SELECT rank, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")]")
|
||||
var/datum/db_query/query_load_admin_ranks = SSdbcore.NewQuery("SELECT `rank`, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")]")
|
||||
if(!query_load_admin_ranks.Execute())
|
||||
message_admins("Error loading admin ranks from database. Loading from backup.")
|
||||
log_sql("Error loading admin ranks from database. Loading from backup.")
|
||||
@@ -168,7 +164,7 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
else
|
||||
while(query_load_admin_ranks.NextRow())
|
||||
var/skip
|
||||
var/rank_name = ckeyEx(query_load_admin_ranks.item[1])
|
||||
var/rank_name = query_load_admin_ranks.item[1]
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
if(R.name == rank_name) //this rank was already loaded from txt override
|
||||
skip = 1
|
||||
@@ -234,20 +230,12 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
rank_names[R.name] = R
|
||||
//ckeys listed in admins.txt are always made admins before sql loading is attempted
|
||||
var/list/lines = world.file2list("[global.config.directory]/admins.txt")
|
||||
for(var/line in lines)
|
||||
if(!length(line) || findtextEx(line, "#", 1, 2))
|
||||
continue
|
||||
var/list/entry = splittext(line, "=")
|
||||
if(entry.len < 2)
|
||||
continue
|
||||
var/ckey = ckey(entry[1])
|
||||
var/rank = ckeyEx(entry[2])
|
||||
if(!ckey || !rank)
|
||||
continue
|
||||
new /datum/admins(rank_names[rank], ckey, 0, 1)
|
||||
var/admins_text = file2text("[global.config.directory]/admins.txt")
|
||||
var/regex/admins_regex = new(@"^(?!#)(.+?)\s+=\s+(.+)", "gm")
|
||||
while(admins_regex.Find(admins_text))
|
||||
new /datum/admins(rank_names[admins_regex.group[2]], ckey(admins_regex.group[1]), FALSE, TRUE)
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) || dbfail)
|
||||
var/datum/DBQuery/query_load_admins = SSdbcore.NewQuery("SELECT ckey, rank FROM [format_table_name("admin")] ORDER BY rank")
|
||||
var/datum/db_query/query_load_admins = SSdbcore.NewQuery("SELECT ckey, `rank` FROM [format_table_name("admin")] ORDER BY `rank`")
|
||||
if(!query_load_admins.Execute())
|
||||
message_admins("Error loading admins from database. Loading from backup.")
|
||||
log_sql("Error loading admins from database. Loading from backup.")
|
||||
@@ -255,7 +243,7 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
else
|
||||
while(query_load_admins.NextRow())
|
||||
var/admin_ckey = ckey(query_load_admins.item[1])
|
||||
var/admin_rank = ckeyEx(query_load_admins.item[2])
|
||||
var/admin_rank = query_load_admins.item[2]
|
||||
var/skip
|
||||
if(rank_names[admin_rank] == null)
|
||||
message_admins("[admin_ckey] loaded with invalid admin rank [admin_rank].")
|
||||
|
||||
@@ -3,8 +3,11 @@
|
||||
if(!M || !istype(M) || !M.ckey)
|
||||
return FALSE
|
||||
|
||||
if(!M.client) //no cache. fallback to a datum/DBQuery
|
||||
var/datum/DBQuery/query_jobban_check_ban = SSdbcore.NewQuery("SELECT reason FROM [format_table_name("ban")] WHERE ckey = '[sanitizeSQL(M.ckey)]' AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned) AND job = '[sanitizeSQL(rank)]'")
|
||||
if(!M.client) //no cache. fallback to a datum/db_query
|
||||
var/datum/db_query/query_jobban_check_ban = SSdbcore.NewQuery({"
|
||||
SELECT reason FROM [format_table_name("ban")]
|
||||
WHERE ckey = :ckey AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned) AND job = :rank
|
||||
"}, list("ckey" = M.ckey, "rank" = rank))
|
||||
if(!query_jobban_check_ban.warn_execute())
|
||||
qdel(query_jobban_check_ban)
|
||||
return
|
||||
@@ -28,7 +31,10 @@
|
||||
return
|
||||
if(C && istype(C))
|
||||
C.jobbancache = list()
|
||||
var/datum/DBQuery/query_jobban_build_cache = SSdbcore.NewQuery("SELECT job, reason FROM [format_table_name("ban")] WHERE ckey = '[sanitizeSQL(C.ckey)]' AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)")
|
||||
var/datum/db_query/query_jobban_build_cache = SSdbcore.NewQuery({"
|
||||
SELECT job, reason FROM [format_table_name("ban")]
|
||||
WHERE ckey = :ckey AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)
|
||||
"}, list("ckey" = C.ckey))
|
||||
if(!query_jobban_build_cache.warn_execute())
|
||||
qdel(query_jobban_build_cache)
|
||||
return
|
||||
|
||||
@@ -34,8 +34,9 @@
|
||||
var/endtime = input("Set end time for poll as format YYYY-MM-DD HH:MM:SS. All times in server time. HH:MM:SS is optional and 24-hour. Must be later than starting time for obvious reasons.", "Set end time", SQLtime()) as text
|
||||
if(!endtime)
|
||||
return
|
||||
endtime = sanitizeSQL(endtime)
|
||||
var/datum/DBQuery/query_validate_time = SSdbcore.NewQuery("SELECT IF(STR_TO_DATE('[endtime]','%Y-%c-%d %T') > NOW(), STR_TO_DATE('[endtime]','%Y-%c-%d %T'), 0)")
|
||||
var/datum/db_query/query_validate_time = SSdbcore.NewQuery({"
|
||||
SELECT IF(STR_TO_DATE(:endtime,'%Y-%c-%d %T') > NOW(), STR_TO_DATE(:endtime,'%Y-%c-%d %T'), 0)
|
||||
"}, list("endtime" = endtime))
|
||||
if(!query_validate_time.warn_execute() || QDELETED(usr) || !src)
|
||||
qdel(query_validate_time)
|
||||
return
|
||||
@@ -63,11 +64,9 @@
|
||||
dontshow = 0
|
||||
else
|
||||
return
|
||||
var/sql_ckey = sanitizeSQL(ckey)
|
||||
var/question = input("Write your question","Question") as message|null
|
||||
if(!question)
|
||||
return
|
||||
question = sanitizeSQL(question)
|
||||
var/list/sql_option_list = list()
|
||||
if(polltype != POLLTYPE_TEXT)
|
||||
var/add_option = 1
|
||||
@@ -75,7 +74,6 @@
|
||||
var/option = input("Write your option","Option") as message|null
|
||||
if(!option)
|
||||
return
|
||||
option = sanitizeSQL(option)
|
||||
var/default_percentage_calc = 0
|
||||
if(polltype != POLLTYPE_IRV)
|
||||
switch(alert("Should this option be included by default when poll result percentages are generated?",,"Yes","No","Cancel"))
|
||||
@@ -92,34 +90,27 @@
|
||||
var/descmax = ""
|
||||
if(polltype == POLLTYPE_RATING)
|
||||
minval = input("Set minimum rating value.","Minimum rating") as num|null
|
||||
if(minval)
|
||||
minval = sanitizeSQL(minval)
|
||||
else if(minval == null)
|
||||
if(minval == null)
|
||||
return
|
||||
maxval = input("Set maximum rating value.","Maximum rating") as num|null
|
||||
if(maxval)
|
||||
maxval = sanitizeSQL(maxval)
|
||||
if(minval >= maxval)
|
||||
to_chat(src, "Maximum rating value can't be less than or equal to minimum rating value")
|
||||
continue
|
||||
else if(maxval == null)
|
||||
if(maxval == null)
|
||||
return
|
||||
descmin = input("Optional: Set description for minimum rating","Minimum rating description") as message|null
|
||||
if(descmin)
|
||||
descmin = sanitizeSQL(descmin)
|
||||
else if(descmin == null)
|
||||
if(descmin == null)
|
||||
return
|
||||
descmid = input("Optional: Set description for median rating","Median rating description") as message|null
|
||||
if(descmid)
|
||||
descmid = sanitizeSQL(descmid)
|
||||
else if(descmid == null)
|
||||
if(descmid == null)
|
||||
return
|
||||
descmax = input("Optional: Set description for maximum rating","Maximum rating description") as message|null
|
||||
if(descmax)
|
||||
descmax = sanitizeSQL(descmax)
|
||||
else if(descmax == null)
|
||||
if(descmax == null)
|
||||
return
|
||||
sql_option_list += list(list("text" = "'[option]'", "minval" = "'[minval]'", "maxval" = "'[maxval]'", "descmin" = "'[descmin]'", "descmid" = "'[descmid]'", "descmax" = "'[descmax]'", "default_percentage_calc" = "'[default_percentage_calc]'"))
|
||||
sql_option_list += list(list(
|
||||
"text" = option, "minval" = minval, "maxval" = maxval,
|
||||
"descmin" = descmin, "descmid" = descmid, "descmax" = descmax,
|
||||
"default_percentage_calc" = default_percentage_calc))
|
||||
switch(alert(" ",,"Add option","Finish", "Cancel"))
|
||||
if("Add option")
|
||||
add_option = 1
|
||||
@@ -129,14 +120,21 @@
|
||||
return 0
|
||||
var/m1 = "[key_name(usr)] has created a new server poll. Poll type: [polltype] - Admin Only: [adminonly ? "Yes" : "No"] - Question: [question]"
|
||||
var/m2 = "[key_name_admin(usr)] has created a new server poll. Poll type: [polltype] - Admin Only: [adminonly ? "Yes" : "No"]<br>Question: [question]"
|
||||
var/datum/DBQuery/query_polladd_question = SSdbcore.NewQuery("INSERT INTO [format_table_name("poll_question")] (polltype, starttime, endtime, question, adminonly, multiplechoiceoptions, createdby_ckey, createdby_ip, dontshow) VALUES ('[polltype]', '[starttime]', '[endtime]', '[question]', '[adminonly]', '[choice_amount]', '[sql_ckey]', INET_ATON('[address]'), '[dontshow]')")
|
||||
var/datum/db_query/query_polladd_question = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("poll_question")] (polltype, starttime, endtime, question, adminonly, multiplechoiceoptions, createdby_ckey, createdby_ip, dontshow)
|
||||
VALUES (:polltype, :starttime, :endtime, :question, :adminonly, :choice_amount, :ckey, INET_ATON(:address), :dontshow)
|
||||
"}, list(
|
||||
"polltype" = polltype, "starttime" = starttime, "endtime" = endtime,
|
||||
"question" = question, "adminonly" = adminonly, "choice_amount" = choice_amount,
|
||||
"ckey" = ckey, "address" = address, "dontshow" = dontshow
|
||||
))
|
||||
if(!query_polladd_question.warn_execute())
|
||||
qdel(query_polladd_question)
|
||||
return
|
||||
qdel(query_polladd_question)
|
||||
if(polltype != POLLTYPE_TEXT)
|
||||
var/pollid = 0
|
||||
var/datum/DBQuery/query_get_id = SSdbcore.NewQuery("SELECT LAST_INSERT_ID()")
|
||||
var/datum/db_query/query_get_id = SSdbcore.NewQuery("SELECT LAST_INSERT_ID()")
|
||||
if(!query_get_id.warn_execute())
|
||||
qdel(query_get_id)
|
||||
return
|
||||
@@ -145,6 +143,6 @@
|
||||
qdel(query_get_id)
|
||||
for(var/list/i in sql_option_list)
|
||||
i |= list("pollid" = "'[pollid]'")
|
||||
SSdbcore.MassInsert(format_table_name("poll_option"), sql_option_list, warn = 1)
|
||||
SSdbcore.MassInsert(format_table_name("poll_option"), sql_option_list, warn = TRUE)
|
||||
log_admin(m1)
|
||||
message_admins(m2)
|
||||
|
||||
@@ -29,27 +29,27 @@
|
||||
return
|
||||
if (!bypasscache)
|
||||
var/datum/ipintel/cachedintel = SSipintel.cache[ip]
|
||||
if (cachedintel && cachedintel.is_valid())
|
||||
if (cachedintel?.is_valid())
|
||||
cachedintel.cache = TRUE
|
||||
return cachedintel
|
||||
|
||||
if(SSdbcore.Connect())
|
||||
var/rating_bad = CONFIG_GET(number/ipintel_rating_bad)
|
||||
var/datum/DBQuery/query_get_ip_intel = SSdbcore.NewQuery({"
|
||||
var/datum/db_query/query_get_ip_intel = SSdbcore.NewQuery({"
|
||||
SELECT date, intel, TIMESTAMPDIFF(MINUTE,date,NOW())
|
||||
FROM [format_table_name("ipintel")]
|
||||
WHERE
|
||||
ip = INET_ATON('[ip]')
|
||||
ip = INET_ATON(':ip')
|
||||
AND ((
|
||||
intel < [rating_bad]
|
||||
intel < :rating_bad
|
||||
AND
|
||||
date + INTERVAL [CONFIG_GET(number/ipintel_save_good)] HOUR > NOW()
|
||||
date + INTERVAL :save_good HOUR > NOW()
|
||||
) OR (
|
||||
intel >= [rating_bad]
|
||||
intel >= :rating_bad
|
||||
AND
|
||||
date + INTERVAL [CONFIG_GET(number/ipintel_save_bad)] HOUR > NOW()
|
||||
date + INTERVAL :save_bad HOUR > NOW()
|
||||
))
|
||||
"})
|
||||
"}, list("ip" = ip, "rating_bad" = rating_bad, "save_good" = CONFIG_GET(number/ipintel_save_good), "save_bad" = CONFIG_GET(number/ipintel_save_bad)))
|
||||
if(!query_get_ip_intel.Execute())
|
||||
qdel(query_get_ip_intel)
|
||||
return
|
||||
@@ -67,12 +67,15 @@
|
||||
if (updatecache && res.intel >= 0)
|
||||
SSipintel.cache[ip] = res
|
||||
if(SSdbcore.Connect())
|
||||
var/datum/DBQuery/query_add_ip_intel = SSdbcore.NewQuery("INSERT INTO [format_table_name("ipintel")] (ip, intel) VALUES (INET_ATON('[ip]'), [res.intel]) ON DUPLICATE KEY UPDATE intel = VALUES(intel), date = NOW()")
|
||||
var/datum/db_query/query_add_ip_intel = SSdbcore.NewQuery(
|
||||
"INSERT INTO [format_table_name("ipintel")] (ip, intel) VALUES (INET_ATON(:ip), :intel) ON DUPLICATE KEY UPDATE intel = VALUES(intel), date = NOW()",
|
||||
list("ip" = ip, "intel" = res.intel)
|
||||
)
|
||||
query_add_ip_intel.Execute()
|
||||
qdel(query_add_ip_intel)
|
||||
|
||||
|
||||
/proc/ip_intel_query(ip, var/retryed=0)
|
||||
/proc/ip_intel_query(ip, retryed=0)
|
||||
. = -1 //default
|
||||
if (!ip)
|
||||
return
|
||||
@@ -131,8 +134,3 @@
|
||||
/proc/log_ipintel(text)
|
||||
log_game("IPINTEL: [text]")
|
||||
debug_admins("IPINTEL: [text]")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -15,21 +15,14 @@
|
||||
else
|
||||
output += "<br><a href='?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightspage=0'>\[Log\]</a><br><a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1'>\[Management\]</a>"
|
||||
if(action == 1)
|
||||
var/list/searchlist = list(" WHERE ")
|
||||
if(target)
|
||||
searchlist += "ckey = '[sanitizeSQL(target)]'"
|
||||
if(operation)
|
||||
if(target)
|
||||
searchlist += " AND "
|
||||
searchlist += "operation = '[sanitizeSQL(operation)]'"
|
||||
var/search
|
||||
if(searchlist.len > 1)
|
||||
search = searchlist.Join("")
|
||||
var/logcount = 0
|
||||
var/logssperpage = 20
|
||||
var/pagecount = 0
|
||||
page = text2num(page)
|
||||
var/datum/DBQuery/query_count_admin_logs = SSdbcore.NewQuery("SELECT COUNT(id) FROM [format_table_name("admin_log")][search]")
|
||||
var/datum/db_query/query_count_admin_logs = SSdbcore.NewQuery(
|
||||
"SELECT COUNT(id) FROM [format_table_name("admin_log")] WHERE (:target IS NULL OR adminckey = :target) AND (:operation IS NULL OR operation = :operation)",
|
||||
list("target" = target, "operation" = operation)
|
||||
)
|
||||
if(!query_count_admin_logs.warn_execute())
|
||||
qdel(query_count_admin_logs)
|
||||
return
|
||||
@@ -43,8 +36,20 @@
|
||||
logcount -= logssperpage
|
||||
pagecount++
|
||||
output += "|"
|
||||
var/limit = " LIMIT [logssperpage * page], [logssperpage]"
|
||||
var/datum/DBQuery/query_search_admin_logs = SSdbcore.NewQuery("SELECT datetime, round_id, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey), operation, IF(ckey IS NULL, target, byond_key), log FROM [format_table_name("admin_log")] LEFT JOIN [format_table_name("player")] ON target = ckey[search] ORDER BY datetime DESC[limit]")
|
||||
var/datum/db_query/query_search_admin_logs = SSdbcore.NewQuery({"
|
||||
SELECT
|
||||
datetime,
|
||||
round_id,
|
||||
IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey),
|
||||
operation,
|
||||
IF(ckey IS NULL, target, byond_key),
|
||||
log
|
||||
FROM [format_table_name("admin_log")]
|
||||
LEFT JOIN [format_table_name("player")] ON target = ckey
|
||||
WHERE (:target IS NULL OR ckey = :target) AND (:operation IS NULL OR operation = :operation)
|
||||
ORDER BY datetime DESC
|
||||
LIMIT :skip, :take
|
||||
"}, list("target" = target, "operation" = operation, "skip" = logssperpage * page, "take" = logssperpage))
|
||||
if(!query_search_admin_logs.warn_execute())
|
||||
qdel(query_search_admin_logs)
|
||||
return
|
||||
@@ -59,7 +64,7 @@
|
||||
qdel(query_search_admin_logs)
|
||||
if(action == 2)
|
||||
output += "<h3>Admin ckeys with invalid ranks</h3>"
|
||||
var/datum/DBQuery/query_check_admin_errors = SSdbcore.NewQuery("SELECT IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("admin")].ckey), ckey), [format_table_name("admin")].rank FROM [format_table_name("admin")] LEFT JOIN [format_table_name("admin_ranks")] ON [format_table_name("admin_ranks")].rank = [format_table_name("admin")].rank WHERE [format_table_name("admin_ranks")].rank IS NULL")
|
||||
var/datum/db_query/query_check_admin_errors = SSdbcore.NewQuery("SELECT IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("admin")].ckey), ckey), [format_table_name("admin")].`rank` FROM [format_table_name("admin")] LEFT JOIN [format_table_name("admin_ranks")] ON [format_table_name("admin_ranks")].`rank` = [format_table_name("admin")].`rank` WHERE [format_table_name("admin_ranks")].`rank` IS NULL")
|
||||
if(!query_check_admin_errors.warn_execute())
|
||||
qdel(query_check_admin_errors)
|
||||
return
|
||||
@@ -70,7 +75,7 @@
|
||||
output += "<hr style='background:#000000; border:0; height:1px'>"
|
||||
qdel(query_check_admin_errors)
|
||||
output += "<h3>Unused ranks</h3>"
|
||||
var/datum/DBQuery/query_check_unused_rank = SSdbcore.NewQuery("SELECT [format_table_name("admin_ranks")].rank, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")] LEFT JOIN [format_table_name("admin")] ON [format_table_name("admin")].rank = [format_table_name("admin_ranks")].rank WHERE [format_table_name("admin")].rank IS NULL")
|
||||
var/datum/db_query/query_check_unused_rank = SSdbcore.NewQuery("SELECT [format_table_name("admin_ranks")].`rank`, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")] LEFT JOIN [format_table_name("admin")] ON [format_table_name("admin")].`rank` = [format_table_name("admin_ranks")].`rank` WHERE [format_table_name("admin")].`rank` IS NULL")
|
||||
if(!query_check_unused_rank.warn_execute())
|
||||
qdel(query_check_unused_rank)
|
||||
return
|
||||
@@ -130,7 +135,7 @@
|
||||
log_admin("[key_name(usr)] attempted to edit admin permissions without sufficient rights.")
|
||||
return
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='admin prefix'>Admin Edit blocked: Advanced ProcCall detected.</span>")
|
||||
to_chat(usr, "<span class='admin prefix'>Admin Edit blocked: Advanced ProcCall detected.</span>", confidential = TRUE)
|
||||
return
|
||||
var/datum/asset/permissions_assets = get_asset_datum(/datum/asset/simple/permissions)
|
||||
permissions_assets.send(src)
|
||||
@@ -145,19 +150,19 @@
|
||||
skip = TRUE
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_admins) && task == "rank")
|
||||
if(admin_ckey in GLOB.protected_admins)
|
||||
to_chat(usr, "<span class='admin prefix'>Editing the rank of this admin is blocked by server configuration.</span>")
|
||||
to_chat(usr, "<span class='admin prefix'>Editing the rank of this admin is blocked by server configuration.</span>", confidential = TRUE)
|
||||
return
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_ranks) && task == "permissions")
|
||||
if(D.rank in GLOB.protected_ranks)
|
||||
to_chat(usr, "<span class='admin prefix'>Editing the flags of this rank is blocked by server configuration.</span>")
|
||||
to_chat(usr, "<span class='admin prefix'>Editing the flags of this rank is blocked by server configuration.</span>", confidential = TRUE)
|
||||
return
|
||||
if(CONFIG_GET(flag/load_legacy_ranks_only) && (task == "add" || task == "rank" || task == "permissions"))
|
||||
to_chat(usr, "<span class='admin prefix'>Database rank loading is disabled, only temporary changes can be made to a rank's permissions and permanently creating a new rank is blocked.</span>")
|
||||
to_chat(usr, "<span class='admin prefix'>Database rank loading is disabled, only temporary changes can be made to a rank's permissions and permanently creating a new rank is blocked.</span>", confidential = TRUE)
|
||||
legacy_only = TRUE
|
||||
if(check_rights(R_DBRANKS, FALSE))
|
||||
if(!skip)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Unable to connect to database, changes are temporary only.</span>")
|
||||
to_chat(usr, "<span class='danger'>Unable to connect to database, changes are temporary only.</span>", confidential = TRUE)
|
||||
use_db = FALSE
|
||||
else
|
||||
use_db = alert("Permanent changes are saved to the database for future rounds, temporary changes will affect only the current round", "Permanent or Temporary?", "Permanent", "Temporary", "Cancel")
|
||||
@@ -165,7 +170,6 @@
|
||||
return
|
||||
if(use_db == "Permanent")
|
||||
use_db = TRUE
|
||||
admin_ckey = sanitizeSQL(admin_ckey)
|
||||
else
|
||||
use_db = FALSE
|
||||
if(QDELETED(usr))
|
||||
@@ -209,26 +213,34 @@
|
||||
if(!.)
|
||||
return FALSE
|
||||
if(!admin_ckey && (. in GLOB.admin_datums+GLOB.deadmins))
|
||||
to_chat(usr, "<span class='danger'>[admin_key] is already an admin.</span>")
|
||||
to_chat(usr, "<span class='danger'>[admin_key] is already an admin.</span>", confidential = TRUE)
|
||||
return FALSE
|
||||
if(use_db)
|
||||
. = sanitizeSQL(.)
|
||||
//if an admin exists without a datum they won't be caught by the above
|
||||
var/datum/DBQuery/query_admin_in_db = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("admin")] WHERE ckey = '[.]'")
|
||||
var/datum/db_query/query_admin_in_db = SSdbcore.NewQuery(
|
||||
"SELECT 1 FROM [format_table_name("admin")] WHERE ckey = :ckey",
|
||||
list("ckey" = .)
|
||||
)
|
||||
if(!query_admin_in_db.warn_execute())
|
||||
qdel(query_admin_in_db)
|
||||
return FALSE
|
||||
if(query_admin_in_db.NextRow())
|
||||
qdel(query_admin_in_db)
|
||||
to_chat(usr, "<span class='danger'>[admin_key] already listed in admin database. Check the Management tab if they don't appear in the list of admins.</span>")
|
||||
to_chat(usr, "<span class='danger'>[admin_key] already listed in admin database. Check the Management tab if they don't appear in the list of admins.</span>", confidential = TRUE)
|
||||
return FALSE
|
||||
qdel(query_admin_in_db)
|
||||
var/datum/DBQuery/query_add_admin = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin")] (ckey, rank) VALUES ('[.]', 'NEW ADMIN')")
|
||||
var/datum/db_query/query_add_admin = SSdbcore.NewQuery(
|
||||
"INSERT INTO [format_table_name("admin")] (ckey, `rank`) VALUES (:ckey, 'NEW ADMIN')",
|
||||
list("ckey" = .)
|
||||
)
|
||||
if(!query_add_admin.warn_execute())
|
||||
qdel(query_add_admin)
|
||||
return FALSE
|
||||
qdel(query_add_admin)
|
||||
var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'add admin', '[.]', 'New admin added: [.]')")
|
||||
var/datum/db_query/query_add_admin_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'add admin', :target, CONCAT('New admin added: ', :target))
|
||||
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "target" = .))
|
||||
if(!query_add_admin_log.warn_execute())
|
||||
qdel(query_add_admin_log)
|
||||
return FALSE
|
||||
@@ -243,12 +255,18 @@
|
||||
var/m1 = "[key_name_admin(usr)] removed [admin_key] from the admins list [use_db ? "permanently" : "temporarily"]"
|
||||
var/m2 = "[key_name(usr)] removed [admin_key] from the admins list [use_db ? "permanently" : "temporarily"]"
|
||||
if(use_db)
|
||||
var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("DELETE FROM [format_table_name("admin")] WHERE ckey = '[admin_ckey]'")
|
||||
var/datum/db_query/query_add_rank = SSdbcore.NewQuery(
|
||||
"DELETE FROM [format_table_name("admin")] WHERE ckey = :ckey",
|
||||
list("ckey" = admin_ckey)
|
||||
)
|
||||
if(!query_add_rank.warn_execute())
|
||||
qdel(query_add_rank)
|
||||
return
|
||||
qdel(query_add_rank)
|
||||
var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'remove admin', '[admin_ckey]', 'Admin removed: [admin_ckey]')")
|
||||
var/datum/db_query/query_add_rank_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'remove admin', :admin_ckey, CONCAT('Admin removed: ', :admin_ckey))
|
||||
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "admin_ckey" = admin_ckey))
|
||||
if(!query_add_rank_log.warn_execute())
|
||||
qdel(query_add_rank_log)
|
||||
return
|
||||
@@ -271,6 +289,14 @@
|
||||
log_admin("[key_name(usr)] forcefully deadmined [admin_key]")
|
||||
D.deactivate() //after logs so the deadmined admin can see the message.
|
||||
|
||||
/datum/admins/proc/auto_deadmin()
|
||||
to_chat(owner, "<span class='interface'>You are now a normal player.</span>", confidential = TRUE)
|
||||
var/old_owner = owner
|
||||
deactivate()
|
||||
message_admins("[old_owner] deadmined via auto-deadmin config.")
|
||||
log_admin("[old_owner] deadmined via auto-deadmin config.")
|
||||
return TRUE
|
||||
|
||||
/datum/admins/proc/change_admin_rank(admin_ckey, admin_key, use_db, datum/admins/D, legacy_only)
|
||||
var/datum/admin_rank/R
|
||||
var/list/rank_names = list()
|
||||
@@ -281,7 +307,7 @@
|
||||
rank_names[R.name] = R
|
||||
var/new_rank = input("Please select a rank", "New rank") as null|anything in rank_names
|
||||
if(new_rank == "*New Rank*")
|
||||
new_rank = ckeyEx(input("Please input a new rank", "New custom rank") as text|null)
|
||||
new_rank = input("Please input a new rank", "New custom rank") as text|null
|
||||
if(!new_rank)
|
||||
return
|
||||
R = rank_names[new_rank]
|
||||
@@ -294,10 +320,12 @@
|
||||
var/m1 = "[key_name_admin(usr)] edited the admin rank of [admin_key] to [new_rank] [use_db ? "permanently" : "temporarily"]"
|
||||
var/m2 = "[key_name(usr)] edited the admin rank of [admin_key] to [new_rank] [use_db ? "permanently" : "temporarily"]"
|
||||
if(use_db)
|
||||
new_rank = sanitizeSQL(new_rank)
|
||||
//if a player was tempminned before having a permanent change made to their rank they won't yet be in the db
|
||||
var/old_rank
|
||||
var/datum/DBQuery/query_admin_in_db = SSdbcore.NewQuery("SELECT rank FROM [format_table_name("admin")] WHERE ckey = '[admin_ckey]'")
|
||||
var/datum/db_query/query_admin_in_db = SSdbcore.NewQuery(
|
||||
"SELECT `rank` FROM [format_table_name("admin")] WHERE ckey = :admin_ckey",
|
||||
list("admin_ckey" = admin_ckey)
|
||||
)
|
||||
if(!query_admin_in_db.warn_execute())
|
||||
qdel(query_admin_in_db)
|
||||
return
|
||||
@@ -308,29 +336,44 @@
|
||||
old_rank = query_admin_in_db.item[1]
|
||||
qdel(query_admin_in_db)
|
||||
//similarly if a temp rank is created it won't be in the db if someone is permanently changed to it
|
||||
var/datum/DBQuery/query_rank_in_db = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("admin_ranks")] WHERE rank = '[new_rank]'")
|
||||
var/datum/db_query/query_rank_in_db = SSdbcore.NewQuery(
|
||||
"SELECT 1 FROM [format_table_name("admin_ranks")] WHERE `rank` = :new_rank",
|
||||
list("new_rank" = new_rank)
|
||||
)
|
||||
if(!query_rank_in_db.warn_execute())
|
||||
qdel(query_rank_in_db)
|
||||
return
|
||||
if(!query_rank_in_db.NextRow())
|
||||
QDEL_NULL(query_rank_in_db)
|
||||
var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_ranks")] (rank, flags, exclude_flags, can_edit_flags) VALUES ('[new_rank]', '0', '0', '0')")
|
||||
var/datum/db_query/query_add_rank = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_ranks")] (`rank`, flags, exclude_flags, can_edit_flags)
|
||||
VALUES (:new_rank, '0', '0', '0')
|
||||
"}, list("new_rank" = new_rank))
|
||||
if(!query_add_rank.warn_execute())
|
||||
qdel(query_add_rank)
|
||||
return
|
||||
qdel(query_add_rank)
|
||||
var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'add rank', '[new_rank]', 'New rank added: [new_rank]')")
|
||||
var/datum/db_query/query_add_rank_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'add rank', :new_rank, CONCAT('New rank added: ', :new_rank))
|
||||
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "new_rank" = new_rank))
|
||||
if(!query_add_rank_log.warn_execute())
|
||||
qdel(query_add_rank_log)
|
||||
return
|
||||
qdel(query_add_rank_log)
|
||||
qdel(query_rank_in_db)
|
||||
var/datum/DBQuery/query_change_rank = SSdbcore.NewQuery("UPDATE [format_table_name("admin")] SET rank = '[new_rank]' WHERE ckey = '[admin_ckey]'")
|
||||
var/datum/db_query/query_change_rank = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("admin")] SET `rank` = :new_rank WHERE ckey = :admin_ckey",
|
||||
list("new_rank" = new_rank, "admin_ckey" = admin_ckey)
|
||||
)
|
||||
if(!query_change_rank.warn_execute())
|
||||
qdel(query_change_rank)
|
||||
return
|
||||
qdel(query_change_rank)
|
||||
var/datum/DBQuery/query_change_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'change admin rank', '[admin_ckey]', 'Rank of [admin_ckey] changed from [old_rank] to [new_rank]')")
|
||||
var/datum/db_query/query_change_rank_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'change admin rank', :target, CONCAT('Rank of ', :target, ' changed from ', :old_rank, ' to ', :new_rank))
|
||||
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "target" = admin_ckey, "old_rank" = old_rank, "new_rank" = new_rank))
|
||||
if(!query_change_rank_log.warn_execute())
|
||||
qdel(query_change_rank_log)
|
||||
return
|
||||
@@ -357,11 +400,15 @@
|
||||
return
|
||||
var/m1 = "[key_name_admin(usr)] edited the permissions of [use_db ? " rank [D.rank.name] permanently" : "[admin_key] temporarily"]"
|
||||
var/m2 = "[key_name(usr)] edited the permissions of [use_db ? " rank [D.rank.name] permanently" : "[admin_key] temporarily"]"
|
||||
if(use_db || legacy_only)
|
||||
if(use_db && !legacy_only)
|
||||
var/rank_name = D.rank.name
|
||||
var/old_flags
|
||||
var/old_exclude_flags
|
||||
var/old_can_edit_flags
|
||||
var/datum/DBQuery/query_get_rank_flags = SSdbcore.NewQuery("SELECT flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")] WHERE rank = '[D.rank.name]'")
|
||||
var/datum/db_query/query_get_rank_flags = SSdbcore.NewQuery(
|
||||
"SELECT flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")] WHERE `rank` = :rank_name",
|
||||
list("rank_name" = rank_name)
|
||||
)
|
||||
if(!query_get_rank_flags.warn_execute())
|
||||
qdel(query_get_rank_flags)
|
||||
return
|
||||
@@ -370,12 +417,19 @@
|
||||
old_exclude_flags = text2num(query_get_rank_flags.item[2])
|
||||
old_can_edit_flags = text2num(query_get_rank_flags.item[3])
|
||||
qdel(query_get_rank_flags)
|
||||
var/datum/DBQuery/query_change_rank_flags = SSdbcore.NewQuery("UPDATE [format_table_name("admin_ranks")] SET flags = '[new_flags]', exclude_flags = '[new_exclude_flags]', can_edit_flags = '[new_can_edit_flags]' WHERE rank = '[D.rank.name]'")
|
||||
var/datum/db_query/query_change_rank_flags = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("admin_ranks")] SET flags = :new_flags, exclude_flags = :new_exclude_flags, can_edit_flags = :new_can_edit_flags WHERE `rank` = :rank_name",
|
||||
list("new_flags" = new_flags, "new_exclude_flags" = new_exclude_flags, "new_can_edit_flags" = new_can_edit_flags, "rank_name" = rank_name)
|
||||
)
|
||||
if(!query_change_rank_flags.warn_execute())
|
||||
qdel(query_change_rank_flags)
|
||||
return
|
||||
qdel(query_change_rank_flags)
|
||||
var/datum/DBQuery/query_change_rank_flags_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'change rank flags', '[D.rank.name]', 'Permissions of [D.rank.name] changed from[rights2text(old_flags," ")][rights2text(old_exclude_flags," ", "-")][rights2text(old_can_edit_flags," ", "*")] to[rights2text(new_flags," ")][rights2text(new_exclude_flags," ", "-")][rights2text(new_can_edit_flags," ", "*")]')")
|
||||
var/log_message = "Permissions of [rank_name] changed from[rights2text(old_flags," ")][rights2text(old_exclude_flags," ", "-")][rights2text(old_can_edit_flags," ", "*")] to[rights2text(new_flags," ")][rights2text(new_exclude_flags," ", "-")][rights2text(new_can_edit_flags," ", "*")]"
|
||||
var/datum/db_query/query_change_rank_flags_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'change rank flags', :rank_name, :log)
|
||||
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "rank_name" = rank_name, "log" = log_message))
|
||||
if(!query_change_rank_flags_log.warn_execute())
|
||||
qdel(query_change_rank_flags_log)
|
||||
return
|
||||
@@ -418,33 +472,41 @@
|
||||
return
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
if(R.name == admin_rank && (!(R.rights & usr.client.holder.rank.can_edit_rights) == R.rights))
|
||||
to_chat(usr, "<span class='admin prefix'>You don't have edit rights to all the rights this rank has, rank deletion not permitted.</span>")
|
||||
to_chat(usr, "<span class='admin prefix'>You don't have edit rights to all the rights this rank has, rank deletion not permitted.</span>", confidential = TRUE)
|
||||
return
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_ranks) && (admin_rank in GLOB.protected_ranks))
|
||||
to_chat(usr, "<span class='admin prefix'>Deletion of protected ranks is not permitted, it must be removed from admin_ranks.txt.</span>")
|
||||
to_chat(usr, "<span class='admin prefix'>Deletion of protected ranks is not permitted, it must be removed from admin_ranks.txt.</span>", confidential = TRUE)
|
||||
return
|
||||
if(CONFIG_GET(flag/load_legacy_ranks_only))
|
||||
to_chat(usr, "<span class='admin prefix'>Rank deletion not permitted while database rank loading is disabled.</span>")
|
||||
to_chat(usr, "<span class='admin prefix'>Rank deletion not permitted while database rank loading is disabled.</span>", confidential = TRUE)
|
||||
return
|
||||
admin_rank = sanitizeSQL(admin_rank)
|
||||
var/datum/DBQuery/query_admins_with_rank = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("admin")] WHERE rank = '[admin_rank]'")
|
||||
var/datum/db_query/query_admins_with_rank = SSdbcore.NewQuery(
|
||||
"SELECT 1 FROM [format_table_name("admin")] WHERE `rank` = :admin_rank",
|
||||
list("admin_rank" = admin_rank)
|
||||
)
|
||||
if(!query_admins_with_rank.warn_execute())
|
||||
qdel(query_admins_with_rank)
|
||||
return
|
||||
if(query_admins_with_rank.NextRow())
|
||||
qdel(query_admins_with_rank)
|
||||
to_chat(usr, "<span class='danger'>Error: Rank deletion attempted while rank still used; Tell a coder, this shouldn't happen.</span>")
|
||||
to_chat(usr, "<span class='danger'>Error: Rank deletion attempted while rank still used; Tell a coder, this shouldn't happen.</span>", confidential = TRUE)
|
||||
return
|
||||
qdel(query_admins_with_rank)
|
||||
if(alert("Are you sure you want to remove [admin_rank]?","Confirm Removal","Do it","Cancel") == "Do it")
|
||||
var/m1 = "[key_name_admin(usr)] removed rank [admin_rank] permanently"
|
||||
var/m2 = "[key_name(usr)] removed rank [admin_rank] permanently"
|
||||
var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("DELETE FROM [format_table_name("admin_ranks")] WHERE rank = '[admin_rank]'")
|
||||
var/datum/db_query/query_add_rank = SSdbcore.NewQuery(
|
||||
"DELETE FROM [format_table_name("admin_ranks")] WHERE `rank` = :admin_rank",
|
||||
list("admin_rank" = admin_rank)
|
||||
)
|
||||
if(!query_add_rank.warn_execute())
|
||||
qdel(query_add_rank)
|
||||
return
|
||||
qdel(query_add_rank)
|
||||
var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'remove rank', '[admin_rank]', 'Rank removed: [admin_rank]')")
|
||||
var/datum/db_query/query_add_rank_log = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log)
|
||||
VALUES (:time, :round_id, :adminckey, INET_ATON(:adminip), 'remove rank', :admin_rank, CONCAT('Rank removed: ', :admin_rank))
|
||||
"}, list("time" = SQLtime(), "round_id" = "[GLOB.round_id]", "adminckey" = usr.ckey, "adminip" = usr.client.address, "admin_rank" = admin_rank))
|
||||
if(!query_add_rank_log.warn_execute())
|
||||
qdel(query_add_rank_log)
|
||||
return
|
||||
@@ -455,11 +517,13 @@
|
||||
/datum/admins/proc/sync_lastadminrank(admin_ckey, admin_key, datum/admins/D)
|
||||
var/sqlrank = "Player"
|
||||
if (D)
|
||||
sqlrank = sanitizeSQL(D.rank.name)
|
||||
admin_ckey = sanitizeSQL(admin_ckey)
|
||||
var/datum/DBQuery/query_sync_lastadminrank = SSdbcore.NewQuery("UPDATE [format_table_name("player")] SET lastadminrank = '[sqlrank]' WHERE ckey = '[admin_ckey]'")
|
||||
sqlrank = D.rank.name
|
||||
var/datum/db_query/query_sync_lastadminrank = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("player")] SET lastadminrank = :rank WHERE ckey = :ckey",
|
||||
list("rank" = sqlrank, "ckey" = admin_ckey)
|
||||
)
|
||||
if(!query_sync_lastadminrank.warn_execute())
|
||||
qdel(query_sync_lastadminrank)
|
||||
return
|
||||
qdel(query_sync_lastadminrank)
|
||||
to_chat(usr, "<span class='admin'>Sync of [admin_key] successful.</span>")
|
||||
to_chat(usr, "<span class='admin'>Sync of [admin_key] successful.</span>", confidential = TRUE)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/proc/create_message(type, target_key, admin_ckey, text, timestamp, server, secret, logged = 1, browse, expiry, note_severity)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>", confidential = TRUE)
|
||||
return
|
||||
if(!type)
|
||||
return
|
||||
@@ -9,8 +9,11 @@
|
||||
var/new_key = input(usr,"Who would you like to create a [type] for?","Enter a key or ckey",null) as null|text
|
||||
if(!new_key)
|
||||
return
|
||||
var/new_ckey = sanitizeSQL(ckey(new_key))
|
||||
var/datum/DBQuery/query_find_ckey = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ckey = '[new_ckey]'")
|
||||
var/new_ckey = ckey(new_key)
|
||||
var/datum/db_query/query_find_ckey = SSdbcore.NewQuery(
|
||||
"SELECT ckey FROM [format_table_name("player")] WHERE ckey = :ckey",
|
||||
list("ckey" = new_ckey)
|
||||
)
|
||||
if(!query_find_ckey.warn_execute())
|
||||
qdel(query_find_ckey)
|
||||
return
|
||||
@@ -23,29 +26,24 @@
|
||||
target_key = new_key
|
||||
if(QDELETED(usr))
|
||||
return
|
||||
if(target_ckey)
|
||||
target_ckey = sanitizeSQL(target_ckey)
|
||||
if(!target_key)
|
||||
target_key = target_ckey
|
||||
if(!admin_ckey)
|
||||
admin_ckey = usr.ckey
|
||||
if(!admin_ckey)
|
||||
return
|
||||
admin_ckey = sanitizeSQL(admin_ckey)
|
||||
if(!target_ckey)
|
||||
target_ckey = admin_ckey
|
||||
if(!text)
|
||||
text = input(usr,"Write your [type]","Create [type]") as null|message
|
||||
if(!text)
|
||||
return
|
||||
text = sanitizeSQL(text)
|
||||
if(!timestamp)
|
||||
timestamp = SQLtime()
|
||||
if(!server)
|
||||
var/ssqlname = CONFIG_GET(string/serversqlname)
|
||||
if (ssqlname)
|
||||
server = ssqlname
|
||||
server = sanitizeSQL(server)
|
||||
if(isnull(secret))
|
||||
switch(alert("Hide note from being viewed by players?", "Secret note?","Yes","No","Cancel"))
|
||||
if("Yes")
|
||||
@@ -59,15 +57,17 @@
|
||||
var/expire_time = input("Set expiry time for [type] as format YYYY-MM-DD HH:MM:SS. All times in server time. HH:MM:SS is optional and 24-hour. Must be later than current time for obvious reasons.", "Set expiry time", SQLtime()) as null|text
|
||||
if(!expire_time)
|
||||
return
|
||||
expire_time = sanitizeSQL(expire_time)
|
||||
var/datum/DBQuery/query_validate_expire_time = SSdbcore.NewQuery("SELECT IF(STR_TO_DATE('[expire_time]','%Y-%c-%d %T') > NOW(), STR_TO_DATE('[expire_time]','%Y-%c-%d %T'), 0)")
|
||||
var/datum/db_query/query_validate_expire_time = SSdbcore.NewQuery(
|
||||
"SELECT IF(STR_TO_DATE(:expire_time,'%Y-%c-%d %T') > NOW(), STR_TO_DATE(:expire_time,'%Y-%c-%d %T'), 0)",
|
||||
list("expire_time" = expire_time)
|
||||
)
|
||||
if(!query_validate_expire_time.warn_execute())
|
||||
qdel(query_validate_expire_time)
|
||||
return
|
||||
if(query_validate_expire_time.NextRow())
|
||||
var/checktime = text2num(query_validate_expire_time.item[1])
|
||||
if(!checktime)
|
||||
to_chat(usr, "Datetime entered is improperly formatted or not later than current server time.")
|
||||
to_chat(usr, "Datetime entered is improperly formatted or not later than current server time.", confidential = TRUE)
|
||||
qdel(query_validate_expire_time)
|
||||
return
|
||||
expiry = query_validate_expire_time.item[1]
|
||||
@@ -76,8 +76,23 @@
|
||||
note_severity = input("Set the severity of the note.", "Severity", null, null) as null|anything in list("High", "Medium", "Minor", "None")
|
||||
if(!note_severity)
|
||||
return
|
||||
note_severity = sanitizeSQL(note_severity)
|
||||
var/datum/DBQuery/query_create_message = SSdbcore.NewQuery("INSERT INTO [format_table_name("messages")] (type, targetckey, adminckey, text, timestamp, server, server_ip, server_port, round_id, secret, expire_timestamp, severity) VALUES ('[type]', '[target_ckey]', '[admin_ckey]', '[text]', '[timestamp]', '[server]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', '[GLOB.round_id]','[secret]', [expiry ? "'[expiry]'" : "NULL"], [note_severity ? "'[note_severity]'" : "NULL"])")
|
||||
var/datum/db_query/query_create_message = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("messages")] (type, targetckey, adminckey, text, timestamp, server, server_ip, server_port, round_id, secret, expire_timestamp, severity)
|
||||
VALUES (:type, :target_ckey, :admin_ckey, :text, :timestamp, :server, INET_ATON(:internet_address), :port, :round_id, :secret, :expiry, :note_severity)
|
||||
"}, list(
|
||||
"type" = type,
|
||||
"target_ckey" = target_ckey,
|
||||
"admin_ckey" = admin_ckey,
|
||||
"text" = text,
|
||||
"timestamp" = timestamp,
|
||||
"server" = server,
|
||||
"internet_address" = world.internet_address || "0",
|
||||
"port" = "[world.port]",
|
||||
"round_id" = GLOB.round_id,
|
||||
"secret" = secret,
|
||||
"expiry" = expiry || null,
|
||||
"note_severity" = note_severity,
|
||||
))
|
||||
var/pm = "[key_name(usr)] has created a [type][(type == "note" || type == "message" || type == "watchlist entry") ? " for [target_key]" : ""]: [text]"
|
||||
var/header = "[key_name_admin(usr)] has created a [type][(type == "note" || type == "message" || type == "watchlist entry") ? " for [target_key]" : ""]"
|
||||
if(!query_create_message.warn_execute())
|
||||
@@ -96,7 +111,7 @@
|
||||
|
||||
/proc/delete_message(message_id, logged = 1, browse)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>", confidential = TRUE)
|
||||
return
|
||||
message_id = text2num(message_id)
|
||||
if(!message_id)
|
||||
@@ -106,7 +121,11 @@
|
||||
var/text
|
||||
var/user_key_name = key_name(usr)
|
||||
var/user_name_admin = key_name_admin(usr)
|
||||
var/datum/DBQuery/query_find_del_message = SSdbcore.NewQuery("SELECT type, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), text FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0")
|
||||
var/deleted_by_ckey = usr.ckey
|
||||
var/datum/db_query/query_find_del_message = SSdbcore.NewQuery(
|
||||
"SELECT type, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), text FROM [format_table_name("messages")] WHERE id = :id AND deleted = 0",
|
||||
list("id" = message_id)
|
||||
)
|
||||
if(!query_find_del_message.warn_execute())
|
||||
qdel(query_find_del_message)
|
||||
return
|
||||
@@ -115,7 +134,10 @@
|
||||
target_key = query_find_del_message.item[2]
|
||||
text = query_find_del_message.item[3]
|
||||
qdel(query_find_del_message)
|
||||
var/datum/DBQuery/query_del_message = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET deleted = 1 WHERE id = [message_id]")
|
||||
var/datum/db_query/query_del_message = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("messages")] SET deleted = 1, deleted_ckey = :deleted_ckey WHERE id = :id",
|
||||
list("deleted_ckey" = deleted_by_ckey, "id" = message_id)
|
||||
)
|
||||
if(!query_del_message.warn_execute())
|
||||
qdel(query_del_message)
|
||||
return
|
||||
@@ -132,16 +154,24 @@
|
||||
|
||||
/proc/edit_message(message_id, browse)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>", confidential = TRUE)
|
||||
return
|
||||
message_id = text2num(message_id)
|
||||
if(!message_id)
|
||||
return
|
||||
var/editor_ckey = sanitizeSQL(usr.ckey)
|
||||
var/editor_key = sanitizeSQL(usr.key)
|
||||
var/editor_ckey = usr.ckey
|
||||
var/editor_key = usr.key
|
||||
var/kn = key_name(usr)
|
||||
var/kna = key_name_admin(usr)
|
||||
var/datum/DBQuery/query_find_edit_message = SSdbcore.NewQuery("SELECT type, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), targetckey), text FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0")
|
||||
var/datum/db_query/query_find_edit_message = SSdbcore.NewQuery({"
|
||||
SELECT
|
||||
type,
|
||||
IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey),
|
||||
IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), targetckey),
|
||||
text
|
||||
FROM [format_table_name("messages")]
|
||||
WHERE id = :id AND deleted = 0
|
||||
"}, list("id" = message_id))
|
||||
if(!query_find_edit_message.warn_execute())
|
||||
qdel(query_find_edit_message)
|
||||
return
|
||||
@@ -154,9 +184,12 @@
|
||||
if(!new_text)
|
||||
qdel(query_find_edit_message)
|
||||
return
|
||||
new_text = sanitizeSQL(new_text)
|
||||
var/edit_text = sanitizeSQL("Edited by [editor_key] on [SQLtime()] from<br>[old_text]<br>to<br>[new_text]<hr>")
|
||||
var/datum/DBQuery/query_edit_message = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET text = '[new_text]', lasteditor = '[editor_ckey]', edits = CONCAT(IFNULL(edits,''),'[edit_text]') WHERE id = [message_id] AND deleted = 0")
|
||||
var/edit_text = "Edited by [editor_key] on [SQLtime()] from<br>[old_text]<br>to<br>[new_text]<hr>"
|
||||
var/datum/db_query/query_edit_message = SSdbcore.NewQuery({"
|
||||
UPDATE [format_table_name("messages")]
|
||||
SET text = :text, lasteditor = :lasteditor, edits = CONCAT(IFNULL(edits,''),:edit_text)
|
||||
WHERE id = :id AND deleted = 0
|
||||
"}, list("text" = new_text, "lasteditor" = editor_ckey, "edit_text" = edit_text, "id" = message_id))
|
||||
if(!query_edit_message.warn_execute())
|
||||
qdel(query_edit_message)
|
||||
return
|
||||
@@ -171,16 +204,24 @@
|
||||
|
||||
/proc/edit_message_expiry(message_id, browse)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>", confidential = TRUE)
|
||||
return
|
||||
message_id = text2num(message_id)
|
||||
if(!message_id)
|
||||
return
|
||||
var/editor_ckey = sanitizeSQL(usr.ckey)
|
||||
var/editor_key = sanitizeSQL(usr.key)
|
||||
var/editor_ckey = usr.ckey
|
||||
var/editor_key = usr.key
|
||||
var/kn = key_name(usr)
|
||||
var/kna = key_name_admin(usr)
|
||||
var/datum/DBQuery/query_find_edit_expiry_message = SSdbcore.NewQuery("SELECT type, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey), expire_timestamp FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0")
|
||||
var/datum/db_query/query_find_edit_expiry_message = SSdbcore.NewQuery({"
|
||||
SELECT
|
||||
type,
|
||||
IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey),
|
||||
IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey),
|
||||
expire_timestamp
|
||||
FROM [format_table_name("messages")]
|
||||
WHERE id = :id AND deleted = 0
|
||||
"}, list("id" = message_id))
|
||||
if(!query_find_edit_expiry_message.warn_execute())
|
||||
qdel(query_find_edit_expiry_message)
|
||||
return
|
||||
@@ -197,8 +238,9 @@
|
||||
if(expire_time == "-1")
|
||||
new_expiry = "non-expiring"
|
||||
else
|
||||
expire_time = sanitizeSQL(expire_time)
|
||||
var/datum/DBQuery/query_validate_expire_time_edit = SSdbcore.NewQuery("SELECT IF(STR_TO_DATE('[expire_time]','%Y-%c-%d %T') > NOW(), STR_TO_DATE('[expire_time]','%Y-%c-%d %T'), 0)")
|
||||
var/datum/db_query/query_validate_expire_time_edit = SSdbcore.NewQuery({"
|
||||
SELECT IF(STR_TO_DATE(:expire_time,'%Y-%c-%d %T') > NOW(), STR_TO_DATE(:expire_time,'%Y-%c-%d %T'), 0)
|
||||
"}, list("expire_time" = expire_time))
|
||||
if(!query_validate_expire_time_edit.warn_execute())
|
||||
qdel(query_validate_expire_time_edit)
|
||||
qdel(query_find_edit_expiry_message)
|
||||
@@ -206,14 +248,18 @@
|
||||
if(query_validate_expire_time_edit.NextRow())
|
||||
var/checktime = text2num(query_validate_expire_time_edit.item[1])
|
||||
if(!checktime)
|
||||
to_chat(usr, "Datetime entered is improperly formatted or not later than current server time.")
|
||||
to_chat(usr, "Datetime entered is improperly formatted or not later than current server time.", confidential = TRUE)
|
||||
qdel(query_validate_expire_time_edit)
|
||||
qdel(query_find_edit_expiry_message)
|
||||
return
|
||||
new_expiry = query_validate_expire_time_edit.item[1]
|
||||
qdel(query_validate_expire_time_edit)
|
||||
var/edit_text = sanitizeSQL("Expiration time edited by [editor_key] on [SQLtime()] from [old_expiry] to [new_expiry]<hr>")
|
||||
var/datum/DBQuery/query_edit_message_expiry = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET expire_timestamp = [expire_time == "-1" ? "NULL" : "'[new_expiry]'"], lasteditor = '[editor_ckey]', edits = CONCAT(IFNULL(edits,''),'[edit_text]') WHERE id = [message_id] AND deleted = 0")
|
||||
var/edit_text = "Expiration time edited by [editor_key] on [SQLtime()] from [old_expiry] to [new_expiry]<hr>"
|
||||
var/datum/db_query/query_edit_message_expiry = SSdbcore.NewQuery({"
|
||||
UPDATE [format_table_name("messages")]
|
||||
SET expire_timestamp = :expire_time, lasteditor = :lasteditor, edits = CONCAT(IFNULL(edits,''),:edit_text)
|
||||
WHERE id = :id AND deleted = 0
|
||||
"}, list("expire_time" = (expire_time == "-1" ? null : new_expiry), "lasteditor" = editor_ckey, "edit_text" = edit_text, "id" = message_id))
|
||||
if(!query_edit_message_expiry.warn_execute())
|
||||
qdel(query_edit_message_expiry)
|
||||
qdel(query_find_edit_expiry_message)
|
||||
@@ -229,14 +275,22 @@
|
||||
|
||||
/proc/edit_message_severity(message_id)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>", confidential = TRUE)
|
||||
return
|
||||
message_id = text2num(message_id)
|
||||
if(!message_id)
|
||||
return
|
||||
var/kn = key_name(usr)
|
||||
var/kna = key_name_admin(usr)
|
||||
var/datum/DBQuery/query_find_edit_note_severity = SSdbcore.NewQuery("SELECT type, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey), severity FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0")
|
||||
var/datum/db_query/query_find_edit_note_severity = SSdbcore.NewQuery({"
|
||||
SELECT
|
||||
type,
|
||||
IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey),
|
||||
IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey),
|
||||
severity
|
||||
FROM [format_table_name("messages")]
|
||||
WHERE id = :id AND deleted = 0
|
||||
"}, list("id" = message_id))
|
||||
if(!query_find_edit_note_severity.warn_execute())
|
||||
qdel(query_find_edit_note_severity)
|
||||
return
|
||||
@@ -247,15 +301,19 @@
|
||||
var/old_severity = query_find_edit_note_severity.item[4]
|
||||
if(!old_severity)
|
||||
old_severity = "NA"
|
||||
var/editor_key = sanitizeSQL(usr.key)
|
||||
var/editor_ckey = sanitizeSQL(usr.ckey)
|
||||
var/editor_key = usr.key
|
||||
var/editor_ckey = usr.ckey
|
||||
var/new_severity = input("Set the severity of the note.", "Severity", null, null) as null|anything in list("high", "medium", "minor", "none") //lowercase for edit log consistency
|
||||
if(!new_severity)
|
||||
qdel(query_find_edit_note_severity)
|
||||
return
|
||||
new_severity = sanitizeSQL(new_severity)
|
||||
var/edit_text = sanitizeSQL("Note severity edited by [editor_key] on [SQLtime()] from [old_severity] to [new_severity]<hr>")
|
||||
var/datum/DBQuery/query_edit_note_severity = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET severity = '[new_severity]', lasteditor = '[editor_ckey]', edits = CONCAT(IFNULL(edits,''),'[edit_text]') WHERE id = [message_id] AND deleted = 0")
|
||||
new_severity = new_severity
|
||||
var/edit_text = "Note severity edited by [editor_key] on [SQLtime()] from [old_severity] to [new_severity]<hr>"
|
||||
var/datum/db_query/query_edit_note_severity = SSdbcore.NewQuery({"
|
||||
UPDATE [format_table_name("messages")]
|
||||
SET severity = :severity, lasteditor = :lasteditor, edits = CONCAT(IFNULL(edits,''),:edit_text)
|
||||
WHERE id = :id AND deleted = 0
|
||||
"}, list("severity" = new_severity, "lasteditor" = editor_ckey, "edit_text" = edit_text, "id" = message_id))
|
||||
if(!query_edit_note_severity.warn_execute(async = TRUE))
|
||||
qdel(query_edit_note_severity)
|
||||
qdel(qdel(query_find_edit_note_severity))
|
||||
@@ -268,16 +326,24 @@
|
||||
|
||||
/proc/toggle_message_secrecy(message_id)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>", confidential = TRUE)
|
||||
return
|
||||
message_id = text2num(message_id)
|
||||
if(!message_id)
|
||||
return
|
||||
var/editor_ckey = sanitizeSQL(usr.ckey)
|
||||
var/editor_key = sanitizeSQL(usr.key)
|
||||
var/editor_ckey = usr.ckey
|
||||
var/editor_key = usr.key
|
||||
var/kn = key_name(usr)
|
||||
var/kna = key_name_admin(usr)
|
||||
var/datum/DBQuery/query_find_message_secret = SSdbcore.NewQuery("SELECT type, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), targetckey), secret FROM [format_table_name("messages")] WHERE id = [message_id] AND deleted = 0")
|
||||
var/datum/db_query/query_find_message_secret = SSdbcore.NewQuery({"
|
||||
SELECT
|
||||
type,
|
||||
IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey),
|
||||
IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), targetckey),
|
||||
secret
|
||||
FROM [format_table_name("messages")]
|
||||
WHERE id = :id AND deleted = 0
|
||||
"}, list("id" = message_id))
|
||||
if(!query_find_message_secret.warn_execute())
|
||||
qdel(query_find_message_secret)
|
||||
return
|
||||
@@ -287,7 +353,11 @@
|
||||
var/admin_key = query_find_message_secret.item[3]
|
||||
var/secret = text2num(query_find_message_secret.item[4])
|
||||
var/edit_text = "Made [secret ? "not secret" : "secret"] by [editor_key] on [SQLtime()]<hr>"
|
||||
var/datum/DBQuery/query_message_secret = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET secret = NOT secret, lasteditor = '[editor_ckey]', edits = CONCAT(IFNULL(edits,''),'[edit_text]') WHERE id = [message_id]")
|
||||
var/datum/db_query/query_message_secret = SSdbcore.NewQuery({"
|
||||
UPDATE [format_table_name("messages")]
|
||||
SET secret = NOT secret, lasteditor = :lasteditor, edits = CONCAT(IFNULL(edits,''),:edit_text)
|
||||
WHERE id = :id
|
||||
"}, list("lasteditor" = editor_ckey, "edit_text" = edit_text, "id" = message_id))
|
||||
if(!query_message_secret.warn_execute())
|
||||
qdel(query_find_message_secret)
|
||||
qdel(query_message_secret)
|
||||
@@ -298,11 +368,9 @@
|
||||
browse_messages(target_ckey = ckey(target_key), agegate = TRUE)
|
||||
qdel(query_find_message_secret)
|
||||
|
||||
/proc/browse_messages(type, target_ckey, index, linkless = FALSE, filter, agegate = FALSE, override = FALSE)
|
||||
if((!override || IsAdminAdvancedProcCall()) && !check_rights(R_SENSITIVE))
|
||||
return
|
||||
/proc/browse_messages(type, target_ckey, index, linkless = FALSE, filter, agegate = FALSE)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>", confidential = TRUE)
|
||||
return
|
||||
var/list/output = list()
|
||||
var/ruler = "<hr style='background:#000000; border:0; height:3px'>"
|
||||
@@ -329,7 +397,20 @@
|
||||
else
|
||||
output += "<a href='?_src_=holder;[HrefToken()];showwatchfilter=1'>Filter offline clients</a></center>"
|
||||
output += ruler
|
||||
var/datum/DBQuery/query_get_type_messages = SSdbcore.NewQuery("SELECT id, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), targetckey, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey), text, timestamp, server, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = lasteditor), lasteditor), expire_timestamp FROM [format_table_name("messages")] WHERE type = '[type]' AND deleted = 0 AND (expire_timestamp > NOW() OR expire_timestamp IS NULL)")
|
||||
var/datum/db_query/query_get_type_messages = SSdbcore.NewQuery({"
|
||||
SELECT
|
||||
id,
|
||||
IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey),
|
||||
targetckey,
|
||||
IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey),
|
||||
text,
|
||||
timestamp,
|
||||
server,
|
||||
IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = lasteditor), lasteditor),
|
||||
expire_timestamp
|
||||
FROM [format_table_name("messages")]
|
||||
WHERE type = :type AND deleted = 0 AND (expire_timestamp > NOW() OR expire_timestamp IS NULL)
|
||||
"}, list("type" = type))
|
||||
if(!query_get_type_messages.warn_execute())
|
||||
qdel(query_get_type_messages)
|
||||
return
|
||||
@@ -362,9 +443,24 @@
|
||||
output += "<br>[text]<hr style='background:#000000; border:0; height:1px'>"
|
||||
qdel(query_get_type_messages)
|
||||
if(target_ckey)
|
||||
target_ckey = sanitizeSQL(target_ckey)
|
||||
var/target_key
|
||||
var/datum/DBQuery/query_get_messages = SSdbcore.NewQuery("SELECT type, secret, id, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey), text, timestamp, server, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = lasteditor), lasteditor), DATEDIFF(NOW(), timestamp), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey), expire_timestamp, severity FROM [format_table_name("messages")] WHERE type <> 'memo' AND targetckey = '[target_ckey]' AND deleted = 0 AND (expire_timestamp > NOW() OR expire_timestamp IS NULL) ORDER BY timestamp DESC")
|
||||
var/datum/db_query/query_get_messages = SSdbcore.NewQuery({"
|
||||
SELECT
|
||||
type,
|
||||
secret,
|
||||
id,
|
||||
IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey),
|
||||
text,
|
||||
timestamp,
|
||||
server,
|
||||
IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = lasteditor), lasteditor),
|
||||
DATEDIFF(NOW(), timestamp),
|
||||
IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey), targetckey),
|
||||
expire_timestamp, severity
|
||||
FROM [format_table_name("messages")]
|
||||
WHERE type <> 'memo' AND targetckey = :targetckey AND deleted = 0 AND (expire_timestamp > NOW() OR expire_timestamp IS NULL)
|
||||
ORDER BY timestamp DESC
|
||||
"}, list("targetckey" = target_ckey))
|
||||
if(!query_get_messages.warn_execute())
|
||||
qdel(query_get_messages)
|
||||
return
|
||||
@@ -442,7 +538,9 @@
|
||||
notedata += data
|
||||
qdel(query_get_messages)
|
||||
if(!target_key)
|
||||
var/datum/DBQuery/query_get_message_key = SSdbcore.NewQuery("SELECT byond_key FROM [format_table_name("player")] WHERE ckey = '[target_ckey]'")
|
||||
var/datum/db_query/query_get_message_key = SSdbcore.NewQuery({"
|
||||
SELECT byond_key FROM [format_table_name("player")] WHERE ckey = :ckey
|
||||
"}, list("ckey" = target_ckey))
|
||||
if(!query_get_message_key.warn_execute())
|
||||
qdel(query_get_message_key)
|
||||
return
|
||||
@@ -479,8 +577,6 @@
|
||||
var/search
|
||||
output += "<center><a href='?_src_=holder;[HrefToken()];addmessageempty=1'>Add message</a><a href='?_src_=holder;[HrefToken()];addwatchempty=1'>Add watchlist entry</a><a href='?_src_=holder;[HrefToken()];addnoteempty=1'>Add note</a></center>"
|
||||
output += ruler
|
||||
if(!isnum(index))
|
||||
index = sanitizeSQL(index)
|
||||
switch(index)
|
||||
if(1)
|
||||
search = "^."
|
||||
@@ -488,7 +584,17 @@
|
||||
search = "^\[^\[:alpha:\]\]"
|
||||
else
|
||||
search = "^[index]"
|
||||
var/datum/DBQuery/query_list_messages = SSdbcore.NewQuery("SELECT DISTINCT targetckey, (SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey) FROM [format_table_name("messages")] WHERE type <> 'memo' AND targetckey REGEXP '[search]' AND deleted = 0 AND (expire_timestamp > NOW() OR expire_timestamp IS NULL) ORDER BY targetckey")
|
||||
var/datum/db_query/query_list_messages = SSdbcore.NewQuery({"
|
||||
SELECT DISTINCT
|
||||
targetckey,
|
||||
(SELECT byond_key FROM [format_table_name("player")] WHERE ckey = targetckey)
|
||||
FROM [format_table_name("messages")]
|
||||
WHERE type <> 'memo'
|
||||
AND targetckey REGEXP :search
|
||||
AND deleted = 0
|
||||
AND (expire_timestamp > NOW() OR expire_timestamp IS NULL)
|
||||
ORDER BY targetckey
|
||||
"}, list("search" = search))
|
||||
if(!query_list_messages.warn_execute())
|
||||
qdel(query_list_messages)
|
||||
return
|
||||
@@ -512,17 +618,24 @@
|
||||
|
||||
/proc/get_message_output(type, target_ckey)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>", confidential = TRUE)
|
||||
return
|
||||
if(!type)
|
||||
return
|
||||
var/output
|
||||
if(target_ckey)
|
||||
target_ckey = sanitizeSQL(target_ckey)
|
||||
var/query = "SELECT id, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey), text, timestamp, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = lasteditor), lasteditor) FROM [format_table_name("messages")] WHERE type = '[type]' AND deleted = 0 AND (expire_timestamp > NOW() OR expire_timestamp IS NULL)"
|
||||
if(type == "message" || type == "watchlist entry")
|
||||
query += " AND targetckey = '[target_ckey]'"
|
||||
var/datum/DBQuery/query_get_message_output = SSdbcore.NewQuery(query)
|
||||
var/datum/db_query/query_get_message_output = SSdbcore.NewQuery({"
|
||||
SELECT
|
||||
id,
|
||||
IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey),
|
||||
text,
|
||||
timestamp,
|
||||
IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = lasteditor), lasteditor)
|
||||
FROM [format_table_name("messages")]
|
||||
WHERE type = :type
|
||||
AND deleted = 0
|
||||
AND (expire_timestamp > NOW() OR expire_timestamp IS NULL)
|
||||
AND ((type != 'message' AND type != 'watchlist entry') OR targetckey = :targetckey)
|
||||
"}, list("targetckey" = target_ckey, "type" = type))
|
||||
if(!query_get_message_output.warn_execute())
|
||||
qdel(query_get_message_output)
|
||||
return
|
||||
@@ -536,7 +649,10 @@
|
||||
if("message")
|
||||
output += "<font color='red' size='3'><b>Admin message left by <span class='prefix'>[admin_key]</span> on [timestamp]</b></font>"
|
||||
output += "<br><font color='red'>[text]</font><br>"
|
||||
var/datum/DBQuery/query_message_read = SSdbcore.NewQuery("UPDATE [format_table_name("messages")] SET type = 'message sent' WHERE id = [message_id]")
|
||||
var/datum/db_query/query_message_read = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("messages")] SET type = 'message sent' WHERE id = :id",
|
||||
list("id" = message_id)
|
||||
)
|
||||
if(!query_message_read.warn_execute())
|
||||
qdel(query_get_message_output)
|
||||
qdel(query_message_read)
|
||||
@@ -544,7 +660,7 @@
|
||||
qdel(query_message_read)
|
||||
if("watchlist entry")
|
||||
message_admins("<font color='red'><B>Notice: </B></font><font color='blue'>[key_name_admin(target_ckey)] has been on the watchlist since [timestamp] and has just connected - Reason: [text]</font>")
|
||||
send2irc_adminless_only("Watchlist", "[key_name(target_ckey)] is on the watchlist and has just connected - Reason: [text]")
|
||||
send2tgs_adminless_only("Watchlist", "[key_name(target_ckey)] is on the watchlist and has just connected - Reason: [text]")
|
||||
if("memo")
|
||||
output += "<span class='memo'>Memo by <span class='prefix'>[admin_key]</span> on [timestamp]"
|
||||
if(editor_key)
|
||||
@@ -576,7 +692,7 @@
|
||||
var/timestamp = note.group[1]
|
||||
notetext = note.group[2]
|
||||
var/admin_ckey = note.group[3]
|
||||
var/datum/DBQuery/query_convert_time = SSdbcore.NewQuery("SELECT ADDTIME(STR_TO_DATE('[timestamp]','%d-%b-%Y'), '0')")
|
||||
var/datum/db_query/query_convert_time = SSdbcore.NewQuery("SELECT ADDTIME(STR_TO_DATE(:timestamp,'%d-%b-%Y'), '0')", list("timestamp" = timestamp))
|
||||
if(!query_convert_time.Execute())
|
||||
qdel(query_convert_time)
|
||||
return
|
||||
@@ -591,7 +707,7 @@
|
||||
/*alternatively this proc can be run once to pass through every note and attempt to convert it before deleting the file, if done then AUTOCONVERT_NOTES should be turned off
|
||||
this proc can take several minutes to execute fully if converting and cause DD to hang if converting a lot of notes; it's not advised to do so while a server is live
|
||||
/proc/mass_convert_notes()
|
||||
to_chat(world, "Beginning mass note conversion")
|
||||
to_chat(world, "Beginning mass note conversion", confidential = TRUE)
|
||||
var/savefile/notesfile = new(NOTESFILE)
|
||||
if(!notesfile)
|
||||
log_game("Error: Cannot access [NOTESFILE]")
|
||||
@@ -599,7 +715,7 @@ this proc can take several minutes to execute fully if converting and cause DD t
|
||||
notesfile.cd = "/"
|
||||
for(var/ckey in notesfile.dir)
|
||||
convert_notes_sql(ckey)
|
||||
to_chat(world, "Deleting NOTESFILE")
|
||||
to_chat(world, "Deleting NOTESFILE", confidential = TRUE)
|
||||
fdel(NOTESFILE)
|
||||
to_chat(world, "Finished mass note conversion, remember to turn off AUTOCONVERT_NOTES")*/
|
||||
to_chat(world, "Finished mass note conversion, remember to turn off AUTOCONVERT_NOTES", confidential = TRUE)*/
|
||||
#undef NOTESFILE
|
||||
|
||||
@@ -32,15 +32,11 @@
|
||||
return
|
||||
ban["message"] = "[reason]"
|
||||
|
||||
if(SSdbcore.Connect()) // todo: second wave
|
||||
// var/datum/db_query/query_create_stickyban = SSdbcore.NewQuery({"
|
||||
// INSERT INTO [format_table_name("stickyban")] (ckey, reason, banning_admin)
|
||||
// VALUES (:ckey, :message, :banning_admin)
|
||||
// "}, list("ckey" = ckey, "message" = ban["message"], "banning_admin" = usr.ckey))
|
||||
var/datum/DBQuery/query_create_stickyban = SSdbcore.NewQuery({"
|
||||
if(SSdbcore.Connect())
|
||||
var/datum/db_query/query_create_stickyban = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("stickyban")] (ckey, reason, banning_admin)
|
||||
VALUES ([ckey], [ban["message"]], [usr.ckey])
|
||||
"})
|
||||
VALUES (:ckey, :message, :banning_admin)
|
||||
"}, list("ckey" = ckey, "message" = ban["message"], "banning_admin" = usr.ckey))
|
||||
if (query_create_stickyban.warn_execute())
|
||||
ban["fromdb"] = TRUE
|
||||
qdel(query_create_stickyban)
|
||||
@@ -74,19 +70,14 @@
|
||||
SSstickyban.cache -= ckey
|
||||
|
||||
if (SSdbcore.Connect())
|
||||
// SSdbcore.QuerySelect(list(
|
||||
// SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban")] WHERE ckey = :ckey", list("ckey" = ckey)),
|
||||
// SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = :ckey", list("ckey" = ckey)),
|
||||
// SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_cid")] WHERE stickyban = :ckey", list("ckey" = ckey)),
|
||||
// SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ip")] WHERE stickyban = :ckey", list("ckey" = ckey))
|
||||
// ), warn = TRUE, qdel = TRUE)
|
||||
SSdbcore.QuerySelect(list(
|
||||
SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban")] WHERE ckey = [ckey]"),
|
||||
SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = [ckey]"),
|
||||
SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_cid")] WHERE stickyban = [ckey]"),
|
||||
SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ip")] WHERE stickyban = [ckey]")
|
||||
SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban")] WHERE ckey = :ckey", list("ckey" = ckey)),
|
||||
SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = :ckey", list("ckey" = ckey)),
|
||||
SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_cid")] WHERE stickyban = :ckey", list("ckey" = ckey)),
|
||||
SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ip")] WHERE stickyban = :ckey", list("ckey" = ckey))
|
||||
), warn = TRUE, qdel = TRUE)
|
||||
|
||||
|
||||
log_admin_private("[key_name(usr)] removed [ckey]'s stickyban")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] removed [ckey]'s stickyban</span>")
|
||||
|
||||
@@ -128,12 +119,9 @@
|
||||
SSstickyban.cache[ckey] = ban
|
||||
|
||||
if (SSdbcore.Connect())
|
||||
// var/datum/db_query/query_remove_stickyban_alt = SSdbcore.NewQuery(
|
||||
// "DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = :ckey AND matched_ckey = :alt",
|
||||
// list("ckey" = ckey, "alt" = alt)
|
||||
// )
|
||||
var/datum/DBQuery/query_remove_stickyban_alt = SSdbcore.NewQuery(
|
||||
"DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = [ckey] AND matched_ckey = [alt]"
|
||||
var/datum/db_query/query_remove_stickyban_alt = SSdbcore.NewQuery(
|
||||
"DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = :ckey AND matched_ckey = :alt",
|
||||
list("ckey" = ckey, "alt" = alt)
|
||||
)
|
||||
query_remove_stickyban_alt.warn_execute()
|
||||
qdel(query_remove_stickyban_alt)
|
||||
@@ -165,12 +153,9 @@
|
||||
SSstickyban.cache[ckey] = ban
|
||||
|
||||
if (SSdbcore.Connect())
|
||||
// var/datum/db_query/query_edit_stickyban = SSdbcore.NewQuery(
|
||||
// "UPDATE [format_table_name("stickyban")] SET reason = :reason WHERE ckey = :ckey",
|
||||
// list("reason" = reason, "ckey" = ckey)
|
||||
// )
|
||||
var/datum/DBQuery/query_edit_stickyban = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("stickyban")] SET reason = [reason] WHERE ckey = [ckey]"
|
||||
var/datum/db_query/query_edit_stickyban = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("stickyban")] SET reason = :reason WHERE ckey = :ckey",
|
||||
list("reason" = reason, "ckey" = ckey)
|
||||
)
|
||||
query_edit_stickyban.warn_execute()
|
||||
qdel(query_edit_stickyban)
|
||||
@@ -218,12 +203,9 @@
|
||||
SSstickyban.cache[ckey] = ban
|
||||
|
||||
if (SSdbcore.Connect())
|
||||
// var/datum/db_query/query_exempt_stickyban_alt = SSdbcore.NewQuery(
|
||||
// "UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 1 WHERE stickyban = :ckey AND matched_ckey = :alt",
|
||||
// list("ckey" = ckey, "alt" = alt)
|
||||
// )
|
||||
var/datum/DBQuery/query_exempt_stickyban_alt = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 1 WHERE stickyban = [ckey] AND matched_ckey = [alt]"
|
||||
var/datum/db_query/query_exempt_stickyban_alt = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 1 WHERE stickyban = :ckey AND matched_ckey = :alt",
|
||||
list("ckey" = ckey, "alt" = alt)
|
||||
)
|
||||
query_exempt_stickyban_alt.warn_execute()
|
||||
qdel(query_exempt_stickyban_alt)
|
||||
@@ -271,12 +253,9 @@
|
||||
SSstickyban.cache[ckey] = ban
|
||||
|
||||
if (SSdbcore.Connect())
|
||||
// var/datum/db_query/query_unexempt_stickyban_alt = SSdbcore.NewQuery(
|
||||
// "UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 0 WHERE stickyban = :ckey AND matched_ckey = :alt",
|
||||
// list("ckey" = ckey, "alt" = alt)
|
||||
// )
|
||||
var/datum/DBQuery/query_unexempt_stickyban_alt = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 0 WHERE stickyban = [ckey] AND matched_ckey = [alt]"
|
||||
var/datum/db_query/query_unexempt_stickyban_alt = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 0 WHERE stickyban = :ckey AND matched_ckey = :alt",
|
||||
list("ckey" = ckey, "alt" = alt)
|
||||
)
|
||||
query_unexempt_stickyban_alt.warn_execute()
|
||||
qdel(query_unexempt_stickyban_alt)
|
||||
|
||||
@@ -1269,8 +1269,10 @@
|
||||
else if(href_list["messageedits"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/message_id = sanitizeSQL("[href_list["messageedits"]]")
|
||||
var/datum/DBQuery/query_get_message_edits = SSdbcore.NewQuery("SELECT edits FROM [format_table_name("messages")] WHERE id = '[message_id]'")
|
||||
var/datum/db_query/query_get_message_edits = SSdbcore.NewQuery(
|
||||
"SELECT edits FROM [format_table_name("messages")] WHERE id = :message_id",
|
||||
list("message_id" = href_list["messageedits"])
|
||||
)
|
||||
if(!query_get_message_edits.warn_execute())
|
||||
qdel(query_get_message_edits)
|
||||
return
|
||||
@@ -2967,16 +2969,19 @@
|
||||
to_chat(usr, "<span class='danger'>The client chosen is an admin! Cannot mentorize.</span>")
|
||||
return
|
||||
if(SSdbcore.Connect())
|
||||
var/datum/DBQuery/query_get_mentor = SSdbcore.NewQuery("SELECT id FROM [format_table_name("mentor")] WHERE ckey = '[ckey]'")
|
||||
var/datum/db_query/query_get_mentor = SSdbcore.NewQuery(
|
||||
"SELECT id FROM [format_table_name("mentor")] WHERE ckey = :ckey",
|
||||
list("ckey" = ckey)
|
||||
)
|
||||
if(!query_get_mentor.warn_execute())
|
||||
return
|
||||
if(query_get_mentor.NextRow())
|
||||
to_chat(usr, "<span class='danger'>[ckey] is already a mentor.</span>")
|
||||
return
|
||||
var/datum/DBQuery/query_add_mentor = SSdbcore.NewQuery("INSERT INTO `[format_table_name("mentor")]` (`id`, `ckey`) VALUES (null, '[ckey]')")
|
||||
var/datum/db_query/query_add_mentor = SSdbcore.NewQuery("INSERT INTO `[format_table_name("mentor")]` (`id`, `ckey`) VALUES (null, '[ckey]')")
|
||||
if(!query_add_mentor.warn_execute())
|
||||
return
|
||||
var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO `[format_table_name("admin_log")]` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added new mentor [ckey]');")
|
||||
var/datum/db_query/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO `[format_table_name("admin_log")]` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added new mentor [ckey]');")
|
||||
if(!query_add_admin_log.warn_execute())
|
||||
return
|
||||
else
|
||||
@@ -3000,10 +3005,10 @@
|
||||
C.mentor_datum = null
|
||||
GLOB.mentors -= C
|
||||
if(SSdbcore.Connect())
|
||||
var/datum/DBQuery/query_remove_mentor = SSdbcore.NewQuery("DELETE FROM [format_table_name("mentor")] WHERE ckey = '[ckey]'")
|
||||
var/datum/db_query/query_remove_mentor = SSdbcore.NewQuery("DELETE FROM [format_table_name("mentor")] WHERE ckey = '[ckey]'")
|
||||
if(!query_remove_mentor.warn_execute())
|
||||
return
|
||||
var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO `[format_table_name("admin_log")]` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Removed mentor [ckey]');")
|
||||
var/datum/db_query/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO `[format_table_name("admin_log")]` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Removed mentor [ckey]');")
|
||||
if(!query_add_admin_log.warn_execute())
|
||||
return
|
||||
else
|
||||
|
||||
@@ -205,7 +205,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
MessageNoRecipient(msg)
|
||||
|
||||
//send it to irc if nobody is on and tell us how many were on
|
||||
var/admin_number_present = send2irc_adminless_only(initiator_ckey, "Ticket #[id]: [name]")
|
||||
var/admin_number_present = send2tgs_adminless_only(initiator_ckey, "Ticket #[id]: [name]")
|
||||
log_admin_private("Ticket #[id]: [key_name(initiator)]: [name] - heard by [admin_number_present] non-AFK admins who have +BAN.")
|
||||
if(admin_number_present <= 0)
|
||||
to_chat(C, "<span class='notice'>No active admins are online, your adminhelp was sent to the admin irc.</span>")
|
||||
@@ -222,7 +222,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
/datum/admin_help/proc/AddInteraction(formatted_message)
|
||||
if(heard_by_no_admins && usr && usr.ckey != initiator_ckey)
|
||||
heard_by_no_admins = FALSE
|
||||
send2irc(initiator_ckey, "Ticket #[id]: Answered by [key_name(usr)]")
|
||||
send2adminchat(initiator_ckey, "Ticket #[id]: Answered by [key_name(usr)]")
|
||||
_interactions += "[TIME_STAMP("hh:mm:ss", FALSE)]: [formatted_message]"
|
||||
|
||||
//Removes the ahelp verb and returns it after 2 minutes
|
||||
@@ -573,7 +573,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
. = list("total" = list(), "noflags" = list(), "afk" = list(), "stealth" = list(), "present" = list())
|
||||
for(var/client/X in GLOB.admins)
|
||||
.["total"] += X
|
||||
if(requiredflags != 0 && !check_rights_for(X, requiredflags))
|
||||
if(requiredflags != NONE && !check_rights_for(X, requiredflags))
|
||||
.["noflags"] += X
|
||||
else if(X.is_afk())
|
||||
.["afk"] += X
|
||||
@@ -582,7 +582,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
else
|
||||
.["present"] += X
|
||||
|
||||
/proc/send2irc_adminless_only(source, msg, requiredflags = R_BAN)
|
||||
/proc/send2tgs_adminless_only(source, msg, requiredflags = R_BAN)
|
||||
var/list/adm = get_admin_counts(requiredflags)
|
||||
var/list/activemins = adm["present"]
|
||||
. = activemins.len
|
||||
@@ -596,15 +596,9 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
final = "[msg] - No admins online"
|
||||
else
|
||||
final = "[msg] - All admins stealthed\[[english_list(stealthmins)]\], AFK\[[english_list(afkmins)]\], or lacks +BAN\[[english_list(powerlessmins)]\]! Total: [allmins.len] "
|
||||
send2irc(source,final)
|
||||
send2adminchat(source,final)
|
||||
send2otherserver(source,final)
|
||||
|
||||
|
||||
/proc/send2irc(msg,msg2)
|
||||
msg = replacetext(replacetext(msg, "\proper", ""), "\improper", "")
|
||||
msg2 = replacetext(replacetext(msg2, "\proper", ""), "\improper", "")
|
||||
world.TgsTargetedChatBroadcast("[msg] | [msg2]", TRUE)
|
||||
|
||||
/**
|
||||
* Sends a message to a set of cross-communications-enabled servers using world topic calls
|
||||
*
|
||||
@@ -648,6 +642,10 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
if (!server_url)
|
||||
CRASH("Invalid cross comms config: [server_name]")
|
||||
world.Export("[server_url]?[list2params(message)]")
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
|
||||
>>>>>>> origin/master
|
||||
|
||||
/proc/ircadminwho()
|
||||
var/list/message = list("Admins: ")
|
||||
|
||||
@@ -165,7 +165,7 @@
|
||||
to_chat(src, "<span class='notice'>PM to-<b>Admins</b>: <span class='linkify'>[rawmsg]</span></span>", confidential = TRUE)
|
||||
var/datum/admin_help/AH = admin_ticket_log(src, "<font color='red'>Reply PM from-<b>[key_name(src, TRUE, TRUE)]</b> to <i>External</i>: [keywordparsedmsg]</font>")
|
||||
ircreplyamount--
|
||||
send2irc("[AH ? "#[AH.id] " : ""]Reply: [ckey]", rawmsg)
|
||||
send2adminchat("[AH ? "#[AH.id] " : ""]Reply: [ckey]", rawmsg)
|
||||
|
||||
else
|
||||
var/badmin = FALSE //Lets figure out if an admin is getting bwoinked.
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
if (new_pb && !SSdbcore.Connect())
|
||||
message_admins("The Database is not connected! Panic bunker will not work until the connection is reestablished.")
|
||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Panic Bunker", "[new_pb ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
send2irc("Panic Bunker", "[key_name(usr)] has toggled the Panic Bunker, it is now [new_pb ? "enabled" : "disabled"].")
|
||||
send2adminchat("Panic Bunker", "[key_name(usr)] has toggled the Panic Bunker, it is now [new_pb ? "enabled" : "disabled"].")
|
||||
|
||||
/client/proc/addbunkerbypass(ckeytobypass as text)
|
||||
set category = "Special Verbs"
|
||||
@@ -28,7 +28,7 @@
|
||||
SSpersistence.SavePanicBunker() //we can do this every time, it's okay
|
||||
log_admin("[key_name(usr)] has added [ckeytobypass] to the current round's bunker bypass list.")
|
||||
message_admins("[key_name_admin(usr)] has added [ckeytobypass] to the current round's bunker bypass list.")
|
||||
send2irc("Panic Bunker", "[key_name(usr)] has added [ckeytobypass] to the current round's bunker bypass list.")
|
||||
send2adminchat("Panic Bunker", "[key_name(usr)] has added [ckeytobypass] to the current round's bunker bypass list.")
|
||||
|
||||
/client/proc/revokebunkerbypass(ckeytobypass as text)
|
||||
set category = "Special Verbs"
|
||||
@@ -42,4 +42,4 @@
|
||||
SSpersistence.SavePanicBunker()
|
||||
log_admin("[key_name(usr)] has removed [ckeytobypass] from the current round's bunker bypass list.")
|
||||
message_admins("[key_name_admin(usr)] has removed [ckeytobypass] from the current round's bunker bypass list.")
|
||||
send2irc("Panic Bunker", "[key_name(usr)] has removed [ckeytobypass] from the current round's bunker bypass list.")
|
||||
send2adminchat("Panic Bunker", "[key_name(usr)] has removed [ckeytobypass] from the current round's bunker bypass list.")
|
||||
|
||||
@@ -433,31 +433,21 @@
|
||||
destroy_objective.find_target()
|
||||
objectives += destroy_objective
|
||||
else
|
||||
if(prob(70))
|
||||
var/datum/objective/assassinate/once/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
if(team_mode) //No backstabbing while in a team
|
||||
kill_objective.find_target_by_role(role = ROLE_CHANGELING, role_type = 1, invert = 1)
|
||||
else
|
||||
kill_objective.find_target()
|
||||
objectives += kill_objective
|
||||
|
||||
/*else
|
||||
var/datum/objective/maroon/maroon_objective = new
|
||||
maroon_objective.owner = owner
|
||||
if(team_mode)
|
||||
maroon_objective.find_target_by_role(role = ROLE_CHANGELING, role_type = 1, invert = 1)
|
||||
else
|
||||
maroon_objective.find_target()
|
||||
objectives += maroon_objective*/
|
||||
var/datum/objective/assassinate/once/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
if(team_mode) //No backstabbing while in a team
|
||||
kill_objective.find_target_by_role(role = ROLE_CHANGELING, role_type = 1, invert = 1)
|
||||
else
|
||||
kill_objective.find_target()
|
||||
objectives += kill_objective
|
||||
|
||||
if (!(locate(/datum/objective/escape) in objectives) && escape_objective_possible)
|
||||
var/datum/objective/escape/escape_with_identity/identity_theft = new
|
||||
identity_theft.owner = owner
|
||||
identity_theft.target = kill_objective.target
|
||||
identity_theft.update_explanation_text()
|
||||
objectives += identity_theft
|
||||
escape_objective_possible = FALSE
|
||||
if(!(locate(/datum/objective/escape) in objectives) && escape_objective_possible && prob(50))
|
||||
var/datum/objective/escape/escape_with_identity/identity_theft = new
|
||||
identity_theft.owner = owner
|
||||
identity_theft.target = kill_objective.target
|
||||
identity_theft.update_explanation_text()
|
||||
objectives += identity_theft
|
||||
escape_objective_possible = FALSE
|
||||
|
||||
if (!(locate(/datum/objective/escape) in objectives) && escape_objective_possible)
|
||||
if(prob(50))
|
||||
|
||||
@@ -191,8 +191,6 @@ new /datum/disease_ability/symptom/powerful/youth
|
||||
/datum/disease_ability/action/sneeze
|
||||
name = "Voluntary Sneezing"
|
||||
actions = list(/datum/action/cooldown/disease_sneeze)
|
||||
cost = 2
|
||||
required_total_points = 3
|
||||
short_desc = "Force the host you are following to sneeze, spreading your infection to those in front of them."
|
||||
long_desc = "Force the host you are following to sneeze with extra force, spreading your infection to any victims in a 4 meter cone in front of your host.<br>Cooldown: 20 seconds"
|
||||
|
||||
@@ -229,8 +227,6 @@ new /datum/disease_ability/symptom/powerful/youth
|
||||
/datum/disease_ability/action/infect
|
||||
name = "Secrete Infection"
|
||||
actions = list(/datum/action/cooldown/disease_infect)
|
||||
cost = 2
|
||||
required_total_points = 3
|
||||
short_desc = "Cause all objects your host is touching to become infectious for a limited time, spreading your infection to anyone who touches them."
|
||||
long_desc = "Cause the host you are following to excrete an infective substance from their pores, causing all objects touching their skin to transmit your infection to anyone who touches them for the next 30 seconds. This includes the floor, if they are not wearing shoes, and any items they are holding, if they are not wearing gloves.<br>Cooldown: 40 seconds"
|
||||
|
||||
@@ -271,23 +267,20 @@ new /datum/disease_ability/symptom/powerful/youth
|
||||
//healing costs more so you have to techswitch from naughty disease otherwise we'd have friendly disease for easy greentext (no fun!)
|
||||
|
||||
/datum/disease_ability/symptom/mild
|
||||
cost = 2
|
||||
required_total_points = 4
|
||||
category = "Symptom (Weak)"
|
||||
|
||||
/datum/disease_ability/symptom/medium
|
||||
cost = 4
|
||||
required_total_points = 8
|
||||
category = "Symptom"
|
||||
|
||||
/datum/disease_ability/symptom/medium/heal
|
||||
cost = 5
|
||||
required_total_points = 5
|
||||
malefit = -1
|
||||
category = "Symptom (+)"
|
||||
|
||||
/datum/disease_ability/symptom/powerful
|
||||
cost = 4
|
||||
required_total_points = 16
|
||||
required_total_points = 10
|
||||
category = "Symptom (Strong)"
|
||||
|
||||
/datum/disease_ability/symptom/powerful/heal
|
||||
|
||||
@@ -566,7 +566,7 @@
|
||||
human_user.adjustBruteLoss(-10, FALSE)
|
||||
human_user.adjustFireLoss(-10, FALSE)
|
||||
human_user.adjustStaminaLoss(-10, FALSE)
|
||||
human_user.adjustToxLoss(-10, FALSE)
|
||||
human_user.adjustToxLoss(-10, FALSE, TRUE)
|
||||
human_user.adjustOxyLoss(-10)
|
||||
|
||||
/obj/effect/proc_holder/spell/pointed/manse_link
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
var/mob/living/carbon/human/human_user = user
|
||||
human_user.adjustBruteLoss(-6, FALSE)
|
||||
human_user.adjustFireLoss(-6, FALSE)
|
||||
human_user.adjustToxLoss(-6, FALSE)
|
||||
human_user.adjustToxLoss(-6, FALSE, TRUE)
|
||||
human_user.adjustOxyLoss(-6, FALSE)
|
||||
human_user.adjustStaminaLoss(-20)
|
||||
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
mode = SSticker.mode
|
||||
assassin_prob = max(0,mode.threat_level-40)
|
||||
if(prob(assassin_prob))
|
||||
if(prob(assassin_prob))
|
||||
var/datum/objective/assassinate/once/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
var/datum/objective/assassinate/once/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
else
|
||||
var/list/weights = list()
|
||||
weights["sabo"] = length(subtypesof(/datum/sabotage_objective))
|
||||
|
||||
@@ -256,6 +256,8 @@
|
||||
|
||||
/datum/gas_reaction/fusion/react(datum/gas_mixture/air, datum/holder)
|
||||
var/turf/open/location
|
||||
if (isopenturf(holder))
|
||||
return
|
||||
if (istype(holder,/datum/pipeline)) //Find the tile the reaction is occuring on, or a random part of the network if it's a pipenet.
|
||||
var/datum/pipeline/fusion_pipenet = holder
|
||||
location = get_turf(pick(fusion_pipenet.members))
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
Copyright 2018 Jordan Brown
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -1,68 +0,0 @@
|
||||
/datum/BSQL_Connection
|
||||
var/id
|
||||
var/connection_type
|
||||
|
||||
BSQL_PROTECT_DATUM(/datum/BSQL_Connection)
|
||||
|
||||
/datum/BSQL_Connection/New(connection_type, asyncTimeout, blockingTimeout, threadLimit)
|
||||
if(asyncTimeout == null)
|
||||
asyncTimeout = BSQL_DEFAULT_TIMEOUT
|
||||
if(blockingTimeout == null)
|
||||
blockingTimeout = asyncTimeout
|
||||
if(threadLimit == null)
|
||||
threadLimit = BSQL_DEFAULT_THREAD_LIMIT
|
||||
|
||||
src.connection_type = connection_type
|
||||
|
||||
world._BSQL_InitCheck(src)
|
||||
|
||||
var/error = world._BSQL_Internal_Call("CreateConnection", connection_type, "[asyncTimeout]", "[blockingTimeout]", "[threadLimit]")
|
||||
if(error)
|
||||
BSQL_ERROR(error)
|
||||
return
|
||||
|
||||
id = world._BSQL_Internal_Call("GetConnection")
|
||||
if(!id)
|
||||
BSQL_ERROR("BSQL library failed to provide connect operation for connection id [id]([connection_type])!")
|
||||
|
||||
BSQL_DEL_PROC(/datum/BSQL_Connection)
|
||||
var/error
|
||||
if(id)
|
||||
error = world._BSQL_Internal_Call("ReleaseConnection", id)
|
||||
. = ..()
|
||||
if(error)
|
||||
BSQL_ERROR(error)
|
||||
|
||||
/datum/BSQL_Connection/BeginConnect(ipaddress, port, username, password, database)
|
||||
var/error = world._BSQL_Internal_Call("OpenConnection", id, ipaddress, "[port]", username, password, database)
|
||||
if(error)
|
||||
BSQL_ERROR(error)
|
||||
return
|
||||
|
||||
var/op_id = world._BSQL_Internal_Call("GetOperation")
|
||||
if(!op_id)
|
||||
BSQL_ERROR("Library failed to provide connect operation for connection id [id]([connection_type])!")
|
||||
return
|
||||
|
||||
return new /datum/BSQL_Operation(src, op_id)
|
||||
|
||||
|
||||
/datum/BSQL_Connection/BeginQuery(query)
|
||||
var/error = world._BSQL_Internal_Call("NewQuery", id, query)
|
||||
if(error)
|
||||
BSQL_ERROR(error)
|
||||
return
|
||||
|
||||
var/op_id = world._BSQL_Internal_Call("GetOperation")
|
||||
if(!op_id)
|
||||
BSQL_ERROR("Library failed to provide query operation for connection id [id]([connection_type])!")
|
||||
return
|
||||
|
||||
return new /datum/BSQL_Operation/Query(src, op_id)
|
||||
|
||||
/datum/BSQL_Connection/Quote(str)
|
||||
if(!str)
|
||||
return null;
|
||||
. = world._BSQL_Internal_Call("QuoteString", id, "[str]")
|
||||
if(!.)
|
||||
BSQL_ERROR("Library failed to provide quote for [str]!")
|
||||
@@ -1,43 +0,0 @@
|
||||
/world/proc/_BSQL_Internal_Call(func, ...)
|
||||
var/list/call_args = args.Copy(2)
|
||||
BSQL_Debug("_BSQL_Internal_Call(): [args[1]]([call_args.Join(", ")])")
|
||||
. = call(_BSQL_Library_Path(), func)(arglist(call_args))
|
||||
BSQL_Debug("Result: [. == null ? "NULL" : "\"[.]\""]")
|
||||
|
||||
/world/proc/_BSQL_Library_Path()
|
||||
return system_type == MS_WINDOWS ? "BSQL.dll" : "libBSQL.so"
|
||||
|
||||
/world/proc/_BSQL_InitCheck(datum/BSQL_Connection/caller)
|
||||
var/static/library_initialized = FALSE
|
||||
if(_BSQL_Initialized())
|
||||
return
|
||||
var/libPath = _BSQL_Library_Path()
|
||||
if(!fexists(libPath))
|
||||
BSQL_DEL_CALL(caller)
|
||||
BSQL_ERROR("Could not find [libPath]!")
|
||||
return
|
||||
|
||||
var/version = _BSQL_Internal_Call("Version")
|
||||
if(version != BSQL_VERSION)
|
||||
BSQL_DEL_CALL(caller)
|
||||
BSQL_ERROR("BSQL DMAPI version mismatch! Expected [BSQL_VERSION], got [version == null ? "NULL" : version]!")
|
||||
return
|
||||
|
||||
var/result = _BSQL_Internal_Call("Initialize")
|
||||
if(result)
|
||||
BSQL_DEL_CALL(caller)
|
||||
BSQL_ERROR(result)
|
||||
return
|
||||
_BSQL_Initialized(TRUE)
|
||||
|
||||
/world/proc/_BSQL_Initialized(new_val)
|
||||
var/static/bsql_library_initialized = FALSE
|
||||
if(new_val != null)
|
||||
bsql_library_initialized = new_val
|
||||
return bsql_library_initialized
|
||||
|
||||
/world/BSQL_Shutdown()
|
||||
if(!_BSQL_Initialized())
|
||||
return
|
||||
_BSQL_Internal_Call("Shutdown")
|
||||
_BSQL_Initialized(FALSE)
|
||||
@@ -1,47 +0,0 @@
|
||||
/datum/BSQL_Operation
|
||||
var/datum/BSQL_Connection/connection
|
||||
var/id
|
||||
|
||||
BSQL_PROTECT_DATUM(/datum/BSQL_Operation)
|
||||
|
||||
/datum/BSQL_Operation/New(datum/BSQL_Connection/connection, id)
|
||||
src.connection = connection
|
||||
src.id = id
|
||||
|
||||
BSQL_DEL_PROC(/datum/BSQL_Operation)
|
||||
var/error
|
||||
if(!BSQL_IS_DELETED(connection))
|
||||
error = world._BSQL_Internal_Call("ReleaseOperation", connection.id, id)
|
||||
. = ..()
|
||||
if(error)
|
||||
BSQL_ERROR(error)
|
||||
|
||||
/datum/BSQL_Operation/IsComplete()
|
||||
if(BSQL_IS_DELETED(connection))
|
||||
return TRUE
|
||||
var/result = world._BSQL_Internal_Call("OpComplete", connection.id, id)
|
||||
if(!result)
|
||||
BSQL_ERROR("Error fetching operation [id] for connection [connection.id]!")
|
||||
return
|
||||
return result == "DONE"
|
||||
|
||||
/datum/BSQL_Operation/GetError()
|
||||
if(BSQL_IS_DELETED(connection))
|
||||
return "Connection deleted!"
|
||||
return world._BSQL_Internal_Call("GetError", connection.id, id)
|
||||
|
||||
/datum/BSQL_Operation/GetErrorCode()
|
||||
if(BSQL_IS_DELETED(connection))
|
||||
return -2
|
||||
return text2num(world._BSQL_Internal_Call("GetErrorCode", connection.id, id))
|
||||
|
||||
/datum/BSQL_Operation/WaitForCompletion()
|
||||
if(BSQL_IS_DELETED(connection))
|
||||
return
|
||||
var/error = world._BSQL_Internal_Call("BlockOnOperation", connection.id, id)
|
||||
if(error)
|
||||
if(error == "Operation timed out!") //match this with the implementation
|
||||
return FALSE
|
||||
BSQL_ERROR("Error waiting for operation [id] for connection [connection.id]! [error]")
|
||||
return
|
||||
return TRUE
|
||||
@@ -1,35 +0,0 @@
|
||||
/datum/BSQL_Operation/Query
|
||||
var/last_result_json
|
||||
var/list/last_result
|
||||
|
||||
BSQL_PROTECT_DATUM(/datum/BSQL_Operation/Query)
|
||||
|
||||
/datum/BSQL_Operation/Query/CurrentRow()
|
||||
return last_result
|
||||
|
||||
/datum/BSQL_Operation/Query/IsComplete()
|
||||
//whole different ballgame here
|
||||
if(BSQL_IS_DELETED(connection))
|
||||
return TRUE
|
||||
var/result = world._BSQL_Internal_Call("ReadyRow", connection.id, id)
|
||||
switch(result)
|
||||
if("DONE")
|
||||
//load the data
|
||||
LoadQueryResult()
|
||||
return TRUE
|
||||
if("NOTDONE")
|
||||
return FALSE
|
||||
else
|
||||
BSQL_ERROR(result)
|
||||
|
||||
/datum/BSQL_Operation/Query/WaitForCompletion()
|
||||
. = ..()
|
||||
if(.)
|
||||
LoadQueryResult()
|
||||
|
||||
/datum/BSQL_Operation/Query/proc/LoadQueryResult()
|
||||
last_result_json = world._BSQL_Internal_Call("GetRow", connection.id, id)
|
||||
if(last_result_json)
|
||||
last_result = json_decode(last_result_json)
|
||||
else
|
||||
last_result = null
|
||||
@@ -1,4 +0,0 @@
|
||||
#include "core\connection.dm"
|
||||
#include "core\library.dm"
|
||||
#include "core\operation.dm"
|
||||
#include "core\query.dm"
|
||||
@@ -42,18 +42,21 @@
|
||||
|
||||
/datum/supply_pack/misc/book_crate
|
||||
name = "Book Crate"
|
||||
desc = "Surplus from the Nanotrasen Archives, these five books are sure to be good reads."
|
||||
desc = "Surplus from the Nanotrasen Archives, these seven books are sure to be good reads."
|
||||
// cost = CARGO_CRATE_VALUE * 3
|
||||
cost = 1500
|
||||
contains = list(/obj/item/book/codex_gigas,
|
||||
/obj/item/book/manual/random/,
|
||||
/obj/item/book/manual/random/,
|
||||
/obj/item/book/manual/random/,
|
||||
/obj/item/book/random/triple)
|
||||
/obj/item/book/random,
|
||||
/obj/item/book/random,
|
||||
/obj/item/book/random)
|
||||
crate_type = /obj/structure/closet/crate/wooden
|
||||
|
||||
/datum/supply_pack/misc/paper
|
||||
name = "Bureaucracy Crate"
|
||||
desc = "High stacks of papers on your desk Are a big problem - make it Pea-sized with these bureaucratic supplies! Contains five pens, some camera film, hand labeler supplies, a paper bin, three folders, two clipboards and two stamps as well as a briefcase."//that was too forced
|
||||
desc = "High stacks of papers on your desk Are a big problem - make it Pea-sized with these bureaucratic supplies! Contains six pens, some camera film, hand labeler supplies, a paper bin, a carbon paper bin, three folders, a laser pointer, two clipboards and two stamps."//that was too forced
|
||||
cost = 1500
|
||||
contains = list(/obj/structure/filingcabinet/chestdrawer/wheeled,
|
||||
/obj/item/camera_film,
|
||||
@@ -61,9 +64,11 @@
|
||||
/obj/item/hand_labeler_refill,
|
||||
/obj/item/hand_labeler_refill,
|
||||
/obj/item/paper_bin,
|
||||
/obj/item/paper_bin/carbon,
|
||||
/obj/item/pen/fourcolor,
|
||||
/obj/item/pen/fourcolor,
|
||||
/obj/item/pen,
|
||||
/obj/item/pen/fountain,
|
||||
/obj/item/pen/blue,
|
||||
/obj/item/pen/red,
|
||||
/obj/item/folder/blue,
|
||||
@@ -73,7 +78,7 @@
|
||||
/obj/item/clipboard,
|
||||
/obj/item/stamp,
|
||||
/obj/item/stamp/denied,
|
||||
/obj/item/storage/briefcase)
|
||||
/obj/item/laser_pointer/purple)
|
||||
crate_name = "bureaucracy crate"
|
||||
|
||||
/datum/supply_pack/misc/captain_pen
|
||||
@@ -94,6 +99,30 @@
|
||||
crate_type = /obj/structure/closet/crate/wooden
|
||||
crate_name = "calligraphy crate"
|
||||
|
||||
/datum/supply_pack/misc/toner
|
||||
name = "Toner Crate"
|
||||
desc = "Spent too much ink printing butt pictures? Fret not, with these six toner refills, you'll be printing butts 'till the cows come home!'"
|
||||
cost = 200 * 4
|
||||
contains = list(/obj/item/toner,
|
||||
/obj/item/toner,
|
||||
/obj/item/toner,
|
||||
/obj/item/toner,
|
||||
/obj/item/toner,
|
||||
/obj/item/toner)
|
||||
crate_name = "toner crate"
|
||||
|
||||
/datum/supply_pack/misc/toner_large
|
||||
name = "Toner Crate (Large)"
|
||||
desc = "Tired of changing toner cartridges? These six extra heavy duty refills contain roughly five times as much toner as the base model!"
|
||||
cost = 200 * 6
|
||||
contains = list(/obj/item/toner/large,
|
||||
/obj/item/toner/large,
|
||||
/obj/item/toner/large,
|
||||
/obj/item/toner/large,
|
||||
/obj/item/toner/large,
|
||||
/obj/item/toner/large)
|
||||
crate_name = "large toner crate"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////// Entertainment ///////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -419,7 +419,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
if (nnpa >= 0)
|
||||
message_admins("New user: [key_name_admin(src)] is connecting here for the first time.")
|
||||
if (CONFIG_GET(flag/irc_first_connection_alert))
|
||||
send2irc_adminless_only("New-user", "[key_name(src)] is connecting for the first time!")
|
||||
send2tgs_adminless_only("New-user", "[key_name(src)] is connecting for the first time!")
|
||||
else if (isnum(cached_player_age) && cached_player_age < nnpa)
|
||||
message_admins("New user: [key_name_admin(src)] just connected with an age of [cached_player_age] day[(player_age==1?"":"s")]")
|
||||
if(CONFIG_GET(flag/use_account_age_for_jobs) && account_age >= 0)
|
||||
@@ -427,7 +427,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
if(account_age >= 0 && account_age < nnpa)
|
||||
message_admins("[key_name_admin(src)] (IP: [address], ID: [computer_id]) is a new BYOND account [account_age] day[(account_age==1?"":"s")] old, created on [account_join_date].")
|
||||
if (CONFIG_GET(flag/irc_first_connection_alert))
|
||||
send2irc_adminless_only("new_byond_user", "[key_name(src)] (IP: [address], ID: [computer_id]) is a new BYOND account [account_age] day[(account_age==1?"":"s")] old, created on [account_join_date].")
|
||||
send2tgs_adminless_only("new_byond_user", "[key_name(src)] (IP: [address], ID: [computer_id]) is a new BYOND account [account_age] day[(account_age==1?"":"s")] old, created on [account_join_date].")
|
||||
get_message_output("watchlist entry", ckey)
|
||||
check_ip_intel()
|
||||
validate_key_in_db()
|
||||
@@ -523,7 +523,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
"Forever alone :("\
|
||||
)
|
||||
|
||||
send2irc("Server", "[cheesy_message] (No admins online)")
|
||||
send2adminchat("Server", "[cheesy_message] (No admins online)")
|
||||
QDEL_LIST_ASSOC_VAL(char_render_holders)
|
||||
if(movingmob != null)
|
||||
movingmob.client_mobs_in_contents -= mob
|
||||
@@ -538,14 +538,21 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
return
|
||||
if(!SSdbcore.Connect())
|
||||
return
|
||||
var/sql_ckey = sanitizeSQL(src.ckey)
|
||||
var/datum/DBQuery/query_get_related_ip = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ip = INET_ATON('[address]') AND ckey != '[sql_ckey]'")
|
||||
query_get_related_ip.Execute()
|
||||
var/datum/db_query/query_get_related_ip = SSdbcore.NewQuery(
|
||||
"SELECT ckey FROM [format_table_name("player")] WHERE ip = INET_ATON(:address) AND ckey != :ckey",
|
||||
list("address" = address, "ckey" = ckey)
|
||||
)
|
||||
if(!query_get_related_ip.Execute())
|
||||
qdel(query_get_related_ip)
|
||||
return
|
||||
related_accounts_ip = ""
|
||||
while(query_get_related_ip.NextRow())
|
||||
related_accounts_ip += "[query_get_related_ip.item[1]], "
|
||||
qdel(query_get_related_ip)
|
||||
var/datum/DBQuery/query_get_related_cid = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE computerid = '[computer_id]' AND ckey != '[sql_ckey]'")
|
||||
var/datum/db_query/query_get_related_cid = SSdbcore.NewQuery(
|
||||
"SELECT ckey FROM [format_table_name("player")] WHERE computerid = :computerid AND ckey != :ckey",
|
||||
list("computerid" = computer_id, "ckey" = ckey)
|
||||
)
|
||||
if(!query_get_related_cid.Execute())
|
||||
qdel(query_get_related_cid)
|
||||
return
|
||||
@@ -559,45 +566,40 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
else
|
||||
if (!GLOB.deadmins[ckey] && check_randomizer(connectiontopic))
|
||||
return
|
||||
var/sql_ip = sanitizeSQL(address)
|
||||
var/sql_computerid = sanitizeSQL(computer_id)
|
||||
var/sql_admin_rank = sanitizeSQL(admin_rank)
|
||||
var/new_player
|
||||
var/datum/DBQuery/query_client_in_db = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("player")] WHERE ckey = '[sql_ckey]'")
|
||||
var/datum/db_query/query_client_in_db = SSdbcore.NewQuery(
|
||||
"SELECT 1 FROM [format_table_name("player")] WHERE ckey = :ckey",
|
||||
list("ckey" = ckey)
|
||||
)
|
||||
if(!query_client_in_db.Execute())
|
||||
qdel(query_client_in_db)
|
||||
return
|
||||
if(!query_client_in_db.NextRow()) //new user detected
|
||||
if(!holder && !GLOB.deadmins[ckey])
|
||||
if(CONFIG_GET(flag/panic_bunker) && !(ckey in GLOB.bunker_passthrough))
|
||||
log_access("Failed Login: [key] - New account attempting to connect during panic bunker")
|
||||
message_admins("<span class='adminnotice'>Failed Login: [key] - New account attempting to connect during panic bunker</span>")
|
||||
to_chat(src, "<span class='notice'>You must first join the Discord to verify your account before joining this server.<br>To do so, read the rules and post a request in the #station-access-requests channel under the \"Main server\" category in the Discord server linked here: <a href='https://discord.gg/E6SQuhz'>https://discord.gg/E6SQuhz</a><br>If you have already done so, wait a few minutes then try again; sometimes the server needs to fully load before you can join.</span>") //CIT CHANGE - makes the panic bunker disconnect message point to the discord
|
||||
var/list/connectiontopic_a = params2list(connectiontopic)
|
||||
var/list/panic_addr = CONFIG_GET(string/panic_server_address)
|
||||
if(panic_addr && !connectiontopic_a["redirect"])
|
||||
var/panic_name = CONFIG_GET(string/panic_server_name)
|
||||
to_chat(src, "<span class='notice'>Sending you to [panic_name ? panic_name : panic_addr].</span>")
|
||||
winset(src, null, "command=.options")
|
||||
src << link("[panic_addr]?redirect=1")
|
||||
qdel(query_client_in_db)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
new_player = 1
|
||||
account_join_date = sanitizeSQL(findJoinDate())
|
||||
var/sql_key = sanitizeSQL(key)
|
||||
var/datum/DBQuery/query_add_player = SSdbcore.NewQuery("INSERT INTO [format_table_name("player")] (`ckey`, `byond_key`, `firstseen`, `firstseen_round_id`, `lastseen`, `lastseen_round_id`, `ip`, `computerid`, `lastadminrank`, `accountjoindate`) VALUES ('[sql_ckey]', '[sql_key]', Now(), '[GLOB.round_id]', Now(), '[GLOB.round_id]', INET_ATON('[sql_ip]'), '[sql_computerid]', '[sql_admin_rank]', [account_join_date ? "'[account_join_date]'" : "NULL"])")
|
||||
if(!query_add_player.Execute())
|
||||
qdel(query_client_in_db)
|
||||
qdel(query_add_player)
|
||||
return
|
||||
qdel(query_add_player)
|
||||
if(!account_join_date)
|
||||
account_join_date = "Error"
|
||||
account_age = -1
|
||||
else if(ckey in GLOB.bunker_passthrough)
|
||||
GLOB.bunker_passthrough -= ckey
|
||||
//If we aren't an admin, and the flag is set
|
||||
if(CONFIG_GET(flag/panic_bunker) && !holder && !GLOB.deadmins[ckey] && !(ckey in GLOB.bunker_passthrough))
|
||||
var/living_recs = CONFIG_GET(number/panic_bunker_living)
|
||||
//Relies on pref existing, but this proc is only called after that occurs, so we're fine.
|
||||
var/minutes = get_exp_living(pure_numeric = TRUE)
|
||||
if(minutes <= living_recs) // && !CONFIG_GET(flag/panic_bunker_interview)
|
||||
var/reject_message = "Failed Login: [key] - Account attempting to connect during panic bunker, but they do not have the required living time [minutes]/[living_recs]"
|
||||
log_access(reject_message)
|
||||
message_admins("<span class='adminnotice'>[reject_message]</span>")
|
||||
var/message = CONFIG_GET(string/panic_bunker_message)
|
||||
message = replacetext(message, "%minutes%", living_recs)
|
||||
to_chat(src, message)
|
||||
var/list/connectiontopic_a = params2list(connectiontopic)
|
||||
var/list/panic_addr = CONFIG_GET(string/panic_server_address)
|
||||
if(panic_addr && !connectiontopic_a["redirect"])
|
||||
var/panic_name = CONFIG_GET(string/panic_server_name)
|
||||
to_chat(src, "<span class='notice'>Sending you to [panic_name ? panic_name : panic_addr].</span>")
|
||||
winset(src, null, "command=.options")
|
||||
src << link("[panic_addr]?redirect=1")
|
||||
qdel(query_client_in_db)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
if(!query_client_in_db.NextRow())
|
||||
new_player = 1
|
||||
if(CONFIG_GET(flag/age_verification)) //setup age verification
|
||||
if(!set_db_player_flags())
|
||||
message_admins(usr, "<span class='danger'>ERROR: Unable to read player flags from database. Please check logs.</span>")
|
||||
@@ -609,9 +611,24 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
update_flag_db(DB_FLAG_AGE_CONFIRMATION_COMPLETE, TRUE)
|
||||
else
|
||||
update_flag_db(DB_FLAG_AGE_CONFIRMATION_INCOMPLETE, TRUE)
|
||||
|
||||
account_join_date = findJoinDate()
|
||||
var/datum/db_query/query_add_player = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("player")] (`ckey`, `byond_key`, `firstseen`, `firstseen_round_id`, `lastseen`, `lastseen_round_id`, `ip`, `computerid`, `lastadminrank`, `accountjoindate`)
|
||||
VALUES (:ckey, :key, Now(), :round_id, Now(), :round_id, INET_ATON(:ip), :computerid, :adminrank, :account_join_date)
|
||||
"}, list("ckey" = ckey, "key" = key, "round_id" = GLOB.round_id, "ip" = address, "computerid" = computer_id, "adminrank" = admin_rank, "account_join_date" = account_join_date || null))
|
||||
if(!query_add_player.Execute())
|
||||
qdel(query_client_in_db)
|
||||
qdel(query_add_player)
|
||||
return
|
||||
qdel(query_add_player)
|
||||
if(!account_join_date)
|
||||
account_join_date = "Error"
|
||||
account_age = -1
|
||||
qdel(query_client_in_db)
|
||||
var/datum/DBQuery/query_get_client_age = SSdbcore.NewQuery("SELECT firstseen, DATEDIFF(Now(),firstseen), accountjoindate, DATEDIFF(Now(),accountjoindate) FROM [format_table_name("player")] WHERE ckey = '[sql_ckey]'")
|
||||
var/datum/db_query/query_get_client_age = SSdbcore.NewQuery(
|
||||
"SELECT firstseen, DATEDIFF(Now(),firstseen), accountjoindate, DATEDIFF(Now(),accountjoindate) FROM [format_table_name("player")] WHERE ckey = :ckey",
|
||||
list("ckey" = ckey)
|
||||
)
|
||||
if(!query_get_client_age.Execute())
|
||||
qdel(query_get_client_age)
|
||||
return
|
||||
@@ -622,11 +639,14 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
account_join_date = query_get_client_age.item[3]
|
||||
account_age = text2num(query_get_client_age.item[4])
|
||||
if(!account_age)
|
||||
account_join_date = sanitizeSQL(findJoinDate())
|
||||
account_join_date = findJoinDate()
|
||||
if(!account_join_date)
|
||||
account_age = -1
|
||||
else
|
||||
var/datum/DBQuery/query_datediff = SSdbcore.NewQuery("SELECT DATEDIFF(Now(),'[account_join_date]')")
|
||||
var/datum/db_query/query_datediff = SSdbcore.NewQuery(
|
||||
"SELECT DATEDIFF(Now(), :account_join_date)",
|
||||
list("account_join_date" = account_join_date)
|
||||
)
|
||||
if(!query_datediff.Execute())
|
||||
qdel(query_datediff)
|
||||
return
|
||||
@@ -635,14 +655,20 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
qdel(query_datediff)
|
||||
qdel(query_get_client_age)
|
||||
if(!new_player)
|
||||
var/datum/DBQuery/query_log_player = SSdbcore.NewQuery("UPDATE [format_table_name("player")] SET lastseen = Now(), lastseen_round_id = '[GLOB.round_id]', ip = INET_ATON('[sql_ip]'), computerid = '[sql_computerid]', lastadminrank = '[sql_admin_rank]', accountjoindate = [account_join_date ? "'[account_join_date]'" : "NULL"] WHERE ckey = '[sql_ckey]'")
|
||||
var/datum/db_query/query_log_player = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("player")] SET lastseen = Now(), lastseen_round_id = :round_id, ip = INET_ATON(:ip), computerid = :computerid, lastadminrank = :admin_rank, accountjoindate = :account_join_date WHERE ckey = :ckey",
|
||||
list("round_id" = GLOB.round_id, "ip" = address, "computerid" = computer_id, "admin_rank" = admin_rank, "account_join_date" = account_join_date || null, "ckey" = ckey)
|
||||
)
|
||||
if(!query_log_player.Execute())
|
||||
qdel(query_log_player)
|
||||
return
|
||||
qdel(query_log_player)
|
||||
if(!account_join_date)
|
||||
account_join_date = "Error"
|
||||
var/datum/DBQuery/query_log_connection = SSdbcore.NewQuery("INSERT INTO `[format_table_name("connection_log")]` (`id`,`datetime`,`server_ip`,`server_port`,`round_id`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')),'[world.port]','[GLOB.round_id]','[sql_ckey]',INET_ATON('[sql_ip]'),'[sql_computerid]')")
|
||||
var/datum/db_query/query_log_connection = SSdbcore.NewQuery({"
|
||||
INSERT INTO `[format_table_name("connection_log")]` (`id`,`datetime`,`server_ip`,`server_port`,`round_id`,`ckey`,`ip`,`computerid`)
|
||||
VALUES(null,Now(),INET_ATON(:internet_address),:port,:round_id,:ckey,INET_ATON(:ip),:computerid)
|
||||
"}, list("internet_address" = world.internet_address || "0", "port" = world.port, "round_id" = GLOB.round_id, "ckey" = ckey, "ip" = address, "computerid" = computer_id))
|
||||
query_log_connection.Execute()
|
||||
qdel(query_log_connection)
|
||||
|
||||
@@ -666,9 +692,11 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
CRASH("Age check regex failed for [src.ckey]")
|
||||
|
||||
/client/proc/validate_key_in_db()
|
||||
var/sql_ckey = sanitizeSQL(ckey)
|
||||
var/sql_key
|
||||
var/datum/DBQuery/query_check_byond_key = SSdbcore.NewQuery("SELECT byond_key FROM [format_table_name("player")] WHERE ckey = '[sql_ckey]'")
|
||||
var/datum/db_query/query_check_byond_key = SSdbcore.NewQuery(
|
||||
"SELECT byond_key FROM [format_table_name("player")] WHERE ckey = :ckey",
|
||||
list("ckey" = ckey)
|
||||
)
|
||||
if(!query_check_byond_key.Execute())
|
||||
qdel(query_check_byond_key)
|
||||
return
|
||||
@@ -684,8 +712,11 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
if(F)
|
||||
var/regex/R = regex("\\tkey = \"(.+)\"")
|
||||
if(R.Find(F))
|
||||
var/web_key = sanitizeSQL(R.group[1])
|
||||
var/datum/DBQuery/query_update_byond_key = SSdbcore.NewQuery("UPDATE [format_table_name("player")] SET byond_key = '[web_key]' WHERE ckey = '[sql_ckey]'")
|
||||
var/web_key = R.group[1]
|
||||
var/datum/db_query/query_update_byond_key = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("player")] SET byond_key = :byond_key WHERE ckey = :ckey",
|
||||
list("byond_key" = web_key, "ckey" = ckey)
|
||||
)
|
||||
query_update_byond_key.Execute()
|
||||
qdel(query_update_byond_key)
|
||||
else
|
||||
@@ -702,8 +733,10 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
var/static/tokens = list()
|
||||
var/static/cidcheck_failedckeys = list() //to avoid spamming the admins if the same guy keeps trying.
|
||||
var/static/cidcheck_spoofckeys = list()
|
||||
var/sql_ckey = sanitizeSQL(ckey)
|
||||
var/datum/DBQuery/query_cidcheck = SSdbcore.NewQuery("SELECT computerid FROM [format_table_name("player")] WHERE ckey = '[sql_ckey]'")
|
||||
var/datum/db_query/query_cidcheck = SSdbcore.NewQuery(
|
||||
"SELECT computerid FROM [format_table_name("player")] WHERE ckey = :ckey",
|
||||
list("ckey" = ckey)
|
||||
)
|
||||
query_cidcheck.Execute()
|
||||
|
||||
var/lastcid
|
||||
@@ -722,7 +755,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
|
||||
sleep(15 SECONDS) //Longer sleep here since this would trigger if a client tries to reconnect manually because the inital reconnect failed
|
||||
|
||||
//we sleep after telling the client to reconnect, so if we still exist something is up
|
||||
//we sleep after telling the client to reconnect, so if we still exist something is up
|
||||
log_access("Forced disconnect: [key] [computer_id] [address] - CID randomizer check")
|
||||
|
||||
qdel(src)
|
||||
@@ -736,7 +769,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
|
||||
if (!cidcheck_failedckeys[ckey])
|
||||
message_admins("<span class='adminnotice'>[key_name(src)] has been detected as using a cid randomizer. Connection rejected.</span>")
|
||||
send2irc_adminless_only("CidRandomizer", "[key_name(src)] has been detected as using a cid randomizer. Connection rejected.")
|
||||
send2tgs_adminless_only("CidRandomizer", "[key_name(src)] has been detected as using a cid randomizer. Connection rejected.")
|
||||
cidcheck_failedckeys[ckey] = TRUE
|
||||
note_randomizer_user()
|
||||
|
||||
@@ -747,7 +780,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
else
|
||||
if (cidcheck_failedckeys[ckey])
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(src)] has been allowed to connect after showing they removed their cid randomizer</span>")
|
||||
send2irc_adminless_only("CidRandomizer", "[key_name(src)] has been allowed to connect after showing they removed their cid randomizer.")
|
||||
send2tgs_adminless_only("CidRandomizer", "[key_name(src)] has been allowed to connect after showing they removed their cid randomizer.")
|
||||
cidcheck_failedckeys -= ckey
|
||||
if (cidcheck_spoofckeys[ckey])
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(src)] has been allowed to connect after appearing to have attempted to spoof a cid randomizer check because it <i>appears</i> they aren't spoofing one this time</span>")
|
||||
@@ -778,10 +811,11 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
add_system_note("CID-Error", "Detected as using a cid randomizer.")
|
||||
|
||||
/client/proc/add_system_note(system_ckey, message)
|
||||
var/sql_system_ckey = sanitizeSQL(system_ckey)
|
||||
var/sql_ckey = sanitizeSQL(ckey)
|
||||
//check to see if we noted them in the last day.
|
||||
var/datum/DBQuery/query_get_notes = SSdbcore.NewQuery("SELECT id FROM [format_table_name("messages")] WHERE type = 'note' AND targetckey = '[sql_ckey]' AND adminckey = '[sql_system_ckey]' AND timestamp + INTERVAL 1 DAY < NOW() AND deleted = 0 AND expire_timestamp > NOW()")
|
||||
var/datum/db_query/query_get_notes = SSdbcore.NewQuery(
|
||||
"SELECT id FROM [format_table_name("messages")] WHERE type = 'note' AND targetckey = :targetckey AND adminckey = :adminckey AND timestamp + INTERVAL 1 DAY < NOW() AND deleted = 0 AND (expire_timestamp > NOW() OR expire_timestamp IS NULL)",
|
||||
list("targetckey" = ckey, "adminckey" = system_ckey)
|
||||
)
|
||||
if(!query_get_notes.Execute())
|
||||
qdel(query_get_notes)
|
||||
return
|
||||
@@ -790,7 +824,10 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
return
|
||||
qdel(query_get_notes)
|
||||
//regardless of above, make sure their last note is not from us, as no point in repeating the same note over and over.
|
||||
query_get_notes = SSdbcore.NewQuery("SELECT adminckey FROM [format_table_name("messages")] WHERE targetckey = '[sql_ckey]' AND deleted = 0 AND expire_timestamp > NOW() ORDER BY timestamp DESC LIMIT 1")
|
||||
query_get_notes = SSdbcore.NewQuery(
|
||||
"SELECT adminckey FROM [format_table_name("messages")] WHERE targetckey = :targetckey AND deleted = 0 AND (expire_timestamp > NOW() OR expire_timestamp IS NULL) ORDER BY timestamp DESC LIMIT 1",
|
||||
list("targetckey" = ckey)
|
||||
)
|
||||
if(!query_get_notes.Execute())
|
||||
qdel(query_get_notes)
|
||||
return
|
||||
|
||||
@@ -1370,9 +1370,11 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
|
||||
/datum/preferences/proc/process_link(mob/user, list/href_list)
|
||||
if(href_list["jobbancheck"])
|
||||
var/job = sanitizeSQL(href_list["jobbancheck"])
|
||||
var/sql_ckey = sanitizeSQL(user.ckey)
|
||||
var/datum/DBQuery/query_get_jobban = SSdbcore.NewQuery("SELECT reason, bantime, duration, expiration_time, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].a_ckey), a_ckey) FROM [format_table_name("ban")] WHERE ckey = '[sql_ckey]' AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned) AND job = '[job]'")
|
||||
var/job = href_list["jobbancheck"]
|
||||
var/datum/db_query/query_get_jobban = SSdbcore.NewQuery({"
|
||||
SELECT reason, bantime, duration, expiration_time, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].a_ckey), a_ckey)
|
||||
FROM [format_table_name("ban")] WHERE ckey = :ckey AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned) AND job = :job
|
||||
"}, list("ckey" = user.ckey, "job" = job))
|
||||
if(!query_get_jobban.warn_execute())
|
||||
qdel(query_get_jobban)
|
||||
return
|
||||
@@ -1387,7 +1389,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
if(text2num(duration) > 0)
|
||||
text += ". The ban is for [duration] minutes and expires on [expiration_time] (server time)"
|
||||
text += ".</span>"
|
||||
to_chat(user, text)
|
||||
to_chat(user, text, confidential = TRUE)
|
||||
qdel(query_get_jobban)
|
||||
return
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ GLOBAL_VAR_INIT(normal_aooc_colour, "#ce254f")
|
||||
if(!mob)
|
||||
return
|
||||
|
||||
if(!(prefs.toggles & CHAT_OOC))
|
||||
if(!(prefs.chat_toggles & CHAT_OOC))
|
||||
to_chat(src, "<span class='danger'> You have OOC muted.</span>")
|
||||
return
|
||||
if(jobban_isbanned(mob, "OOC"))
|
||||
|
||||
@@ -179,7 +179,7 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8")
|
||||
to_chat(usr, "<span class='notice'>Sorry, that function is not enabled on this server.</span>")
|
||||
return
|
||||
|
||||
browse_messages(null, usr.ckey, null, TRUE, override = TRUE)
|
||||
browse_messages(null, usr.ckey, null, TRUE)
|
||||
|
||||
/client/proc/self_playtime()
|
||||
set name = "View tracked playtime"
|
||||
|
||||
@@ -220,8 +220,8 @@
|
||||
parry_max_attacks = INFINITY
|
||||
parry_failed_cooldown_duration = 2.25 SECONDS
|
||||
parry_failed_stagger_duration = 2.25 SECONDS
|
||||
parry_cooldown = 3 SECONDS
|
||||
parry_failed_clickcd_duration = 0.5 SECONDS
|
||||
parry_cooldown = 0
|
||||
parry_failed_clickcd_duration = 0
|
||||
|
||||
/obj/item/clothing/gloves/botanic_leather
|
||||
name = "botanist's leather gloves"
|
||||
|
||||
@@ -1040,6 +1040,12 @@
|
||||
icon_state = "wbreakpoly"
|
||||
item_state = "wbreakpoly"
|
||||
|
||||
/obj/item/clothing/suit/toggle/wbreakpoly/on_toggle(mob/user)
|
||||
if(suittoggled)
|
||||
to_chat(usr, "<span class='notice'>You zip up [src].</span>")
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>You unzip [src].</span>")
|
||||
|
||||
/obj/item/clothing/suit/toggle/wbreakpoly/polychromic/ComponentInitialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/polychromic, list("#464F65", "#916035", "#474747"), 3)
|
||||
|
||||
@@ -110,6 +110,9 @@
|
||||
suit_toggle(user)
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/suit/toggle/proc/on_toggle(mob/user) // override this, not suit_toggle, which does checks
|
||||
to_chat(usr, "<span class='notice'>You toggle [src]'s [togglename].</span>")
|
||||
|
||||
/obj/item/clothing/suit/toggle/ui_action_click()
|
||||
suit_toggle()
|
||||
|
||||
@@ -119,7 +122,7 @@
|
||||
if(!can_use(usr))
|
||||
return 0
|
||||
|
||||
to_chat(usr, "<span class='notice'>You toggle [src]'s [togglename].</span>")
|
||||
on_toggle(usr)
|
||||
if(src.suittoggled)
|
||||
src.icon_state = "[initial(icon_state)]"
|
||||
src.suittoggled = FALSE
|
||||
|
||||
@@ -138,3 +138,27 @@
|
||||
icon_state = "greyturtle"
|
||||
item_state = "greyturtle"
|
||||
can_adjust = FALSE
|
||||
|
||||
/obj/item/clothing/under/suit/turtle/purple
|
||||
name = "purple turtleneck"
|
||||
icon_state = "turtle_sci"
|
||||
item_state = "turtle_sci"
|
||||
can_adjust = FALSE
|
||||
|
||||
/obj/item/clothing/under/suit/turtle/orange
|
||||
name = "orange turtleneck"
|
||||
icon_state = "turtle_eng"
|
||||
item_state = "turtle_eng"
|
||||
can_adjust = FALSE
|
||||
|
||||
/obj/item/clothing/under/suit/turtle/red
|
||||
name = "red turtleneck"
|
||||
icon_state = "turtle_sec"
|
||||
item_state = "turtle_sec"
|
||||
can_adjust = FALSE
|
||||
|
||||
/obj/item/clothing/under/suit/turtle/blue
|
||||
name = "blue turtleneck"
|
||||
icon_state = "turtle_med"
|
||||
item_state = "turtle_med"
|
||||
can_adjust = FALSE
|
||||
|
||||
@@ -21,27 +21,6 @@
|
||||
new /obj/item/reagent_containers/food/snacks/candyheart(B)
|
||||
new /obj/item/storage/fancy/heart_box(B)
|
||||
|
||||
var/list/valentines = list()
|
||||
for(var/mob/living/M in GLOB.player_list)
|
||||
if(!M.stat && M.client && M.mind && !HAS_TRAIT(M, TRAIT_NO_MIDROUND_ANTAG))
|
||||
valentines |= M
|
||||
|
||||
|
||||
while(valentines.len)
|
||||
var/mob/living/L = pick_n_take(valentines)
|
||||
if(valentines.len)
|
||||
var/mob/living/date = pick_n_take(valentines)
|
||||
|
||||
|
||||
forge_valentines_objective(L, date)
|
||||
forge_valentines_objective(date, L)
|
||||
|
||||
if(valentines.len && prob(4))
|
||||
var/mob/living/notgoodenough = pick_n_take(valentines)
|
||||
forge_valentines_objective(notgoodenough, date)
|
||||
else
|
||||
L.mind.add_antag_datum(/datum/antagonist/heartbreaker)
|
||||
|
||||
/proc/forge_valentines_objective(mob/living/lover,mob/living/date,var/chemLove = FALSE)
|
||||
lover.mind.special_role = "valentine"
|
||||
if (chemLove == TRUE)
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/datum/round_event_control/supermatter_surge
|
||||
name = "Supermatter Surge"
|
||||
typepath = /datum/round_event/supermatter_surge
|
||||
weight = 20
|
||||
max_occurrences = 4
|
||||
earliest_start = 10 MINUTES
|
||||
|
||||
/datum/round_event_control/supermatter_surge/canSpawnEvent()
|
||||
if(GLOB.main_supermatter_engine?.has_been_powered)
|
||||
return ..()
|
||||
|
||||
/datum/round_event/supermatter_surge
|
||||
var/power = 2000
|
||||
|
||||
/datum/round_event/supermatter_surge/setup()
|
||||
power = rand(200,4000)
|
||||
|
||||
/datum/round_event/supermatter_surge/announce()
|
||||
if(power > 800 || prob(round(power/8)))
|
||||
priority_announce("Class [round(power/500) + 1] supermatter surge detected. Intervention may be required.", "Anomaly Alert")
|
||||
|
||||
/datum/round_event/supermatter_surge/start()
|
||||
GLOB.main_supermatter_engine.matter_power += power
|
||||
@@ -435,7 +435,7 @@
|
||||
name = "alien drone cube"
|
||||
desc = "Just add water and run!"
|
||||
tastes = list("the jungle" = 1, "acid" = 1)
|
||||
dried_being = /mob/living/carbon/alien/humanoid/drone
|
||||
dried_being = /mob/living/simple_animal/hostile/alien/sentinel/cube
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/cube/goat
|
||||
name = "goat cube"
|
||||
|
||||
@@ -97,6 +97,7 @@
|
||||
if(myseed.mutatelist.len > 0)
|
||||
myseed.instability = (myseed.instability/2)
|
||||
mutatespecie()
|
||||
return BULLET_ACT_HIT
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
GLOBAL_LIST_EMPTY(exp_to_update)
|
||||
GLOBAL_PROTECT(exp_to_update)
|
||||
|
||||
|
||||
// Procs
|
||||
/datum/job/proc/required_playtime_remaining(client/C)
|
||||
if(!C)
|
||||
@@ -57,6 +56,7 @@ GLOBAL_PROTECT(exp_to_update)
|
||||
amount += explist[job]
|
||||
return amount
|
||||
|
||||
// todo: port tgui exp
|
||||
/client/proc/get_exp_report()
|
||||
if(!CONFIG_GET(flag/use_exp_tracking))
|
||||
return "Tracking is disabled in the server configuration file."
|
||||
@@ -121,12 +121,11 @@ GLOBAL_PROTECT(exp_to_update)
|
||||
return_text += "</LI></UL>"
|
||||
return return_text
|
||||
|
||||
|
||||
/client/proc/get_exp_living()
|
||||
if(!prefs.exp)
|
||||
return "No data"
|
||||
/client/proc/get_exp_living(pure_numeric = FALSE)
|
||||
if(!prefs.exp || !prefs.exp[EXP_TYPE_LIVING])
|
||||
return pure_numeric ? 0 : "No data"
|
||||
var/exp_living = text2num(prefs.exp[EXP_TYPE_LIVING])
|
||||
return get_exp_format(exp_living)
|
||||
return pure_numeric ? exp_living : get_exp_format(exp_living)
|
||||
|
||||
/proc/get_exp_format(expnum)
|
||||
if(expnum > 60)
|
||||
@@ -148,7 +147,7 @@ GLOBAL_PROTECT(exp_to_update)
|
||||
set waitfor = FALSE
|
||||
var/list/old_minutes = GLOB.exp_to_update
|
||||
GLOB.exp_to_update = null
|
||||
SSdbcore.MassInsert(format_table_name("role_time"), old_minutes, "ON DUPLICATE KEY UPDATE minutes = minutes + VALUES(minutes)")
|
||||
SSdbcore.MassInsert(format_table_name("role_time"), old_minutes, duplicate_key = "ON DUPLICATE KEY UPDATE minutes = minutes + VALUES(minutes)")
|
||||
|
||||
//resets a client's exp to what was in the db.
|
||||
/client/proc/set_exp_from_db()
|
||||
@@ -156,7 +155,10 @@ GLOBAL_PROTECT(exp_to_update)
|
||||
return -1
|
||||
if(!SSdbcore.Connect())
|
||||
return -1
|
||||
var/datum/DBQuery/exp_read = SSdbcore.NewQuery("SELECT job, minutes FROM [format_table_name("role_time")] WHERE ckey = '[sanitizeSQL(ckey)]'")
|
||||
var/datum/db_query/exp_read = SSdbcore.NewQuery(
|
||||
"SELECT job, minutes FROM [format_table_name("role_time")] WHERE ckey = :ckey",
|
||||
list("ckey" = ckey)
|
||||
)
|
||||
if(!exp_read.Execute(async = TRUE))
|
||||
qdel(exp_read)
|
||||
return -1
|
||||
@@ -188,7 +190,10 @@ GLOBAL_PROTECT(exp_to_update)
|
||||
else
|
||||
prefs.db_flags |= newflag
|
||||
|
||||
var/datum/DBQuery/flag_update = SSdbcore.NewQuery("UPDATE [format_table_name("player")] SET flags = '[prefs.db_flags]' WHERE ckey='[sanitizeSQL(ckey)]'")
|
||||
var/datum/db_query/flag_update = SSdbcore.NewQuery(
|
||||
"UPDATE [format_table_name("player")] SET flags=:flags WHERE ckey=:ckey",
|
||||
list("flags" = "[prefs.db_flags]", "ckey" = ckey)
|
||||
)
|
||||
|
||||
if(!flag_update.Execute())
|
||||
qdel(flag_update)
|
||||
@@ -256,8 +261,8 @@ GLOBAL_PROTECT(exp_to_update)
|
||||
CRASH("invalid job value [jtype]:[jvalue]")
|
||||
LAZYINITLIST(GLOB.exp_to_update)
|
||||
GLOB.exp_to_update.Add(list(list(
|
||||
"job" = "'[sanitizeSQL(jtype)]'",
|
||||
"ckey" = "'[sanitizeSQL(ckey)]'",
|
||||
"job" = jtype,
|
||||
"ckey" = ckey,
|
||||
"minutes" = jvalue)))
|
||||
prefs.exp[jtype] += jvalue
|
||||
addtimer(CALLBACK(SSblackbox,/datum/controller/subsystem/blackbox/proc/update_exp_db),20,TIMER_OVERRIDE|TIMER_UNIQUE)
|
||||
@@ -268,7 +273,10 @@ GLOBAL_PROTECT(exp_to_update)
|
||||
if(!SSdbcore.Connect())
|
||||
return FALSE
|
||||
|
||||
var/datum/DBQuery/flags_read = SSdbcore.NewQuery("SELECT flags FROM [format_table_name("player")] WHERE ckey='[ckey]'")
|
||||
var/datum/db_query/flags_read = SSdbcore.NewQuery(
|
||||
"SELECT flags FROM [format_table_name("player")] WHERE ckey=:ckey",
|
||||
list("ckey" = ckey)
|
||||
)
|
||||
|
||||
if(!flags_read.Execute(async = TRUE))
|
||||
qdel(flags_read)
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#define BOOKCASE_UNANCHORED 0
|
||||
#define BOOKCASE_ANCHORED 1
|
||||
#define BOOKCASE_FINISHED 2
|
||||
|
||||
/* Library Items
|
||||
*
|
||||
* Contains:
|
||||
@@ -17,69 +21,85 @@
|
||||
desc = "A great place for storing knowledge."
|
||||
anchored = FALSE
|
||||
density = TRUE
|
||||
opacity = 0
|
||||
opacity = FALSE
|
||||
resistance_flags = FLAMMABLE
|
||||
max_integrity = 200
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 0)
|
||||
var/state = 0
|
||||
var/list/allowed_books = list(/obj/item/book, /obj/item/spellbook, /obj/item/storage/book, /obj/item/gun/magic/wand/book) //Things allowed in the bookcase
|
||||
var/state = BOOKCASE_UNANCHORED
|
||||
/// When enabled, books_to_load number of random books will be generated for this bookcase when first interacted with.
|
||||
var/load_random_books = FALSE
|
||||
/// The category of books to pick from when populating random books.
|
||||
var/random_category = null
|
||||
/// How many random books to generate.
|
||||
var/books_to_load = 0
|
||||
|
||||
/obj/structure/bookcase/examine(mob/user)
|
||||
. = ..()
|
||||
if(!anchored)
|
||||
. += "<span class='notice'>The <i>bolts</i> on the bottom are unsecured.</span>"
|
||||
if(anchored)
|
||||
else
|
||||
. += "<span class='notice'>It's secured in place with <b>bolts</b>.</span>"
|
||||
switch(state)
|
||||
if(0)
|
||||
if(BOOKCASE_UNANCHORED)
|
||||
. += "<span class='notice'>There's a <b>small crack</b> visible on the back panel.</span>"
|
||||
if(1)
|
||||
if(BOOKCASE_ANCHORED)
|
||||
. += "<span class='notice'>There's space inside for a <i>wooden</i> shelf.</span>"
|
||||
if(2)
|
||||
if(BOOKCASE_FINISHED)
|
||||
. += "<span class='notice'>There's a <b>small crack</b> visible on the shelf.</span>"
|
||||
|
||||
/obj/structure/bookcase/Initialize(mapload)
|
||||
. = ..()
|
||||
if(!mapload)
|
||||
return
|
||||
state = 2
|
||||
icon_state = "book-0"
|
||||
anchored = TRUE
|
||||
set_anchored(TRUE)
|
||||
state = BOOKCASE_FINISHED
|
||||
for(var/obj/item/I in loc)
|
||||
if(istype(I, /obj/item/book))
|
||||
I.forceMove(src)
|
||||
if(!isbook(I))
|
||||
continue
|
||||
I.forceMove(src)
|
||||
update_icon()
|
||||
|
||||
/obj/structure/bookcase/set_anchored(anchorvalue)
|
||||
. = ..()
|
||||
if(isnull(.))
|
||||
return
|
||||
state = anchorvalue
|
||||
if(!anchorvalue) //in case we were vareditted or uprooted by a hostile mob, ensure we drop all our books instead of having them disappear till we're rebuild.
|
||||
var/atom/Tsec = drop_location()
|
||||
for(var/obj/I in contents)
|
||||
if(!isbook(I))
|
||||
continue
|
||||
I.forceMove(Tsec)
|
||||
update_icon()
|
||||
|
||||
/obj/structure/bookcase/attackby(obj/item/I, mob/user, params)
|
||||
switch(state)
|
||||
if(0)
|
||||
if(BOOKCASE_UNANCHORED)
|
||||
if(I.tool_behaviour == TOOL_WRENCH)
|
||||
if(I.use_tool(src, user, 20, volume=50))
|
||||
to_chat(user, "<span class='notice'>You wrench the frame into place.</span>")
|
||||
anchored = TRUE
|
||||
state = 1
|
||||
if(I.tool_behaviour == TOOL_CROWBAR)
|
||||
set_anchored(TRUE)
|
||||
else if(I.tool_behaviour == TOOL_CROWBAR)
|
||||
if(I.use_tool(src, user, 20, volume=50))
|
||||
to_chat(user, "<span class='notice'>You pry the frame apart.</span>")
|
||||
deconstruct(TRUE)
|
||||
|
||||
if(1)
|
||||
if(BOOKCASE_ANCHORED)
|
||||
if(istype(I, /obj/item/stack/sheet/mineral/wood))
|
||||
var/obj/item/stack/sheet/mineral/wood/W = I
|
||||
if(W.get_amount() >= 2)
|
||||
W.use(2)
|
||||
to_chat(user, "<span class='notice'>You add a shelf.</span>")
|
||||
state = 2
|
||||
icon_state = "book-0"
|
||||
if(I.tool_behaviour == TOOL_WRENCH)
|
||||
state = BOOKCASE_FINISHED
|
||||
update_icon()
|
||||
else if(I.tool_behaviour == TOOL_WRENCH)
|
||||
I.play_tool_sound(src, 100)
|
||||
to_chat(user, "<span class='notice'>You unwrench the frame.</span>")
|
||||
anchored = FALSE
|
||||
state = 0
|
||||
set_anchored(FALSE)
|
||||
|
||||
if(2)
|
||||
if(BOOKCASE_FINISHED)
|
||||
var/datum/component/storage/STR = I.GetComponent(/datum/component/storage)
|
||||
if(is_type_in_list(I, allowed_books))
|
||||
if(isbook(I))
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
return
|
||||
update_icon()
|
||||
@@ -107,19 +127,22 @@
|
||||
I.play_tool_sound(src, 100)
|
||||
to_chat(user, "<span class='notice'>You pry the shelf out.</span>")
|
||||
new /obj/item/stack/sheet/mineral/wood(drop_location(), 2)
|
||||
state = 1
|
||||
icon_state = "bookempty"
|
||||
state = BOOKCASE_ANCHORED
|
||||
update_icon()
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/bookcase/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
if(. || !istype(user))
|
||||
|
||||
/obj/structure/bookcase/on_attack_hand(mob/living/user)
|
||||
if(!istype(user))
|
||||
return
|
||||
if(load_random_books)
|
||||
create_random_books(books_to_load, src, FALSE, random_category)
|
||||
load_random_books = FALSE
|
||||
if(contents.len)
|
||||
var/obj/item/book/choice = input("Which book would you like to remove from the shelf?") as null|obj in contents
|
||||
var/obj/item/book/choice = input(user, "Which book would you like to remove from the shelf?") as null|obj in sortNames(contents.Copy())
|
||||
if(choice)
|
||||
if(!CHECK_MOBILITY(user, MOBILITY_USE) || !in_range(loc, user))
|
||||
if(!(user.mobility_flags & MOBILITY_USE) || user.stat != CONSCIOUS || !in_range(loc, user))
|
||||
return
|
||||
if(ishuman(user))
|
||||
if(!user.get_active_held_item())
|
||||
@@ -128,36 +151,25 @@
|
||||
choice.forceMove(drop_location())
|
||||
update_icon()
|
||||
|
||||
/obj/structure/bookcase/attack_ghost(mob/dead/observer/user)
|
||||
. = ..()
|
||||
if(!length(contents))
|
||||
to_chat(user, "<span class='warning'>It's empty!</span>")
|
||||
return
|
||||
var/obj/item/book/choice = input("Which book would you like to read?") as null|obj in contents
|
||||
if(choice)
|
||||
if(!istype(choice)) //spellbook, cult tome, or the one weird bible storage
|
||||
to_chat(user,"A mysterious force is keeping you from reading that.")
|
||||
return
|
||||
choice.attack_ghost(user)
|
||||
|
||||
/obj/structure/bookcase/deconstruct(disassembled = TRUE)
|
||||
new /obj/item/stack/sheet/mineral/wood(loc, 4)
|
||||
for(var/obj/item/book/B in contents)
|
||||
B.forceMove(get_turf(src))
|
||||
qdel(src)
|
||||
var/atom/Tsec = drop_location()
|
||||
new /obj/item/stack/sheet/mineral/wood(Tsec, 4)
|
||||
for(var/obj/item/I in contents)
|
||||
if(!isbook(I))
|
||||
continue
|
||||
I.forceMove(Tsec)
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/structure/bookcase/update_icon_state()
|
||||
icon_state = "book-[min(length(contents), 5)]"
|
||||
|
||||
|
||||
/obj/structure/bookcase/manuals/medical
|
||||
name = "medical manuals bookcase"
|
||||
|
||||
/obj/structure/bookcase/manuals/medical/Initialize()
|
||||
. = ..()
|
||||
new /obj/item/book/manual/wiki/medical_cloning(src)
|
||||
update_icon()
|
||||
if(state == BOOKCASE_UNANCHORED || state == BOOKCASE_ANCHORED)
|
||||
icon_state = "bookempty"
|
||||
return
|
||||
var/amount = contents.len
|
||||
if(load_random_books)
|
||||
amount += books_to_load
|
||||
icon_state = "book-[clamp(amount, 0, 5)]"
|
||||
|
||||
|
||||
/obj/structure/bookcase/manuals/engineering
|
||||
@@ -198,34 +210,27 @@
|
||||
var/dat //Actual page content
|
||||
var/due_date = 0 //Game time in 1/10th seconds
|
||||
var/author //Who wrote the thing, can be changed by pen or PC. It is not automatically assigned
|
||||
var/unique = 0 //0 - Normal book, 1 - Should not be treated as normal book, unable to be copied, unable to be modified
|
||||
var/unique = FALSE //false - Normal book, true - Should not be treated as normal book, unable to be copied, unable to be modified
|
||||
var/title //The real name of the book.
|
||||
var/window_size = null // Specific window size for the book, i.e: "1920x1080", Size x Width
|
||||
|
||||
|
||||
/obj/item/book/attack_self(mob/user)
|
||||
if(is_blind(user))
|
||||
to_chat(user, "<span class='warning'>As you are trying to read, you suddenly feel very stupid!</span>")
|
||||
return
|
||||
if(ismonkey(user))
|
||||
to_chat(user, "<span class='notice'>You skim through the book but can't comprehend any of it.</span>")
|
||||
if(!user.can_read(src))
|
||||
return
|
||||
if(dat)
|
||||
show_to(user)
|
||||
user.visible_message("[user] opens a book titled \"[title]\" and begins reading intently.")
|
||||
user << browse("<TT><I>Penned by [author].</I></TT> <BR>" + "[dat]", "window=book[window_size != null ? ";size=[window_size]" : ""]")
|
||||
user.visible_message("<span class='notice'>[user] opens a book titled \"[title]\" and begins reading intently.</span>")
|
||||
// SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "book_nerd", /datum/mood_event/book_nerd)
|
||||
onclose(user, "book")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>This book is completely blank!</span>")
|
||||
|
||||
/obj/item/book/attack_ghost(mob/dead/observer/O)
|
||||
. = ..()
|
||||
show_to(O)
|
||||
|
||||
/obj/item/book/proc/show_to(mob/user)
|
||||
user << browse("<TT><I>Penned by [author].</I></TT> <BR>" + "[dat]", "window=book[window_size != null ? ";size=[window_size]" : ""]")
|
||||
|
||||
/obj/item/book/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/pen))
|
||||
if(is_blind(user))
|
||||
to_chat(user, "<span class='warning'> As you are trying to write on the book, you suddenly feel very stupid!</span>")
|
||||
if(user.is_blind())
|
||||
to_chat(user, "<span class='warning'>As you are trying to write on the book, you suddenly feel very stupid!</span>")
|
||||
return
|
||||
if(unique)
|
||||
to_chat(user, "<span class='warning'>These pages don't seem to take the ink well! Looks like you can't modify it.</span>")
|
||||
@@ -243,10 +248,10 @@
|
||||
if(!user.canUseTopic(src, BE_CLOSE, literate))
|
||||
return
|
||||
if (length(newtitle) > 20)
|
||||
to_chat(user, "That title won't fit on the cover!")
|
||||
to_chat(user, "<span class='warning'>That title won't fit on the cover!</span>")
|
||||
return
|
||||
if(!newtitle)
|
||||
to_chat(user, "That title is invalid.")
|
||||
to_chat(user, "<span class='warning'>That title is invalid.</span>")
|
||||
return
|
||||
else
|
||||
name = newtitle
|
||||
@@ -256,7 +261,7 @@
|
||||
if(!user.canUseTopic(src, BE_CLOSE, literate))
|
||||
return
|
||||
if(!content)
|
||||
to_chat(user, "The content is invalid.")
|
||||
to_chat(user, "<span class='warning'>The content is invalid.</span>")
|
||||
return
|
||||
else
|
||||
dat += content
|
||||
@@ -265,7 +270,7 @@
|
||||
if(!user.canUseTopic(src, BE_CLOSE, literate))
|
||||
return
|
||||
if(!newauthor)
|
||||
to_chat(user, "The name is invalid.")
|
||||
to_chat(user, "<span class='warning'>The name is invalid.</span>")
|
||||
return
|
||||
else
|
||||
author = newauthor
|
||||
@@ -275,32 +280,32 @@
|
||||
else if(istype(I, /obj/item/barcodescanner))
|
||||
var/obj/item/barcodescanner/scanner = I
|
||||
if(!scanner.computer)
|
||||
to_chat(user, "[I]'s screen flashes: 'No associated computer found!'")
|
||||
to_chat(user, "<span class='alert'>[I]'s screen flashes: 'No associated computer found!'</span>")
|
||||
else
|
||||
switch(scanner.mode)
|
||||
if(0)
|
||||
scanner.book = src
|
||||
to_chat(user, "[I]'s screen flashes: 'Book stored in buffer.'")
|
||||
to_chat(user, "<span class='notice'>[I]'s screen flashes: 'Book stored in buffer.'</span>")
|
||||
if(1)
|
||||
scanner.book = src
|
||||
scanner.computer.buffer_book = name
|
||||
to_chat(user, "[I]'s screen flashes: 'Book stored in buffer. Book title stored in associated computer buffer.'")
|
||||
to_chat(user, "<span class='notice'>[I]'s screen flashes: 'Book stored in buffer. Book title stored in associated computer buffer.'</span>")
|
||||
if(2)
|
||||
scanner.book = src
|
||||
for(var/datum/borrowbook/b in scanner.computer.checkouts)
|
||||
if(b.bookname == name)
|
||||
scanner.computer.checkouts.Remove(b)
|
||||
to_chat(user, "[I]'s screen flashes: 'Book stored in buffer. Book has been checked in.'")
|
||||
to_chat(user, "<span class='notice'>[I]'s screen flashes: 'Book stored in buffer. Book has been checked in.'</span>")
|
||||
return
|
||||
to_chat(user, "[I]'s screen flashes: 'Book stored in buffer. No active check-out record found for current title.'")
|
||||
to_chat(user, "<span class='notice'>[I]'s screen flashes: 'Book stored in buffer. No active check-out record found for current title.'</span>")
|
||||
if(3)
|
||||
scanner.book = src
|
||||
for(var/obj/item/book in scanner.computer.inventory)
|
||||
if(book == src)
|
||||
to_chat(user, "[I]'s screen flashes: 'Book stored in buffer. Title already present in inventory, aborting to avoid duplicate entry.'")
|
||||
to_chat(user, "<span class='alert'>[I]'s screen flashes: 'Book stored in buffer. Title already present in inventory, aborting to avoid duplicate entry.'</span>")
|
||||
return
|
||||
scanner.computer.inventory.Add(src)
|
||||
to_chat(user, "[I]'s screen flashes: 'Book stored in buffer. Title added to general inventory.'")
|
||||
to_chat(user, "<span class='notice'>[I]'s screen flashes: 'Book stored in buffer. Title added to general inventory.'</span>")
|
||||
|
||||
else if(istype(I, /obj/item/kitchen/knife) || I.tool_behaviour == TOOL_WIRECUTTER)
|
||||
to_chat(user, "<span class='notice'>You begin to carve out [title]...</span>")
|
||||
@@ -361,3 +366,8 @@
|
||||
else
|
||||
to_chat(user, "<font color=red>No associated computer found. Only local scans will function properly.</font>")
|
||||
to_chat(user, "\n")
|
||||
|
||||
|
||||
#undef BOOKCASE_UNANCHORED
|
||||
#undef BOOKCASE_ANCHORED
|
||||
#undef BOOKCASE_FINISHED
|
||||
|
||||
@@ -25,12 +25,13 @@
|
||||
var/title
|
||||
var/category = "Any"
|
||||
var/author
|
||||
var/SQLquery
|
||||
clockwork = TRUE //it'd look weird
|
||||
var/search_page = 0
|
||||
COOLDOWN_DECLARE(library_visitor_topic_cooldown)
|
||||
clockwork = TRUE
|
||||
|
||||
/obj/machinery/computer/libraryconsole/ui_interact(mob/user)
|
||||
. = ..()
|
||||
var/dat = "" // <META HTTP-EQUIV='Refresh' CONTENT='10'>
|
||||
var/list/dat = list() // <META HTTP-EQUIV='Refresh' CONTENT='10'>
|
||||
switch(screenstate)
|
||||
if(0)
|
||||
dat += "<h2>Search Settings</h2><br>"
|
||||
@@ -43,13 +44,43 @@
|
||||
dat += "<font color=red><b>ERROR</b>: Unable to contact External Archive. Please contact your system administrator for assistance.</font><BR>"
|
||||
else if(QDELETED(user))
|
||||
return
|
||||
else if(!SQLquery)
|
||||
dat += "<font color=red><b>ERROR</b>: Malformed search request. Please contact your system administrator for assistance.</font><BR>"
|
||||
else
|
||||
dat += "<table>"
|
||||
dat += "<tr><td>AUTHOR</td><td>TITLE</td><td>CATEGORY</td><td>SS<sup>13</sup>BN</td></tr>"
|
||||
|
||||
var/datum/DBQuery/query_library_list_books = SSdbcore.NewQuery(SQLquery)
|
||||
var/bookcount = 0
|
||||
var/booksperpage = 20
|
||||
var/datum/db_query/query_library_count_books = SSdbcore.NewQuery({"
|
||||
SELECT COUNT(id) FROM [format_table_name("library")]
|
||||
WHERE isnull(deleted)
|
||||
AND author LIKE CONCAT('%',:author,'%')
|
||||
AND title LIKE CONCAT('%',:title,'%')
|
||||
AND (:category = 'Any' OR category = :category)
|
||||
"}, list("author" = author, "title" = title, "category" = category))
|
||||
if(!query_library_count_books.warn_execute())
|
||||
qdel(query_library_count_books)
|
||||
return
|
||||
if(query_library_count_books.NextRow())
|
||||
bookcount = text2num(query_library_count_books.item[1])
|
||||
qdel(query_library_count_books)
|
||||
if(bookcount > booksperpage)
|
||||
dat += "<b>Page: </b>"
|
||||
var/pagecount = 1
|
||||
var/list/pagelist = list()
|
||||
while(bookcount > 0)
|
||||
pagelist += "<a href='?src=[REF(src)];bookpagecount=[pagecount - 1]'>[pagecount == search_page + 1 ? "<b>\[[pagecount]\]</b>" : "\[[pagecount]\]"]</a>"
|
||||
bookcount -= booksperpage
|
||||
pagecount++
|
||||
dat += pagelist.Join(" | ")
|
||||
search_page = text2num(search_page)
|
||||
var/datum/db_query/query_library_list_books = SSdbcore.NewQuery({"
|
||||
SELECT author, title, category, id
|
||||
FROM [format_table_name("library")]
|
||||
WHERE isnull(deleted)
|
||||
AND author LIKE CONCAT('%',:author,'%')
|
||||
AND title LIKE CONCAT('%',:title,'%')
|
||||
AND (:category = 'Any' OR category = :category)
|
||||
LIMIT :skip, :take
|
||||
"}, list("author" = author, "title" = title, "category" = category, "skip" = booksperpage * search_page, "take" = booksperpage))
|
||||
if(!query_library_list_books.Execute())
|
||||
dat += "<font color=red><b>ERROR</b>: Unable to retrieve book listings. Please contact your system administrator for assistance.</font><BR>"
|
||||
else
|
||||
@@ -65,12 +96,15 @@
|
||||
dat += "</table><BR>"
|
||||
dat += "<A href='?src=[REF(src)];back=1'>\[Go Back\]</A><BR>"
|
||||
var/datum/browser/popup = new(user, "publiclibrary", name, 600, 400)
|
||||
popup.set_content(dat)
|
||||
popup.set_content(jointext(dat, ""))
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/computer/libraryconsole/Topic(href, href_list)
|
||||
if(!COOLDOWN_FINISHED(src, library_visitor_topic_cooldown))
|
||||
return
|
||||
COOLDOWN_START(src, library_visitor_topic_cooldown, 1 SECONDS)
|
||||
. = ..()
|
||||
if(..())
|
||||
if(.)
|
||||
usr << browse(null, "window=publiclibrary")
|
||||
onclose(usr, "publiclibrary")
|
||||
return
|
||||
@@ -81,29 +115,24 @@
|
||||
title = sanitize(newtitle)
|
||||
else
|
||||
title = null
|
||||
title = sanitizeSQL(title)
|
||||
if(href_list["setcategory"])
|
||||
var/newcategory = input("Choose a category to search for:") in list("Any", "Fiction", "Non-Fiction", "Adult", "Reference", "Religion")
|
||||
if(newcategory)
|
||||
category = sanitize(newcategory)
|
||||
else
|
||||
category = "Any"
|
||||
category = sanitizeSQL(category)
|
||||
if(href_list["setauthor"])
|
||||
var/newauthor = input("Enter an author to search for:") as text|null
|
||||
if(newauthor)
|
||||
author = sanitize(newauthor)
|
||||
else
|
||||
author = null
|
||||
author = sanitizeSQL(author)
|
||||
if(href_list["search"])
|
||||
SQLquery = "SELECT author, title, category, id FROM [format_table_name("library")] WHERE isnull(deleted) AND "
|
||||
if(category == "Any")
|
||||
SQLquery += "author LIKE '%[author]%' AND title LIKE '%[title]%'"
|
||||
else
|
||||
SQLquery += "author LIKE '%[author]%' AND title LIKE '%[title]%' AND category='[category]'"
|
||||
screenstate = 1
|
||||
|
||||
if(href_list["bookpagecount"])
|
||||
search_page = text2num(href_list["bookpagecount"])
|
||||
|
||||
if(href_list["back"])
|
||||
screenstate = 0
|
||||
|
||||
@@ -120,44 +149,12 @@
|
||||
var/getdate
|
||||
var/duedate
|
||||
|
||||
/*
|
||||
* Cachedbook datum
|
||||
*/
|
||||
/datum/cachedbook // Datum used to cache the SQL DB books locally in order to achieve a performance gain.
|
||||
var/id
|
||||
var/title
|
||||
var/author
|
||||
var/category
|
||||
|
||||
GLOBAL_LIST(cachedbooks) // List of our cached book datums
|
||||
|
||||
|
||||
/proc/load_library_db_to_cache()
|
||||
if(GLOB.cachedbooks)
|
||||
return
|
||||
if(!SSdbcore.Connect())
|
||||
return
|
||||
GLOB.cachedbooks = list()
|
||||
var/datum/DBQuery/query_library_cache = SSdbcore.NewQuery("SELECT id, author, title, category FROM [format_table_name("library")] WHERE isnull(deleted)")
|
||||
if(!query_library_cache.Execute())
|
||||
qdel(query_library_cache)
|
||||
return
|
||||
while(query_library_cache.NextRow())
|
||||
var/datum/cachedbook/newbook = new()
|
||||
newbook.id = query_library_cache.item[1]
|
||||
newbook.author = query_library_cache.item[2]
|
||||
newbook.title = query_library_cache.item[3]
|
||||
newbook.category = query_library_cache.item[4]
|
||||
GLOB.cachedbooks += newbook
|
||||
qdel(query_library_cache)
|
||||
|
||||
|
||||
|
||||
#define PRINTER_COOLDOWN 60
|
||||
|
||||
/*
|
||||
* Library Computer
|
||||
* After 860 days, it's finally a buildable computer.
|
||||
* After 860 days, it's finally a buildable computer.*
|
||||
* * i cannot change maps because you are a buch of fucks who ignore map changes
|
||||
*/
|
||||
// TODO: Make this an actual /obj/machinery/computer that can be crafted from circuit boards and such
|
||||
// It is August 22nd, 2012... This TODO has already been here for months.. I wonder how long it'll last before someone does something about it.
|
||||
@@ -165,11 +162,15 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
|
||||
/obj/machinery/computer/libraryconsole/bookmanagement
|
||||
name = "book inventory management console"
|
||||
desc = "Librarian's command station."
|
||||
screenstate = 0 // 0 - Main Menu, 1 - Inventory, 2 - Checked Out, 3 - Check Out a Book
|
||||
verb_say = "beeps"
|
||||
verb_ask = "beeps"
|
||||
verb_exclaim = "beeps"
|
||||
pass_flags = PASSTABLE
|
||||
|
||||
circuit = /obj/item/circuitboard/computer/libraryconsole
|
||||
|
||||
// var/screenstate = 0 // 0 - Main Menu, 1 - Inventory, 2 - Checked Out, 3 - Check Out a Book
|
||||
|
||||
var/arcanecheckout = 0
|
||||
var/buffer_book
|
||||
var/buffer_mob
|
||||
@@ -178,25 +179,9 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
|
||||
var/list/inventory = list()
|
||||
var/checkoutperiod = 5 // In minutes
|
||||
var/obj/machinery/libraryscanner/scanner // Book scanner that will be used when uploading books to the Archive
|
||||
var/list/libcomp_menu
|
||||
var/page = 1 //current page of the external archives
|
||||
var/cooldown = 0
|
||||
|
||||
/obj/machinery/computer/libraryconsole/bookmanagement/proc/build_library_menu()
|
||||
if(libcomp_menu)
|
||||
return
|
||||
load_library_db_to_cache()
|
||||
if(!GLOB.cachedbooks)
|
||||
return
|
||||
libcomp_menu = list("")
|
||||
|
||||
for(var/i in 1 to GLOB.cachedbooks.len)
|
||||
var/datum/cachedbook/C = GLOB.cachedbooks[i]
|
||||
var/page = round(i/250)+1
|
||||
if (libcomp_menu.len < page)
|
||||
libcomp_menu.len = page
|
||||
libcomp_menu[page] = ""
|
||||
libcomp_menu[page] += "<tr><td>[C.author]</td><td>[C.title]</td><td>[C.category]</td><td><A href='?src=[REF(src)];targetid=[C.id]'>\[Order\]</A></td></tr>\n"
|
||||
var/printer_cooldown = 0
|
||||
COOLDOWN_DECLARE(library_console_topic_cooldown)
|
||||
|
||||
/obj/machinery/computer/libraryconsole/bookmanagement/Initialize()
|
||||
. = ..()
|
||||
@@ -258,17 +243,37 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
|
||||
dat += "<A href='?src=[REF(src)];switchscreen=0'>(Return to main menu)</A><BR>"
|
||||
if(4)
|
||||
dat += "<h3>External Archive</h3>"
|
||||
build_library_menu()
|
||||
|
||||
if(!GLOB.cachedbooks)
|
||||
if(!SSdbcore.Connect())
|
||||
dat += "<font color=red><b>ERROR</b>: Unable to contact External Archive. Please contact your system administrator for assistance.</font>"
|
||||
else
|
||||
var/booksperpage = 50
|
||||
var/pagecount
|
||||
var/datum/db_query/query_library_count_books = SSdbcore.NewQuery("SELECT COUNT(id) FROM [format_table_name("library")] WHERE isnull(deleted)")
|
||||
if(!query_library_count_books.Execute())
|
||||
qdel(query_library_count_books)
|
||||
return
|
||||
if(query_library_count_books.NextRow())
|
||||
pagecount = CEILING(text2num(query_library_count_books.item[1]) / booksperpage, 1)
|
||||
qdel(query_library_count_books)
|
||||
var/list/booklist = list()
|
||||
var/datum/db_query/query_library_get_books = SSdbcore.NewQuery({"
|
||||
SELECT id, author, title, category
|
||||
FROM [format_table_name("library")]
|
||||
WHERE isnull(deleted)
|
||||
LIMIT :skip, :take
|
||||
"}, list("skip" = booksperpage * (page - 1), "take" = booksperpage))
|
||||
if(!query_library_get_books.Execute())
|
||||
qdel(query_library_get_books)
|
||||
return
|
||||
while(query_library_get_books.NextRow())
|
||||
booklist += "<tr><td>[query_library_get_books.item[2]]</td><td>[query_library_get_books.item[3]]</td><td>[query_library_get_books.item[4]]</td><td><A href='?src=[REF(src)];targetid=[query_library_get_books.item[1]]'>\[Order\]</A></td></tr>\n"
|
||||
dat += "<A href='?src=[REF(src)];orderbyid=1'>(Order book by SS<sup>13</sup>BN)</A><BR><BR>"
|
||||
dat += "<table>"
|
||||
dat += "<tr><td>AUTHOR</td><td>TITLE</td><td>CATEGORY</td><td></td></tr>"
|
||||
dat += libcomp_menu[clamp(page,1,libcomp_menu.len)]
|
||||
dat += "<tr><td><A href='?src=[REF(src)];page=[(max(1,page-1))]'><<<<</A></td> <td></td> <td></td> <td><span style='text-align:right'><A href='?src=[REF(src)];page=[(min(libcomp_menu.len,page+1))]'>>>>></A></span></td></tr>"
|
||||
dat += jointext(booklist, "")
|
||||
dat += "<tr><td><A href='?src=[REF(src)];page=[max(1,page-1)]'><<<<</A></td> <td></td> <td></td> <td><span style='text-align:right'><A href='?src=[REF(src)];page=[min(pagecount,page+1)]'>>>>></A></span></td></tr>"
|
||||
dat += "</table>"
|
||||
qdel(query_library_get_books)
|
||||
dat += "<BR><A href='?src=[REF(src)];switchscreen=0'>(Return to main menu)</A><BR>"
|
||||
if(5)
|
||||
dat += "<H3>Upload a New Title</H3>"
|
||||
@@ -321,33 +326,27 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
|
||||
return null
|
||||
|
||||
/obj/machinery/computer/libraryconsole/bookmanagement/proc/print_forbidden_lore(mob/user)
|
||||
var/spook = pick("blood", "brass")
|
||||
var/turf/T = get_turf(src)
|
||||
if(spook == "blood")
|
||||
new /obj/item/melee/cultblade/dagger(T)
|
||||
else
|
||||
new /obj/item/clockwork/slab(T)
|
||||
|
||||
to_chat(user, "<span class='warning'>Your sanity barely endures the seconds spent in the vault's browsing window. The only thing to remind you of this when you stop browsing is a [spook == "blood" ? "sinister dagger" : "strange metal tablet"] sitting on the desk. You don't even remember where it came from...</span>")
|
||||
user.visible_message("[user] stares at the blank screen for a few moments, [user.p_their()] expression frozen in fear. When [user.p_they()] finally awaken[user.p_s()] from it, [user.p_they()] look[user.p_s()] a lot older.", 2)
|
||||
new /obj/item/melee/cultblade/dagger(get_turf(src))
|
||||
to_chat(user, "<span class='warning'>Your sanity barely endures the seconds spent in the vault's browsing window. The only thing to remind you of this when you stop browsing is a sinister dagger sitting on the desk. You don't even remember where it came from...</span>")
|
||||
user.visible_message("<span class='warning'>[user] stares at the blank screen for a few moments, [user.p_their()] expression frozen in fear. When [user.p_they()] finally awaken[user.p_s()] from it, [user.p_they()] look[user.p_s()] a lot older.</span>", 2)
|
||||
|
||||
/obj/machinery/computer/libraryconsole/bookmanagement/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/barcodescanner))
|
||||
var/obj/item/barcodescanner/scanner = W
|
||||
scanner.computer = src
|
||||
to_chat(user, "[scanner]'s associated machine has been set to [src].")
|
||||
audible_message("[src] lets out a low, short blip.")
|
||||
to_chat(user, "<span class='notice'>[scanner]'s associated machine has been set to [src].</span>")
|
||||
audible_message("<span class='hear'>[src] lets out a low, short blip.</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/libraryconsole/bookmanagement/emag_act(mob/user)
|
||||
. = ..()
|
||||
if(!density || obj_flags & EMAGGED)
|
||||
return
|
||||
obj_flags |= EMAGGED
|
||||
return TRUE
|
||||
if(density && !(obj_flags & EMAGGED))
|
||||
obj_flags |= EMAGGED
|
||||
|
||||
/obj/machinery/computer/libraryconsole/bookmanagement/Topic(href, href_list)
|
||||
if(!COOLDOWN_FINISHED(src, library_console_topic_cooldown))
|
||||
return
|
||||
COOLDOWN_START(src, library_console_topic_cooldown, 1 SECONDS)
|
||||
if(..())
|
||||
usr << browse(null, "window=library")
|
||||
onclose(usr, "library")
|
||||
@@ -385,7 +384,7 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
|
||||
if(checkoutperiod < 1)
|
||||
checkoutperiod = 1
|
||||
if(href_list["editbook"])
|
||||
buffer_book = stripped_input(usr, "Enter the book's title:")
|
||||
buffer_book = stripped_input(usr, "Enter the book's title:", max_length = 45)
|
||||
if(href_list["editmob"])
|
||||
buffer_mob = stripped_input(usr, "Enter the recipient's name:", max_length = MAX_NAME_LEN)
|
||||
if(href_list["checkout"])
|
||||
@@ -404,7 +403,7 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
|
||||
if(b && istype(b))
|
||||
inventory.Remove(b)
|
||||
if(href_list["setauthor"])
|
||||
var/newauthor = stripped_input(usr, "Enter the author's name: ")
|
||||
var/newauthor = stripped_input(usr, "Enter the author's name: ", max_length = 45)
|
||||
if(newauthor)
|
||||
scanner.cache.author = newauthor
|
||||
if(href_list["setcategory"])
|
||||
@@ -419,14 +418,11 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
|
||||
if (!SSdbcore.Connect())
|
||||
alert("Connection to Archive has been severed. Aborting.")
|
||||
else
|
||||
|
||||
var/sqltitle = sanitizeSQL(scanner.cache.name)
|
||||
var/sqlauthor = sanitizeSQL(scanner.cache.author)
|
||||
var/sqlcontent = sanitizeSQL(scanner.cache.dat)
|
||||
var/sqlcategory = sanitizeSQL(upload_category)
|
||||
var/sqlckey = sanitizeSQL(usr.ckey)
|
||||
var/msg = "[key_name(usr)] has uploaded the book titled [scanner.cache.name], [length(scanner.cache.dat)] signs"
|
||||
var/datum/DBQuery/query_library_upload = SSdbcore.NewQuery("INSERT INTO [format_table_name("library")] (author, title, content, category, ckey, datetime, round_id_created) VALUES ('[sqlauthor]', '[sqltitle]', '[sqlcontent]', '[sqlcategory]', '[sqlckey]', Now(), '[GLOB.round_id]')")
|
||||
var/datum/db_query/query_library_upload = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("library")] (author, title, content, category, ckey, datetime, round_id_created)
|
||||
VALUES (:author, :title, :content, :category, :ckey, Now(), :round_id)
|
||||
"}, list("title" = scanner.cache.name, "author" = scanner.cache.author, "content" = scanner.cache.dat, "category" = upload_category, "ckey" = usr.ckey, "round_id" = GLOB.round_id))
|
||||
if(!query_library_upload.Execute())
|
||||
qdel(query_library_upload)
|
||||
alert("Database error encountered uploading to Archive")
|
||||
@@ -448,7 +444,7 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
|
||||
GLOB.news_network.SubmitArticle(scanner.cache.dat, "[scanner.cache.name]", "Nanotrasen Book Club", null)
|
||||
alert("Upload complete. Your uploaded title is now available on station newscasters.")
|
||||
if(href_list["orderbyid"])
|
||||
if(cooldown > world.time)
|
||||
if(printer_cooldown > world.time)
|
||||
say("Printer unavailable. Please allow a short time before attempting to print.")
|
||||
else
|
||||
var/orderid = input("Enter your order:") as num|null
|
||||
@@ -457,14 +453,17 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
|
||||
href_list["targetid"] = num2text(orderid)
|
||||
|
||||
if(href_list["targetid"])
|
||||
var/sqlid = sanitizeSQL(href_list["targetid"])
|
||||
var/id = href_list["targetid"]
|
||||
if (!SSdbcore.Connect())
|
||||
alert("Connection to Archive has been severed. Aborting.")
|
||||
if(cooldown > world.time)
|
||||
if(printer_cooldown > world.time)
|
||||
say("Printer unavailable. Please allow a short time before attempting to print.")
|
||||
else
|
||||
cooldown = world.time + PRINTER_COOLDOWN
|
||||
var/datum/DBQuery/query_library_print = SSdbcore.NewQuery("SELECT * FROM [format_table_name("library")] WHERE id=[sqlid] AND isnull(deleted)")
|
||||
printer_cooldown = world.time + PRINTER_COOLDOWN
|
||||
var/datum/db_query/query_library_print = SSdbcore.NewQuery(
|
||||
"SELECT * FROM [format_table_name("library")] WHERE id=:id AND isnull(deleted)",
|
||||
list("id" = id)
|
||||
)
|
||||
if(!query_library_print.Execute())
|
||||
qdel(query_library_print)
|
||||
say("PRINTER ERROR! Failed to print document (0x0000000F)")
|
||||
@@ -480,24 +479,24 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
|
||||
B.author = author
|
||||
B.dat = content
|
||||
B.icon_state = "book[rand(1,8)]"
|
||||
visible_message("[src]'s printer hums as it produces a completely bound book. How did it do that?")
|
||||
visible_message("<span class='notice'>[src]'s printer hums as it produces a completely bound book. How did it do that?</span>")
|
||||
break
|
||||
qdel(query_library_print)
|
||||
if(href_list["printbible"])
|
||||
if(cooldown < world.time)
|
||||
if(printer_cooldown < world.time)
|
||||
var/obj/item/storage/book/bible/B = new /obj/item/storage/book/bible(src.loc)
|
||||
if(GLOB.bible_icon_state && GLOB.bible_item_state)
|
||||
B.icon_state = GLOB.bible_icon_state
|
||||
B.item_state = GLOB.bible_item_state
|
||||
B.name = GLOB.bible_name
|
||||
B.deity_name = GLOB.deity
|
||||
cooldown = world.time + PRINTER_COOLDOWN
|
||||
printer_cooldown = world.time + PRINTER_COOLDOWN
|
||||
else
|
||||
say("Printer currently unavailable, please wait a moment.")
|
||||
if(href_list["printposter"])
|
||||
if(cooldown < world.time)
|
||||
if(printer_cooldown < world.time)
|
||||
new /obj/item/poster/random_official(src.loc)
|
||||
cooldown = world.time + PRINTER_COOLDOWN
|
||||
printer_cooldown = world.time + PRINTER_COOLDOWN
|
||||
else
|
||||
say("Printer currently unavailable, please wait a moment.")
|
||||
add_fingerprint(usr)
|
||||
@@ -521,7 +520,10 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/libraryscanner/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/machinery/libraryscanner/attack_hand(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
usr.set_machine(src)
|
||||
var/dat = "" // <META HTTP-EQUIV='Refresh' CONTENT='10'>
|
||||
if(cache)
|
||||
@@ -584,14 +586,14 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
|
||||
return
|
||||
if(!user.transferItemToLoc(P, src))
|
||||
return
|
||||
user.visible_message("[user] loads some paper into [src].", "You load some paper into [src].")
|
||||
audible_message("[src] begins to hum as it warms up its printing drums.")
|
||||
user.visible_message("<span class='notice'>[user] loads some paper into [src].</span>", "<span class='notice'>You load some paper into [src].</span>")
|
||||
audible_message("<span class='hear'>[src] begins to hum as it warms up its printing drums.</span>")
|
||||
busy = TRUE
|
||||
sleep(rand(200,400))
|
||||
busy = FALSE
|
||||
if(P)
|
||||
if(!stat)
|
||||
visible_message("[src] whirs as it prints and binds a new book.")
|
||||
visible_message("<span class='notice'>[src] whirs as it prints and binds a new book.</span>")
|
||||
var/obj/item/book/B = new(src.loc)
|
||||
B.dat = P.info
|
||||
B.name = "Print Job #" + "[rand(100, 999)]"
|
||||
|
||||
@@ -10,78 +10,83 @@
|
||||
|
||||
/obj/item/book/random
|
||||
icon_state = "random_book"
|
||||
var/amount = 1
|
||||
var/category = null
|
||||
/// The category of books to pick from when creating this book.
|
||||
var/random_category = null
|
||||
/// If this book has already been 'generated' yet.
|
||||
var/random_loaded = FALSE
|
||||
|
||||
/obj/item/book/random/Initialize()
|
||||
..()
|
||||
create_random_books(amount, src.loc, TRUE, category)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
/obj/item/book/random/Initialize(mapload)
|
||||
. = ..()
|
||||
icon_state = "book[rand(1,8)]"
|
||||
|
||||
/obj/item/book/random/triple
|
||||
amount = 3
|
||||
/obj/item/book/random/attack_self()
|
||||
if(!random_loaded)
|
||||
create_random_books(1, loc, TRUE, random_category, src)
|
||||
random_loaded = TRUE
|
||||
return ..()
|
||||
|
||||
/obj/structure/bookcase/random
|
||||
var/category = null
|
||||
var/book_count = 2
|
||||
load_random_books = TRUE
|
||||
books_to_load = 2
|
||||
icon_state = "random_bookcase"
|
||||
anchored = TRUE
|
||||
state = 2
|
||||
|
||||
/obj/structure/bookcase/random/Initialize(mapload)
|
||||
. = ..()
|
||||
if(!book_count || !isnum(book_count))
|
||||
update_icon()
|
||||
return
|
||||
book_count += pick(-1,-1,0,1,1)
|
||||
create_random_books(book_count, src, FALSE, category)
|
||||
if(books_to_load && isnum(books_to_load))
|
||||
books_to_load += pick(-1,-1,0,1,1)
|
||||
update_icon()
|
||||
|
||||
/proc/create_random_books(amount = 2, location, fail_loud = FALSE, category = null)
|
||||
/proc/create_random_books(amount, location, fail_loud = FALSE, category = null, obj/item/book/existing_book)
|
||||
. = list()
|
||||
if(!isnum(amount) || amount<1)
|
||||
return
|
||||
if (!SSdbcore.Connect())
|
||||
if(fail_loud || prob(5))
|
||||
var/obj/item/paper/P = new(location)
|
||||
P.info = "There once was a book from Nantucket<br>But the database failed us, so f*$! it.<br>I tried to be good to you<br>Now this is an I.O.U<br>If you're feeling entitled, well, stuff it!<br><br><font color='gray'>~</font>"
|
||||
P.update_icon()
|
||||
if(existing_book && (fail_loud || prob(5)))
|
||||
existing_book.author = "???"
|
||||
existing_book.title = "Strange book"
|
||||
existing_book.name = "Strange book"
|
||||
existing_book.dat = "There once was a book from Nantucket<br>But the database failed us, so f*$! it.<br>I tried to be good to you<br>Now this is an I.O.U<br>If you're feeling entitled, well, stuff it!<br><br><font color='gray'>~</font>"
|
||||
return
|
||||
if(prob(25))
|
||||
category = null
|
||||
var/c = category? " AND category='[sanitizeSQL(category)]'" :""
|
||||
var/datum/DBQuery/query_get_random_books = SSdbcore.NewQuery("SELECT * FROM [format_table_name("library")] WHERE isnull(deleted)[c] GROUP BY title ORDER BY rand() LIMIT [amount];") // isdeleted copyright (c) not me
|
||||
var/datum/db_query/query_get_random_books = SSdbcore.NewQuery({"
|
||||
SELECT author, title, content
|
||||
FROM [format_table_name("library")]
|
||||
WHERE isnull(deleted) AND (:category IS NULL OR category = :category)
|
||||
ORDER BY rand() LIMIT :limit
|
||||
"}, list("category" = category, "limit" = amount))
|
||||
if(query_get_random_books.Execute())
|
||||
while(query_get_random_books.NextRow())
|
||||
var/obj/item/book/B = new(location)
|
||||
. += B
|
||||
B.author = query_get_random_books.item[2]
|
||||
B.title = query_get_random_books.item[3]
|
||||
B.dat = query_get_random_books.item[4]
|
||||
var/obj/item/book/B
|
||||
B = existing_book ? existing_book : new(location)
|
||||
B.author = query_get_random_books.item[1]
|
||||
B.title = query_get_random_books.item[2]
|
||||
B.dat = query_get_random_books.item[3]
|
||||
B.name = "Book: [B.title]"
|
||||
B.icon_state= "book[rand(1,8)]"
|
||||
if(!existing_book)
|
||||
B.icon_state= "book[rand(1,8)]"
|
||||
qdel(query_get_random_books)
|
||||
|
||||
/obj/structure/bookcase/random/fiction
|
||||
name = "bookcase (Fiction)"
|
||||
category = "Fiction"
|
||||
random_category = "Fiction"
|
||||
/obj/structure/bookcase/random/nonfiction
|
||||
name = "bookcase (Non-Fiction)"
|
||||
category = "Non-fiction"
|
||||
random_category = "Non-fiction"
|
||||
/obj/structure/bookcase/random/religion
|
||||
name = "bookcase (Religion)"
|
||||
category = "Religion"
|
||||
random_category = "Religion"
|
||||
/obj/structure/bookcase/random/adult
|
||||
name = "bookcase (Adult)"
|
||||
category = "Adult"
|
||||
random_category = "Adult"
|
||||
|
||||
/obj/structure/bookcase/random/reference
|
||||
name = "bookcase (Reference)"
|
||||
category = "Reference"
|
||||
random_category = "Reference"
|
||||
var/ref_book_prob = 20
|
||||
|
||||
/obj/structure/bookcase/random/reference/Initialize(mapload)
|
||||
. = ..()
|
||||
while(book_count > 0 && prob(ref_book_prob))
|
||||
book_count--
|
||||
while(books_to_load > 0 && prob(ref_book_prob))
|
||||
books_to_load--
|
||||
new /obj/item/book/manual/random(src)
|
||||
|
||||
@@ -54,24 +54,7 @@
|
||||
output += "<p>[LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)]</p>"
|
||||
|
||||
if(!IsGuestKey(src.key))
|
||||
if (SSdbcore.Connect())
|
||||
var/isadmin = 0
|
||||
if(src.client && src.client.holder)
|
||||
isadmin = 1
|
||||
var/datum/DBQuery/query_get_new_polls = SSdbcore.NewQuery("SELECT id FROM [format_table_name("poll_question")] WHERE [(isadmin ? "" : "adminonly = false AND")] Now() BETWEEN starttime AND endtime AND id NOT IN (SELECT pollid FROM [format_table_name("poll_vote")] WHERE ckey = \"[sanitizeSQL(ckey)]\") AND id NOT IN (SELECT pollid FROM [format_table_name("poll_textreply")] WHERE ckey = \"[sanitizeSQL(ckey)]\")")
|
||||
var/rs = REF(src)
|
||||
if(query_get_new_polls.Execute())
|
||||
var/newpoll = 0
|
||||
if(query_get_new_polls.NextRow())
|
||||
newpoll = 1
|
||||
|
||||
if(newpoll)
|
||||
output += "<p><b><a href='byond://?src=[rs];showpoll=1'>Show Player Polls</A> (NEW!)</b></p>"
|
||||
else
|
||||
output += "<p><a href='byond://?src=[rs];showpoll=1'>Show Player Polls</A></p>"
|
||||
qdel(query_get_new_polls)
|
||||
if(QDELETED(src))
|
||||
return
|
||||
output += playerpolls()
|
||||
|
||||
output += "</center>"
|
||||
|
||||
@@ -81,6 +64,41 @@
|
||||
popup.set_content(output)
|
||||
popup.open(FALSE)
|
||||
|
||||
/mob/dead/new_player/proc/playerpolls()
|
||||
var/output = "" //hey tg why is this a list?
|
||||
if (SSdbcore.Connect())
|
||||
var/isadmin = FALSE
|
||||
if(client?.holder)
|
||||
isadmin = TRUE
|
||||
var/datum/db_query/query_get_new_polls = SSdbcore.NewQuery({"
|
||||
SELECT id FROM [format_table_name("poll_question")]
|
||||
WHERE (adminonly = 0 OR :isadmin = 1)
|
||||
AND Now() BETWEEN starttime AND endtime
|
||||
AND deleted = 0
|
||||
AND id NOT IN (
|
||||
SELECT pollid FROM [format_table_name("poll_vote")]
|
||||
WHERE ckey = :ckey
|
||||
AND deleted = 0
|
||||
)
|
||||
AND id NOT IN (
|
||||
SELECT pollid FROM [format_table_name("poll_textreply")]
|
||||
WHERE ckey = :ckey
|
||||
AND deleted = 0
|
||||
)
|
||||
"}, list("isadmin" = isadmin, "ckey" = ckey))
|
||||
var/rs = REF(src)
|
||||
if(!query_get_new_polls.Execute())
|
||||
qdel(query_get_new_polls)
|
||||
return
|
||||
if(query_get_new_polls.NextRow())
|
||||
output += "<p><b><a href='byond://?src=[rs];showpoll=1'>Show Player Polls</A> (NEW!)</b></p>"
|
||||
else
|
||||
output += "<p><a href='byond://?src=[rs];showpoll=1'>Show Player Polls</A></p>"
|
||||
qdel(query_get_new_polls)
|
||||
if(QDELETED(src))
|
||||
return
|
||||
return output
|
||||
|
||||
/mob/dead/new_player/proc/age_gate()
|
||||
var/list/dat = list("<center>")
|
||||
dat += "Enter your date of birth here, to confirm that you are over 18.<BR>"
|
||||
@@ -123,71 +141,76 @@
|
||||
if(!client.set_db_player_flags())
|
||||
message_admins("Blocked [src] from new player panel because age gate could not access player database flags.")
|
||||
return FALSE
|
||||
else
|
||||
var/dbflags = client.prefs.db_flags
|
||||
if(dbflags & DB_FLAG_AGE_CONFIRMATION_INCOMPLETE) //they have not completed age gate
|
||||
var/age_verification = age_gate()
|
||||
if(age_verification != 1)
|
||||
client.add_system_note("Automated-Age-Gate", "Failed automatic age gate process.")
|
||||
//ban them and kick them
|
||||
|
||||
//parameters used by sql line, easier to read:
|
||||
var/bantype_str = "ADMIN_PERMABAN"
|
||||
var/reason = "SYSTEM BAN - Inputted date during join verification was under 18 years of age. Contact administration on discord for verification."
|
||||
var/duration = -1
|
||||
var/sql_ckey = sanitizeSQL(client.ckey)
|
||||
var/computerid = client.computer_id
|
||||
if(!computerid)
|
||||
computerid = "0"
|
||||
var/sql_computerid = sanitizeSQL(computerid)
|
||||
var/ip = client.address
|
||||
if(!ip)
|
||||
ip = "0.0.0.0"
|
||||
var/sql_ip = sanitizeSQL(ip)
|
||||
if(!(client.prefs.db_flags & DB_FLAG_AGE_CONFIRMATION_INCOMPLETE)) //completed? Skip
|
||||
return TRUE
|
||||
|
||||
//parameter not used as there's no job but i want to fill out all parameters for the insert line
|
||||
var/sql_job
|
||||
var/age_verification = age_gate()
|
||||
//ban them and kick them
|
||||
if(age_verification != 1)
|
||||
// this isn't code, this is paragraphs.
|
||||
var/player_ckey = ckey(client.ckey)
|
||||
// record all admins and non-admins online at the time
|
||||
var/list/clients_online = GLOB.clients.Copy()
|
||||
var/list/admins_online = GLOB.admins.Copy() //list() // remove the GLOB.admins.Copy() and the comments if you want the pure admins_online check
|
||||
// for(var/client/C in clients_online)
|
||||
// if(C.holder) //deadmins aren't included since they wouldn't show up on adminwho
|
||||
// admins_online += C
|
||||
var/who = clients_online.Join(", ")
|
||||
var/adminwho = admins_online.Join(", ")
|
||||
|
||||
// these are typically the banning admin's, but it's the system so we leave them null, but they're still here for the sake of a full set of values
|
||||
var/sql_a_ckey
|
||||
var/sql_a_computerid
|
||||
var/sql_a_ip
|
||||
var/datum/db_query/query_add_ban = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("ban")]
|
||||
(bantime, server_ip, server_port , round_id, bantype, reason, job, duration, expiration_time, ckey, computerid, ip, a_ckey, a_computerid, a_ip, who, adminwho)
|
||||
VALUES (Now(), INET_ATON(:server_ip), :server_port, :round_id, :bantype_str, :reason, :role, :duration, Now() + INTERVAL :duration MINUTE, :ckey, :computerid, INET_ATON(:ip), :a_ckey, :a_computerid, INET_ATON(:a_ip), :who, :adminwho)"},
|
||||
list(
|
||||
// Server info
|
||||
"server_ip" = world.internet_address || 0,
|
||||
"server_port" = world.port,
|
||||
"round_id" = GLOB.round_id,
|
||||
// Client ban info
|
||||
"bantype_str" = "ADMIN_PERMABAN",
|
||||
"reason" = "SYSTEM BAN - Inputted date during join verification was under 18 years of age. Contact administration on discord for verification.",
|
||||
"role" = null,
|
||||
"duration" = -1,
|
||||
"ckey" = player_ckey,
|
||||
"ip" = client.address || null,
|
||||
"computerid" = client.computer_id || null,
|
||||
// Admin banning info
|
||||
"a_ckey" = "SYSTEM (Automated-Age-Gate)", // the server
|
||||
"a_ip" = null, //key_name
|
||||
"a_computerid" = "0",
|
||||
"who" = who,
|
||||
"adminwho" = adminwho
|
||||
))
|
||||
|
||||
// record all admins and non-admins online at the time
|
||||
var/who
|
||||
for(var/client/C in GLOB.clients)
|
||||
if(!who)
|
||||
who = "[C]"
|
||||
else
|
||||
who += ", [C]"
|
||||
client.add_system_note("Automated-Age-Gate", "Failed automatic age gate process.")
|
||||
if(!query_add_ban.Execute())
|
||||
// this is the part where you should panic.
|
||||
qdel(query_add_ban)
|
||||
message_admins("WARNING! Failed to ban [ckey] for failing the automatic age gate.")
|
||||
send2tgs_adminless_only("WARNING! Failed to ban [ckey] for failing the automatic age gate.")
|
||||
qdel(client)
|
||||
return FALSE
|
||||
qdel(query_add_ban)
|
||||
|
||||
var/adminwho
|
||||
for(var/client/C in GLOB.admins)
|
||||
if(!adminwho)
|
||||
adminwho = "[C]"
|
||||
else
|
||||
adminwho += ", [C]"
|
||||
create_message("note", player_ckey, "SYSTEM (Automated-Age-Gate)", "SYSTEM BAN - Inputted date during join verification was under 18 years of age. Contact administration on discord for verification.", null, null, 0, 0, null, 0, "high")
|
||||
|
||||
var/sql = "INSERT INTO [format_table_name("ban")] (`bantime`,`server_ip`,`server_port`,`round_id`,`bantype`,`reason`,`job`,`duration`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`) VALUES (Now(), INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', '[GLOB.round_id]', '[bantype_str]', '[reason]', '[sql_job]', [(duration)?"[duration]":"0"], Now() + INTERVAL [(duration>0) ? duration : 0] MINUTE, '[sql_ckey]', '[sql_computerid]', INET_ATON('[sql_ip]'), '[sql_a_ckey]', '[sql_a_computerid]', INET_ATON('[sql_a_ip]'), '[who]', '[adminwho]')"
|
||||
var/datum/DBQuery/query_add_ban = SSdbcore.NewQuery(sql)
|
||||
qdel(query_add_ban)
|
||||
// announce this
|
||||
message_admins("[ckey] has been banned for failing the automatic age gate.")
|
||||
send2tgs_adminless_only("[ckey] has been banned for failing the automatic age gate.")
|
||||
|
||||
// announce this
|
||||
message_admins("[html_encode(client.ckey)] has been banned for failing the automatic age gate.")
|
||||
send2irc("[html_encode(client.ckey)] has been banned for failing the automatic age gate.")
|
||||
// removing the client disconnects them
|
||||
qdel(client)
|
||||
|
||||
// removing the client disconnects them
|
||||
qdel(client)
|
||||
return FALSE
|
||||
|
||||
//they claim to be of age, so allow them to continue and update their flags
|
||||
client.update_flag_db(DB_FLAG_AGE_CONFIRMATION_COMPLETE, TRUE)
|
||||
client.update_flag_db(DB_FLAG_AGE_CONFIRMATION_INCOMPLETE, FALSE)
|
||||
//log this
|
||||
message_admins("[ckey] has joined through the automated age gate process.")
|
||||
|
||||
return FALSE
|
||||
else
|
||||
//they claim to be of age, so allow them to continue and update their flags
|
||||
client.update_flag_db(DB_FLAG_AGE_CONFIRMATION_COMPLETE, TRUE)
|
||||
client.update_flag_db(DB_FLAG_AGE_CONFIRMATION_INCOMPLETE, FALSE)
|
||||
//log this
|
||||
message_admins("[ckey] has joined through the automated age gate process.")
|
||||
return TRUE
|
||||
return TRUE
|
||||
|
||||
/mob/dead/new_player/Topic(href, href_list[])
|
||||
|
||||
@@ -4,9 +4,13 @@
|
||||
|
||||
/mob/dead/new_player/proc/handle_player_polling()
|
||||
if(!SSdbcore.IsConnected())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>", confidential = TRUE)
|
||||
return
|
||||
var/datum/DBQuery/query_poll_get = SSdbcore.NewQuery("SELECT id, question FROM [format_table_name("poll_question")] WHERE Now() BETWEEN starttime AND endtime [(client.holder ? "" : "AND adminonly = false")]")
|
||||
var/datum/db_query/query_poll_get = SSdbcore.NewQuery({"
|
||||
SELECT id, question
|
||||
FROM [format_table_name("poll_question")]
|
||||
WHERE Now() BETWEEN starttime AND endtime [(client.holder ? "" : "AND adminonly = false")]
|
||||
"})
|
||||
if(!query_poll_get.warn_execute())
|
||||
qdel(query_poll_get)
|
||||
return
|
||||
@@ -27,9 +31,15 @@
|
||||
if(!pollid)
|
||||
return
|
||||
if (!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>", confidential = TRUE)
|
||||
return
|
||||
var/datum/DBQuery/query_poll_get_details = SSdbcore.NewQuery("SELECT starttime, endtime, question, polltype, multiplechoiceoptions FROM [format_table_name("poll_question")] WHERE id = [pollid]")
|
||||
var/datum/db_query/query_poll_get_details = SSdbcore.NewQuery({"
|
||||
SELECT starttime, endtime, question, polltype, multiplechoiceoptions
|
||||
FROM [format_table_name("poll_question")]
|
||||
WHERE id = :id
|
||||
"}, list(
|
||||
"id" = pollid
|
||||
))
|
||||
if(!query_poll_get_details.warn_execute())
|
||||
qdel(query_poll_get_details)
|
||||
return
|
||||
@@ -47,7 +57,14 @@
|
||||
qdel(query_poll_get_details)
|
||||
switch(polltype)
|
||||
if(POLLTYPE_OPTION)
|
||||
var/datum/DBQuery/query_option_get_votes = SSdbcore.NewQuery("SELECT optionid FROM [format_table_name("poll_vote")] WHERE pollid = [pollid] AND ckey = '[ckey]'")
|
||||
var/datum/db_query/query_option_get_votes = SSdbcore.NewQuery({"
|
||||
SELECT optionid
|
||||
FROM [format_table_name("poll_vote")]
|
||||
WHERE pollid = :id AND ckey = :ckey
|
||||
"}, list(
|
||||
"id" = pollid,
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query_option_get_votes.warn_execute())
|
||||
qdel(query_option_get_votes)
|
||||
return
|
||||
@@ -56,7 +73,13 @@
|
||||
votedoptionid = text2num(query_option_get_votes.item[1])
|
||||
qdel(query_option_get_votes)
|
||||
var/list/datum/polloption/options = list()
|
||||
var/datum/DBQuery/query_option_options = SSdbcore.NewQuery("SELECT id, text FROM [format_table_name("poll_option")] WHERE pollid = [pollid]")
|
||||
var/datum/db_query/query_option_options = SSdbcore.NewQuery({"
|
||||
SELECT id, text
|
||||
FROM [format_table_name("poll_option")]
|
||||
WHERE pollid = :id
|
||||
"}, list(
|
||||
"id" = pollid
|
||||
))
|
||||
if(!query_option_options.warn_execute())
|
||||
qdel(query_option_options)
|
||||
return
|
||||
@@ -92,7 +115,14 @@
|
||||
src << browse(null ,"window=playerpolllist")
|
||||
src << browse(output,"window=playerpoll;size=500x250")
|
||||
if(POLLTYPE_TEXT)
|
||||
var/datum/DBQuery/query_text_get_votes = SSdbcore.NewQuery("SELECT replytext FROM [format_table_name("poll_textreply")] WHERE pollid = [pollid] AND ckey = '[ckey]'")
|
||||
var/datum/db_query/query_text_get_votes = SSdbcore.NewQuery({"
|
||||
SELECT replytext
|
||||
FROM [format_table_name("poll_textreply")]
|
||||
WHERE pollid = :id AND ckey = :ckey
|
||||
"}, list(
|
||||
"id" = pollid,
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query_text_get_votes.warn_execute())
|
||||
qdel(query_text_get_votes)
|
||||
return
|
||||
@@ -120,7 +150,13 @@
|
||||
src << browse(null ,"window=playerpolllist")
|
||||
src << browse(output,"window=playerpoll;size=500x500")
|
||||
if(POLLTYPE_RATING)
|
||||
var/datum/DBQuery/query_rating_get_votes = SSdbcore.NewQuery("SELECT o.text, v.rating FROM [format_table_name("poll_option")] o, [format_table_name("poll_vote")] v WHERE o.pollid = [pollid] AND v.ckey = '[ckey]' AND o.id = v.optionid")
|
||||
var/datum/db_query/query_rating_get_votes = SSdbcore.NewQuery({"
|
||||
SELECT o.text, v.rating FROM [format_table_name("poll_option")] o, [format_table_name("poll_vote")] v
|
||||
WHERE o.pollid = :id AND v.ckey = :ckey AND o.id = v.optionid
|
||||
"}, list(
|
||||
"id" = pollid,
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query_rating_get_votes.warn_execute())
|
||||
qdel(query_rating_get_votes)
|
||||
return
|
||||
@@ -140,7 +176,13 @@
|
||||
output += "<input type='hidden' name='votetype' value=[POLLTYPE_RATING]>"
|
||||
var/minid = 999999
|
||||
var/maxid = 0
|
||||
var/datum/DBQuery/query_rating_options = SSdbcore.NewQuery("SELECT id, text, minval, maxval, descmin, descmid, descmax FROM [format_table_name("poll_option")] WHERE pollid = [pollid]")
|
||||
var/datum/db_query/query_rating_options = SSdbcore.NewQuery({"
|
||||
SELECT id, text, minval, maxval, descmin, descmid, descmax
|
||||
FROM [format_table_name("poll_option")]
|
||||
WHERE pollid = :id
|
||||
"}, list(
|
||||
"id" = pollid
|
||||
))
|
||||
if(!query_rating_options.warn_execute())
|
||||
qdel(query_rating_options)
|
||||
return
|
||||
@@ -177,7 +219,14 @@
|
||||
src << browse(null ,"window=playerpolllist")
|
||||
src << browse(output,"window=playerpoll;size=500x500")
|
||||
if(POLLTYPE_MULTI)
|
||||
var/datum/DBQuery/query_multi_get_votes = SSdbcore.NewQuery("SELECT optionid FROM [format_table_name("poll_vote")] WHERE pollid = [pollid] AND ckey = '[ckey]'")
|
||||
var/datum/db_query/query_multi_get_votes = SSdbcore.NewQuery({"
|
||||
SELECT optionid
|
||||
FROM [format_table_name("poll_vote")]
|
||||
WHERE pollid = :id AND ckey = :ckey
|
||||
"}, list(
|
||||
"id" = pollid,
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query_multi_get_votes.warn_execute())
|
||||
qdel(query_multi_get_votes)
|
||||
return
|
||||
@@ -188,7 +237,13 @@
|
||||
var/list/datum/polloption/options = list()
|
||||
var/maxoptionid = 0
|
||||
var/minoptionid = 0
|
||||
var/datum/DBQuery/query_multi_options = SSdbcore.NewQuery("SELECT id, text FROM [format_table_name("poll_option")] WHERE pollid = [pollid]")
|
||||
var/datum/db_query/query_multi_options = SSdbcore.NewQuery({"
|
||||
SELECT id, text
|
||||
FROM [format_table_name("poll_option")]
|
||||
WHERE pollid = :id
|
||||
"}, list(
|
||||
"id" = pollid
|
||||
))
|
||||
if(!query_multi_options.warn_execute())
|
||||
qdel(query_multi_options)
|
||||
return
|
||||
@@ -231,8 +286,10 @@
|
||||
if(POLLTYPE_IRV)
|
||||
var/datum/asset/irv_assets = get_asset_datum(/datum/asset/group/irv)
|
||||
irv_assets.send(src)
|
||||
|
||||
var/datum/DBQuery/query_irv_get_votes = SSdbcore.NewQuery("SELECT optionid FROM [format_table_name("poll_vote")] WHERE pollid = [pollid] AND ckey = '[ckey]'")
|
||||
var/datum/db_query/query_irv_get_votes = SSdbcore.NewQuery({"
|
||||
SELECT optionid FROM [format_table_name("poll_vote")]
|
||||
WHERE pollid = :pollid AND ckey = :ckey AND deleted = 0
|
||||
"}, list("pollid" = pollid, "ckey" = ckey))
|
||||
if(!query_irv_get_votes.warn_execute())
|
||||
qdel(query_irv_get_votes)
|
||||
return
|
||||
@@ -244,7 +301,13 @@
|
||||
|
||||
var/list/datum/polloption/options = list()
|
||||
|
||||
var/datum/DBQuery/query_irv_options = SSdbcore.NewQuery("SELECT id, text FROM [format_table_name("poll_option")] WHERE pollid = [pollid]")
|
||||
var/datum/db_query/query_irv_options = SSdbcore.NewQuery({"
|
||||
SELECT id, text
|
||||
FROM [format_table_name("poll_option")]
|
||||
WHERE pollid = :id
|
||||
"}, list(
|
||||
"id" = pollid
|
||||
))
|
||||
if(!query_irv_options.warn_execute())
|
||||
qdel(query_irv_options)
|
||||
return
|
||||
@@ -352,16 +415,23 @@
|
||||
if (text)
|
||||
table = "poll_textreply"
|
||||
if (!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>", confidential = TRUE)
|
||||
return
|
||||
var/datum/DBQuery/query_hasvoted = SSdbcore.NewQuery("SELECT id FROM `[format_table_name(table)]` WHERE pollid = [pollid] AND ckey = '[ckey]'")
|
||||
var/datum/db_query/query_hasvoted = SSdbcore.NewQuery({"
|
||||
SELECT id
|
||||
FROM `[format_table_name(table)]`
|
||||
WHERE pollid = :id AND ckey = :ckey
|
||||
"}, list(
|
||||
"id" = pollid,
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query_hasvoted.warn_execute())
|
||||
qdel(query_hasvoted)
|
||||
return
|
||||
if(query_hasvoted.NextRow())
|
||||
qdel(query_hasvoted)
|
||||
if(!silent)
|
||||
to_chat(usr, "<span class='danger'>You've already replied to this poll.</span>")
|
||||
to_chat(usr, "<span class='danger'>You've already replied to this poll.</span>", confidential = TRUE)
|
||||
return TRUE
|
||||
qdel(query_hasvoted)
|
||||
return FALSE
|
||||
@@ -376,24 +446,31 @@
|
||||
/mob/dead/new_player/proc/vote_rig_check()
|
||||
if (usr != src)
|
||||
if (!usr || !src)
|
||||
return 0
|
||||
return FALSE
|
||||
//we gots ourselfs a dirty cheater on our hands!
|
||||
log_game("[key_name(usr)] attempted to rig the vote by voting as [key]")
|
||||
message_admins("[key_name_admin(usr)] attempted to rig the vote by voting as [key]")
|
||||
to_chat(usr, "<span class='danger'>You don't seem to be [key].</span>")
|
||||
to_chat(src, "<span class='danger'>Something went horribly wrong processing your vote. Please contact an administrator, they should have gotten a message about this</span>")
|
||||
return 0
|
||||
return 1
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/mob/dead/new_player/proc/vote_valid_check(pollid, holder, type)
|
||||
if (!SSdbcore.Connect())
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(src, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return 0
|
||||
return
|
||||
pollid = text2num(pollid)
|
||||
if (!pollid || pollid < 0)
|
||||
return 0
|
||||
//validate the poll is actually the right type of poll and its still active
|
||||
var/datum/DBQuery/query_validate_poll = SSdbcore.NewQuery("SELECT id FROM [format_table_name("poll_question")] WHERE id = [pollid] AND Now() BETWEEN starttime AND endtime AND polltype = '[type]' [(holder ? "" : "AND adminonly = false")]")
|
||||
var/datum/db_query/query_validate_poll = SSdbcore.NewQuery({"
|
||||
SELECT id
|
||||
FROM [format_table_name("poll_question")]
|
||||
WHERE id = :id AND Now() BETWEEN starttime AND endtime AND polltype = :type [(holder ? "" : "AND adminonly = false")]
|
||||
"}, list(
|
||||
"id" = pollid,
|
||||
"type" = type
|
||||
))
|
||||
if(!query_validate_poll.warn_execute())
|
||||
qdel(query_validate_poll)
|
||||
return 0
|
||||
@@ -403,88 +480,66 @@
|
||||
qdel(query_validate_poll)
|
||||
return 1
|
||||
|
||||
/**
|
||||
* Processes vote form data and saves results to the database for an IRV type poll.
|
||||
*
|
||||
*/
|
||||
/mob/dead/new_player/proc/vote_on_irv_poll(pollid, list/votelist)
|
||||
if (!SSdbcore.Connect())
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(src, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return 0
|
||||
if (!vote_rig_check())
|
||||
return 0
|
||||
pollid = text2num(pollid)
|
||||
if (!pollid || pollid < 0)
|
||||
return 0
|
||||
if (!votelist || !istype(votelist) || !votelist.len)
|
||||
return 0
|
||||
if (!client)
|
||||
return 0
|
||||
//save these now so we can still process the vote if the client goes away while we process.
|
||||
var/datum/admins/holder = client.holder
|
||||
var/rank = "Player"
|
||||
if (holder)
|
||||
rank = holder.rank.name
|
||||
var/ckey = client.ckey
|
||||
var/address = client.address
|
||||
|
||||
//validate the poll
|
||||
if (!vote_valid_check(pollid, holder, POLLTYPE_IRV))
|
||||
return
|
||||
if(IsAdminAdvancedProcCall())
|
||||
return
|
||||
if(!vote_rig_check())
|
||||
return
|
||||
if(!pollid)
|
||||
return
|
||||
// var/list/votelist = splittext(href_list["IRVdata"], ",")
|
||||
if(!length(votelist))
|
||||
to_chat(src, "<span class='danger'>No ordering data found. Please try again or contact an administrator.</span>")
|
||||
var/admin_rank = "Player"
|
||||
if(!QDELETED(client) && client.holder)
|
||||
admin_rank = client.holder.rank.name
|
||||
if (!vote_valid_check(pollid, client?.holder, POLLTYPE_IRV))
|
||||
return 0
|
||||
|
||||
//lets collect the options
|
||||
var/datum/DBQuery/query_irv_id = SSdbcore.NewQuery("SELECT id FROM [format_table_name("poll_option")] WHERE pollid = [pollid]")
|
||||
if(!query_irv_id.warn_execute())
|
||||
qdel(query_irv_id)
|
||||
return 0
|
||||
var/list/optionlist = list()
|
||||
while (query_irv_id.NextRow())
|
||||
optionlist += text2num(query_irv_id.item[1])
|
||||
qdel(query_irv_id)
|
||||
var/list/special_columns = list(
|
||||
"datetime" = "NOW()",
|
||||
"ip" = "INET_ATON(?)",
|
||||
)
|
||||
|
||||
//validate their votes are actually in the list of options and actually numbers
|
||||
var/list/numberedvotelist = list()
|
||||
for (var/vote in votelist)
|
||||
vote = text2num(vote)
|
||||
numberedvotelist += vote
|
||||
if (!vote) //this is fine because voteid starts at 1, so it will never be 0
|
||||
to_chat(src, "<span class='danger'>Error: Invalid (non-numeric) votes in the vote data.</span>")
|
||||
return 0
|
||||
if (!(vote in optionlist))
|
||||
to_chat(src, "<span class='danger'>Votes for choices that do not appear to be in the poll detected.</span>")
|
||||
return 0
|
||||
if (!numberedvotelist.len)
|
||||
to_chat(src, "<span class='danger'>Invalid vote data</span>")
|
||||
return 0
|
||||
|
||||
//lets add the vote, first we generate an insert statement.
|
||||
|
||||
var/sqlrowlist = ""
|
||||
for (var/vote in numberedvotelist)
|
||||
if (sqlrowlist != "")
|
||||
sqlrowlist += ", " //a comma (,) at the start of the first row to insert will trigger a SQL error
|
||||
sqlrowlist += "(Now(), [pollid], [vote], '[sanitizeSQL(ckey)]', INET_ATON('[sanitizeSQL(address)]'), '[sanitizeSQL(rank)]')"
|
||||
|
||||
//now lets delete their old votes (if any)
|
||||
var/datum/DBQuery/query_irv_del_old = SSdbcore.NewQuery("DELETE FROM [format_table_name("poll_vote")] WHERE pollid = [pollid] AND ckey = '[ckey]'")
|
||||
if(!query_irv_del_old.warn_execute())
|
||||
qdel(query_irv_del_old)
|
||||
return 0
|
||||
qdel(query_irv_del_old)
|
||||
|
||||
//now to add the new ones.
|
||||
var/datum/DBQuery/query_irv_vote = SSdbcore.NewQuery("INSERT INTO [format_table_name("poll_vote")] (datetime, pollid, optionid, ckey, ip, adminrank) VALUES [sqlrowlist]")
|
||||
if(!query_irv_vote.warn_execute())
|
||||
qdel(query_irv_vote)
|
||||
return 0
|
||||
qdel(query_irv_vote)
|
||||
if(!QDELETED(src))
|
||||
src << browse(null,"window=playerpoll")
|
||||
return 1
|
||||
var/sql_votes = list()
|
||||
for(var/o in votelist)
|
||||
var/voteid = text2num(o)
|
||||
if(!voteid)
|
||||
continue
|
||||
sql_votes += list(list(
|
||||
"pollid" = pollid,
|
||||
"optionid" = voteid,
|
||||
"ckey" = ckey,
|
||||
"ip" = client.address,
|
||||
"adminrank" = admin_rank
|
||||
))
|
||||
//IRV results are calculated based on id order, we delete all of a user's votes to avoid potential errors caused by revoting and option editing
|
||||
var/datum/db_query/query_delete_irv_votes = SSdbcore.NewQuery({"
|
||||
UPDATE [format_table_name("poll_vote")] SET deleted = 1 WHERE pollid = :pollid AND ckey = :ckey
|
||||
"}, list("pollid" = pollid, "ckey" = ckey))
|
||||
if(!query_delete_irv_votes.warn_execute())
|
||||
qdel(query_delete_irv_votes)
|
||||
return
|
||||
qdel(query_delete_irv_votes)
|
||||
SSdbcore.MassInsert(format_table_name("poll_vote"), sql_votes, special_columns = special_columns)
|
||||
return TRUE
|
||||
|
||||
|
||||
/mob/dead/new_player/proc/vote_on_poll(pollid, optionid)
|
||||
if (!SSdbcore.Connect())
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(src, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return 0
|
||||
if (!vote_rig_check())
|
||||
return 0
|
||||
return
|
||||
if(!vote_rig_check())
|
||||
return
|
||||
if(IsAdminAdvancedProcCall())
|
||||
return
|
||||
if(!pollid || !optionid)
|
||||
return
|
||||
//validate the poll
|
||||
@@ -493,10 +548,19 @@
|
||||
var/voted = poll_check_voted(pollid)
|
||||
if(isnull(voted) || voted) //Failed or already voted.
|
||||
return
|
||||
var/adminrank = sanitizeSQL(poll_rank())
|
||||
var/adminrank = poll_rank()
|
||||
if(!adminrank)
|
||||
return
|
||||
var/datum/DBQuery/query_option_vote = SSdbcore.NewQuery("INSERT INTO [format_table_name("poll_vote")] (datetime, pollid, optionid, ckey, ip, adminrank) VALUES (Now(), [pollid], [optionid], '[ckey]', INET_ATON('[client.address]'), '[adminrank]')")
|
||||
var/datum/db_query/query_option_vote = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("poll_vote")] (datetime, pollid, optionid, ckey, ip, adminrank)
|
||||
VALUES (Now(), :pollid, :optionid, :ckey, INET_ATON(:address), :adminrank)
|
||||
"}, list(
|
||||
"pollid" = pollid,
|
||||
"optionid" = optionid,
|
||||
"ckey" = ckey,
|
||||
"address" = client.address,
|
||||
"adminrank" = adminrank
|
||||
))
|
||||
if(!query_option_vote.warn_execute())
|
||||
qdel(query_option_vote)
|
||||
return
|
||||
@@ -506,11 +570,13 @@
|
||||
return 1
|
||||
|
||||
/mob/dead/new_player/proc/log_text_poll_reply(pollid, replytext)
|
||||
if (!SSdbcore.Connect())
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(src, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return 0
|
||||
if (!vote_rig_check())
|
||||
return 0
|
||||
return
|
||||
if(!vote_rig_check())
|
||||
return
|
||||
if(IsAdminAdvancedProcCall())
|
||||
return
|
||||
if(!pollid)
|
||||
return
|
||||
//validate the poll
|
||||
@@ -522,18 +588,23 @@
|
||||
var/voted = poll_check_voted(pollid, text = TRUE, silent = TRUE)
|
||||
if(isnull(voted))
|
||||
return
|
||||
var/adminrank = sanitizeSQL(poll_rank())
|
||||
var/adminrank = poll_rank()
|
||||
if(!adminrank)
|
||||
return
|
||||
replytext = sanitizeSQL(replytext)
|
||||
if(!(length(replytext) > 0) || !(length(replytext) <= 8000))
|
||||
to_chat(usr, "The text you entered was invalid or too long. Please correct the text and submit again.")
|
||||
return
|
||||
var/datum/DBQuery/query_text_vote
|
||||
var/datum/db_query/query_text_vote
|
||||
if(!voted)
|
||||
query_text_vote = SSdbcore.NewQuery("INSERT INTO [format_table_name("poll_textreply")] (datetime ,pollid ,ckey ,ip ,replytext ,adminrank) VALUES (Now(), [pollid], '[ckey]', INET_ATON('[client.address]'), '[replytext]', '[adminrank]')")
|
||||
query_text_vote = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("poll_textreply")] (datetime, pollid, ckey, ip, replytext, adminrank)
|
||||
VALUES (Now(), :pollid, :ckey, INET_ATON(:address), :replytext, :adminrank)
|
||||
"}, list("pollid" = pollid, "ckey" = ckey, "address" = client.address, "replytext" = replytext, "adminrank" = adminrank))
|
||||
else
|
||||
query_text_vote = SSdbcore.NewQuery("UPDATE [format_table_name("poll_textreply")] SET datetime = Now(), ip = INET_ATON('[client.address]'), replytext = '[replytext]' WHERE pollid = '[pollid]' AND ckey = '[ckey]'")
|
||||
query_text_vote = SSdbcore.NewQuery({"
|
||||
UPDATE [format_table_name("poll_textreply")]
|
||||
SET datetime = Now(), ip = INET_ATON(:address), replytext = :replytext WHERE pollid = :pollid AND ckey = :ckey
|
||||
"}, list("address" = client.address, "replytext" = replytext, "pollid" = pollid, "ckey" = ckey))
|
||||
if(!query_text_vote.warn_execute())
|
||||
qdel(query_text_vote)
|
||||
return
|
||||
@@ -543,17 +614,26 @@
|
||||
return 1
|
||||
|
||||
/mob/dead/new_player/proc/vote_on_numval_poll(pollid, optionid, rating)
|
||||
if (!SSdbcore.Connect())
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(src, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return 0
|
||||
if (!vote_rig_check())
|
||||
return 0
|
||||
return
|
||||
if(!vote_rig_check())
|
||||
return
|
||||
if(IsAdminAdvancedProcCall())
|
||||
return
|
||||
if(!pollid || !optionid || !rating)
|
||||
return
|
||||
//validate the poll
|
||||
if (!vote_valid_check(pollid, client.holder, POLLTYPE_RATING))
|
||||
return 0
|
||||
var/datum/DBQuery/query_numval_hasvoted = SSdbcore.NewQuery("SELECT id FROM [format_table_name("poll_vote")] WHERE optionid = [optionid] AND ckey = '[ckey]'")
|
||||
var/datum/db_query/query_numval_hasvoted = SSdbcore.NewQuery({"
|
||||
SELECT id
|
||||
FROM [format_table_name("poll_vote")]
|
||||
WHERE optionid = :id AND ckey = :ckey
|
||||
"}, list(
|
||||
"id" = optionid,
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query_numval_hasvoted.warn_execute())
|
||||
qdel(query_numval_hasvoted)
|
||||
return
|
||||
@@ -565,8 +645,10 @@
|
||||
var/adminrank = "Player"
|
||||
if(client.holder)
|
||||
adminrank = client.holder.rank.name
|
||||
adminrank = sanitizeSQL(adminrank)
|
||||
var/datum/DBQuery/query_numval_vote = SSdbcore.NewQuery("INSERT INTO [format_table_name("poll_vote")] (datetime ,pollid ,optionid ,ckey ,ip ,adminrank, rating) VALUES (Now(), [pollid], [optionid], '[ckey]', INET_ATON('[client.address]'), '[adminrank]', [(isnull(rating)) ? "null" : rating])")
|
||||
var/datum/db_query/query_numval_vote = SSdbcore.NewQuery({"
|
||||
INSERT INTO [format_table_name("poll_vote")] (datetime ,pollid ,optionid ,ckey ,ip ,adminrank, rating)
|
||||
VALUES (Now(), :pollid, :optionid, :ckey, INET_ATON(:address), :adminrank, :rating)
|
||||
"}, list("pollid" = pollid, "optionid" = optionid, "ckey" = ckey, "address" = client.address, "adminrank" = adminrank, "rating" = isnull(rating) ? "null" : rating))
|
||||
if(!query_numval_vote.warn_execute())
|
||||
qdel(query_numval_vote)
|
||||
return
|
||||
@@ -575,46 +657,59 @@
|
||||
usr << browse(null,"window=playerpoll")
|
||||
return 1
|
||||
|
||||
/**
|
||||
* Processes vote form data and saves results to the database for a multiple choice type poll.
|
||||
*
|
||||
*/
|
||||
/mob/dead/new_player/proc/vote_on_multi_poll(pollid, optionid)
|
||||
if (!SSdbcore.Connect())
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(src, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return 0
|
||||
if (!vote_rig_check())
|
||||
return 0
|
||||
if(!pollid || !optionid)
|
||||
return 1
|
||||
return
|
||||
if(!vote_rig_check())
|
||||
return
|
||||
if(IsAdminAdvancedProcCall())
|
||||
return
|
||||
//validate the poll
|
||||
if (!vote_valid_check(pollid, client.holder, POLLTYPE_MULTI))
|
||||
return 0
|
||||
var/datum/DBQuery/query_multi_choicelen = SSdbcore.NewQuery("SELECT multiplechoiceoptions FROM [format_table_name("poll_question")] WHERE id = [pollid]")
|
||||
if(!query_multi_choicelen.warn_execute())
|
||||
qdel(query_multi_choicelen)
|
||||
return 1
|
||||
var/i
|
||||
if(query_multi_choicelen.NextRow())
|
||||
i = text2num(query_multi_choicelen.item[1])
|
||||
qdel(query_multi_choicelen)
|
||||
var/datum/DBQuery/query_multi_hasvoted = SSdbcore.NewQuery("SELECT id FROM [format_table_name("poll_vote")] WHERE pollid = [pollid] AND ckey = '[ckey]'")
|
||||
if(!query_multi_hasvoted.warn_execute())
|
||||
qdel(query_multi_hasvoted)
|
||||
return 1
|
||||
while(i)
|
||||
if(query_multi_hasvoted.NextRow())
|
||||
i--
|
||||
else
|
||||
break
|
||||
qdel(query_multi_hasvoted)
|
||||
if(!i)
|
||||
return 2
|
||||
var/adminrank = "Player"
|
||||
if(!QDELETED(client) && client.holder)
|
||||
adminrank = client.holder.rank.name
|
||||
adminrank = sanitizeSQL(adminrank)
|
||||
var/datum/DBQuery/query_multi_vote = SSdbcore.NewQuery("INSERT INTO [format_table_name("poll_vote")] (datetime, pollid, optionid, ckey, ip, adminrank) VALUES (Now(), [pollid], [optionid], '[ckey]', INET_ATON('[client.address]'), '[adminrank]')")
|
||||
if(!query_multi_vote.warn_execute())
|
||||
qdel(query_multi_vote)
|
||||
return 1
|
||||
qdel(query_multi_vote)
|
||||
if(!QDELETED(usr))
|
||||
usr << browse(null,"window=playerpoll")
|
||||
return 0
|
||||
if(!vote_valid_check(pollid, client.holder, POLLTYPE_MULTI))
|
||||
return
|
||||
if(!pollid || !optionid)
|
||||
return
|
||||
// if(length(href_list) > 2)
|
||||
// href_list.Cut(1,3) //first two values aren't options
|
||||
// else
|
||||
// to_chat(src, "<span class='danger'>No options were selected.</span>")
|
||||
|
||||
var/special_columns = list(
|
||||
"datetime" = "NOW()",
|
||||
"ip" = "INET_ATON(?)",
|
||||
)
|
||||
|
||||
var/sql_votes = list()
|
||||
// var/vote_count = 0
|
||||
// for(var/h in href_list)
|
||||
// if(vote_count == poll.options_allowed)
|
||||
// to_chat(src, "<span class='danger'>Allowed option count exceeded, only the first [poll.options_allowed] selected options have been saved.</span>")
|
||||
// break
|
||||
// vote_count++
|
||||
// var/datum/poll_option/option = locate(h) in poll.options
|
||||
var/admin_rank = "Player"
|
||||
if(!QDELETED(client) && client?.holder)
|
||||
admin_rank = client.holder.rank.name
|
||||
sql_votes += list(list(
|
||||
"pollid" = pollid,
|
||||
"optionid" = optionid,
|
||||
"ckey" = ckey,
|
||||
"ip" = client.address,
|
||||
"adminrank" = admin_rank
|
||||
))
|
||||
/*with revoting and poll editing possible there can be an edge case where a poll is changed to allow less multiple choice options than a user has already voted on
|
||||
rather than trying to calculate which options should be updated and which deleted, we just delete all of a user's votes and re-insert as needed*/
|
||||
var/datum/db_query/query_delete_multi_votes = SSdbcore.NewQuery({"
|
||||
UPDATE [format_table_name("poll_vote")] SET deleted = 1 WHERE pollid = :pollid AND ckey = :ckey
|
||||
"}, list("pollid" = pollid, "ckey" = ckey))
|
||||
if(!query_delete_multi_votes.warn_execute())
|
||||
qdel(query_delete_multi_votes)
|
||||
return
|
||||
qdel(query_delete_multi_votes)
|
||||
SSdbcore.MassInsert(format_table_name("poll_vote"), sql_votes, special_columns = special_columns)
|
||||
return TRUE
|
||||
|
||||
@@ -143,10 +143,10 @@
|
||||
parry_efficiency_considered_successful = 0.01
|
||||
parry_efficiency_to_counterattack = 0.01
|
||||
parry_max_attacks = INFINITY
|
||||
parry_failed_cooldown_duration = 3 SECONDS
|
||||
parry_failed_stagger_duration = 2 SECONDS
|
||||
parry_cooldown = 3 SECONDS
|
||||
parry_failed_clickcd_duration = 0.8 SECONDS
|
||||
parry_failed_cooldown_duration = 1.5 SECONDS
|
||||
parry_failed_stagger_duration = 1 SECONDS
|
||||
parry_cooldown = 0
|
||||
parry_failed_clickcd_duration = 0.8
|
||||
|
||||
parry_data = list( // yeah it's snowflake
|
||||
"UNARMED_PARRY_STAGGER" = 3 SECONDS,
|
||||
|
||||
@@ -80,6 +80,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
var/list/inherent_traits = list()
|
||||
var/inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID
|
||||
|
||||
var/list/blacklisted_quirks = list() // Quirks that will be removed upon gaining this species, to be defined by species
|
||||
var/list/removed_quirks = list() // Quirks that got removed due to being blacklisted, and will be restored when on_species_loss() is called
|
||||
|
||||
var/attack_verb = "punch" // punch-specific attack verb
|
||||
var/sound/attack_sound = 'sound/weapons/punch1.ogg'
|
||||
var/sound/miss_sound = 'sound/weapons/punchmiss.ogg'
|
||||
@@ -342,6 +345,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
for(var/X in inherent_traits)
|
||||
ADD_TRAIT(C, X, SPECIES_TRAIT)
|
||||
|
||||
//lets remove those conflicting quirks
|
||||
remove_blacklisted_quirks(C)
|
||||
|
||||
if(TRAIT_VIRUSIMMUNE in inherent_traits)
|
||||
for(var/datum/disease/A in C.diseases)
|
||||
A.cure(FALSE)
|
||||
@@ -395,6 +401,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
for(var/X in inherent_traits)
|
||||
REMOVE_TRAIT(C, X, SPECIES_TRAIT)
|
||||
|
||||
// lets restore the quirks that got removed when gaining this species
|
||||
restore_quirks(C)
|
||||
|
||||
C.remove_movespeed_modifier(/datum/movespeed_modifier/species)
|
||||
|
||||
if(mutant_bodyparts["meat_type"])
|
||||
@@ -424,6 +433,26 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
|
||||
SEND_SIGNAL(C, COMSIG_SPECIES_LOSS, src)
|
||||
|
||||
// shamelessly inspired by antag_datum.remove_blacklisted_quirks()
|
||||
/datum/species/proc/remove_blacklisted_quirks(mob/living/carbon/C)
|
||||
var/mob/living/L = C.mind?.current
|
||||
if(istype(L))
|
||||
var/list/my_quirks = L.client?.prefs.all_quirks.Copy()
|
||||
SSquirks.filter_quirks(my_quirks, blacklisted_quirks)
|
||||
for(var/q in L.roundstart_quirks)
|
||||
var/datum/quirk/Q = q
|
||||
if(!(SSquirks.quirk_name_by_path(Q.type) in my_quirks))
|
||||
L.remove_quirk(Q.type)
|
||||
removed_quirks += Q.type
|
||||
|
||||
// restore any quirks that we removed
|
||||
/datum/species/proc/restore_quirks(mob/living/carbon/C)
|
||||
var/mob/living/L = C.mind?.current
|
||||
if(istype(L))
|
||||
for(var/q in removed_quirks)
|
||||
L.add_quirk(q)
|
||||
|
||||
|
||||
/datum/species/proc/handle_hair(mob/living/carbon/human/H, forced_colour)
|
||||
H.remove_overlay(HAIR_LAYER)
|
||||
var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD)
|
||||
@@ -1454,9 +1483,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
|
||||
|
||||
var/armor_block = target.run_armor_check(affecting, "melee")
|
||||
if(HAS_TRAIT(user, TRAIT_MAULER)) // maulers get 15 armorpierce because if you're going to punch someone you might as well do a good job of it
|
||||
armor_block = target.run_armor_check(affecting, "melee", armour_penetration = 15) // lot of good that sec jumpsuit did you
|
||||
|
||||
playsound(target.loc, user.dna.species.attack_sound, 25, 1, -1)
|
||||
target.visible_message("<span class='danger'>[user] [atk_verb]ed [target]!</span>", \
|
||||
"<span class='userdanger'>[user] [atk_verb]ed you!</span>", null, COMBAT_MESSAGE_RANGE, null, \
|
||||
@@ -1473,9 +1499,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
target.apply_damage(damage*1.5, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
|
||||
target.apply_damage(damage*0.5, STAMINA, affecting, armor_block)
|
||||
log_combat(user, target, "kicked")
|
||||
else if(HAS_TRAIT(user, TRAIT_MAULER)) // mauler punches deal 1.1x raw damage + 1.3x stam damage, and have some armor pierce
|
||||
target.apply_damage(damage*1.1, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
|
||||
target.apply_damage(damage*1.3, STAMINA, affecting, armor_block)
|
||||
else if(HAS_TRAIT(user, TRAIT_MAULER)) // mauler punches deal 1.2x raw damage but nstam
|
||||
target.apply_damage(damage*1.2, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
|
||||
log_combat(user, target, "punched (mauler)")
|
||||
else //other attacks deal full raw damage + 2x in stamina damage
|
||||
target.apply_damage(damage, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
armor = 20 // 120 damage to KO a zombie, which kills it
|
||||
speedmod = 1.6 // they're very slow
|
||||
mutanteyes = /obj/item/organ/eyes/night_vision/zombie
|
||||
blacklisted_quirks = list(/datum/quirk/nonviolent)
|
||||
var/heal_rate = 1
|
||||
var/regen_cooldown = 0
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
break
|
||||
var/msg = "[key_name_admin(src)] [ADMIN_JMP(src)] was found to have no .loc with an attached client, if the cause is unknown it would be wise to ask how this was accomplished."
|
||||
message_admins(msg)
|
||||
send2irc_adminless_only("Mob", msg, R_ADMIN)
|
||||
send2tgs_adminless_only("Mob", msg, R_ADMIN)
|
||||
log_game("[key_name(src)] was found to have no .loc with an attached client.")
|
||||
|
||||
// This is a temporary error tracker to make sure we've caught everything
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
if(!(combat_flags & COMBAT_FLAG_PARRY_CAPABLE))
|
||||
to_chat(src, "<span class='warning'>You are not something that can parry attacks.</span>")
|
||||
return
|
||||
if(!(mobility_flags & MOBILITY_STAND))
|
||||
to_chat(src, "<span class='warning'>You aren't able to parry without solid footing!</span>")
|
||||
return
|
||||
// Prioritize item, then martial art, then unarmed.
|
||||
// yanderedev else if time
|
||||
var/obj/item/using_item = get_active_held_item()
|
||||
|
||||
@@ -78,6 +78,15 @@
|
||||
projectiletype = /obj/item/projectile/neurotox
|
||||
projectilesound = 'sound/weapons/pierce.ogg'
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/sentinel/cube
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
health = 220
|
||||
maxHealth = 220
|
||||
melee_damage_lower = 20
|
||||
melee_damage_upper = 20
|
||||
del_on_death = TRUE
|
||||
loot = list(/obj/effect/mob_spawn/alien/corpse/humanoid/sentinel)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/queen
|
||||
name = "alien queen"
|
||||
|
||||
@@ -425,7 +425,7 @@ Difficulty: Very Hard
|
||||
|
||||
/obj/machinery/anomalous_crystal/honk //Strips and equips you as a clown. I apologize for nothing
|
||||
observer_desc = "This crystal strips and equips its targets as clowns."
|
||||
possible_methods = list(ACTIVATE_MOB_BUMP, ACTIVATE_SPEECH)
|
||||
possible_methods = list(ACTIVATE_TOUCH) //Because We love AOE transformations!
|
||||
activation_sound = 'sound/items/bikehorn.ogg'
|
||||
|
||||
/obj/machinery/anomalous_crystal/honk/ActivationReaction(mob/user)
|
||||
|
||||
@@ -399,6 +399,14 @@ Difficulty: Medium
|
||||
crusher_loot = list()
|
||||
butcher_results = list(/obj/item/stack/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/bone = 30)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/lesser/transformed //ash drake balanced around player control
|
||||
name = "transformed ash drake"
|
||||
desc = "A sentient being transformed into an ash drake"
|
||||
mob_size = MOB_SIZE_HUMAN //prevents crusher vulnerability
|
||||
move_force = MOVE_FORCE_NORMAL //stops them from destroying and unanchoring shit by walking into it
|
||||
environment_smash = ENVIRONMENT_SMASH_STRUCTURES //no we dont want sentient megafauna be able to delete the entire station in a minute flat
|
||||
damage_coeff = list(BRUTE = 0.7, BURN = 0.5, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) //200 health but not locked to standard movespeed, needs armor befitting of a dragon
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/lesser/grant_achievement(medaltype,scoretype)
|
||||
return
|
||||
|
||||
@@ -414,7 +422,8 @@ Difficulty: Medium
|
||||
if(L in hit_list || L == source)
|
||||
continue
|
||||
hit_list += L
|
||||
L.adjustFireLoss(20)
|
||||
L.adjustFireLoss(5)
|
||||
L.adjust_fire_stacks(6)
|
||||
to_chat(L, "<span class='userdanger'>You're hit by [source]'s fire breath!</span>")
|
||||
|
||||
// deals damage to mechs
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
A.GiveTarget(target)
|
||||
A.friends = friends
|
||||
A.faction = faction.Copy()
|
||||
if(!A == /mob/living/simple_animal/hostile/poison/bees/toxin)
|
||||
A.my_creator = type
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelord/AttackingTarget()
|
||||
@@ -88,6 +90,7 @@
|
||||
density = FALSE
|
||||
del_on_death = 1
|
||||
var/swarming = FALSE
|
||||
var/my_creator = null
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/Initialize()
|
||||
. = ..()
|
||||
@@ -205,11 +208,7 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/proc/infest(mob/living/carbon/human/H)
|
||||
visible_message("<span class='warning'>[name] burrows into the flesh of [H]!</span>")
|
||||
var/mob/living/simple_animal/hostile/asteroid/hivelord/legion/L
|
||||
if(HAS_TRAIT(H, TRAIT_DWARF)) //dwarf legions aren't just fluff!
|
||||
L = new /mob/living/simple_animal/hostile/asteroid/hivelord/legion/dwarf(H.loc)
|
||||
else
|
||||
L = new(H.loc)
|
||||
var/mob/living/simple_animal/hostile/asteroid/hivelord/legion/L = check_infest_type(H)
|
||||
visible_message("<span class='warning'>[L] staggers to [L.p_their()] feet!</span>")
|
||||
H.death()
|
||||
H.adjustBruteLoss(1000)
|
||||
@@ -217,6 +216,20 @@
|
||||
H.forceMove(L)
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/proc/check_infest_type(mob/living/carbon/human/human)
|
||||
var/mob/living/simple_animal/hostile/asteroid/hivelord/legion/L
|
||||
var/list/blacklisted_types = list(/mob/living/simple_animal/hostile/asteroid/hivelord/legion/dwarf)
|
||||
if(HAS_TRAIT(human, TRAIT_DWARF)) //dwarf legions aren't just fluff!
|
||||
L = new /mob/living/simple_animal/hostile/asteroid/hivelord/legion/dwarf(human.loc)
|
||||
else if(my_creator)
|
||||
if(my_creator in blacklisted_types)
|
||||
L = new(human.loc)
|
||||
else
|
||||
L = new my_creator(human.loc)
|
||||
else
|
||||
L = new(human.loc)
|
||||
return L
|
||||
|
||||
//Advanced Legion is slightly tougher to kill and can raise corpses (revive other legions)
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelord/legion/advanced
|
||||
stat_attack = DEAD
|
||||
|
||||
@@ -178,10 +178,7 @@
|
||||
|
||||
new /obj/effect/temp_visual/monkeyify/humanify(loc)
|
||||
|
||||
transformation_timer = addtimer(CALLBACK(src, .proc/finish_humanize, tr_flags), TRANSFORMATION_DURATION, TIMER_UNIQUE)
|
||||
|
||||
/mob/living/carbon/proc/finish_humanize(tr_flags)
|
||||
transformation_timer = null
|
||||
sleep(TRANSFORMATION_DURATION) //This entire proc CANNOT be split into two
|
||||
|
||||
var/list/stored_implants = list()
|
||||
var/list/int_organs = list()
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
var/light_on = FALSE
|
||||
integrity_failure = 0.5
|
||||
max_integrity = 100
|
||||
rad_flags = RAD_PROTECT_CONTENTS
|
||||
armor = list("melee" = 0, "bullet" = 20, "laser" = 20, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 0, "acid" = 0)
|
||||
|
||||
var/enabled = 0 // Whether the computer is turned on.
|
||||
|
||||
@@ -182,6 +182,7 @@
|
||||
|
||||
/obj/item/gun/energy/kinetic_accelerator/proc/reload()
|
||||
cell.give(cell.maxcharge)
|
||||
process_chamber()
|
||||
if(!suppressed)
|
||||
playsound(src.loc, 'sound/weapons/kenetic_reload.ogg', 60, 1)
|
||||
else
|
||||
|
||||
@@ -45,6 +45,13 @@
|
||||
trippy = FALSE
|
||||
pH = 8
|
||||
|
||||
//Nicotine is used as a pesticide IRL.
|
||||
/datum/reagent/drug/nicotine/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray, mob/user)
|
||||
. = ..()
|
||||
if(chems.has_reagent(type, 1))
|
||||
mytray.adjustToxic(round(chems.get_reagent_amount(type)))
|
||||
mytray.adjustPests(-rand(1,2))
|
||||
|
||||
/datum/reagent/drug/nicotine/on_mob_life(mob/living/carbon/M)
|
||||
if(prob(1))
|
||||
var/smoke_message = pick("You feel relaxed.", "You feel calmed.","You feel alert.","You feel rugged.")
|
||||
|
||||
@@ -49,6 +49,11 @@
|
||||
var/brute_heal = 1
|
||||
var/burn_heal = 0
|
||||
|
||||
/datum/reagent/consumable/nutriment/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray, mob/user)
|
||||
. = ..()
|
||||
if(chems.has_reagent(type, 1))
|
||||
mytray.adjustHealth(round(chems.get_reagent_amount(type) * 0.2))
|
||||
|
||||
/datum/reagent/consumable/nutriment/on_mob_life(mob/living/carbon/M)
|
||||
if(!HAS_TRAIT(M, TRAIT_NO_PROCESS_FOOD))
|
||||
if(prob(50))
|
||||
|
||||
@@ -155,6 +155,12 @@
|
||||
pH = 11
|
||||
value = REAGENT_VALUE_COMMON
|
||||
|
||||
// Healing
|
||||
/datum/reagent/medicine/cryoxadone/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray, mob/user)
|
||||
. = ..()
|
||||
mytray.adjustHealth(round(chems.get_reagent_amount(type) * 3))
|
||||
mytray.adjustToxic(-round(chems.get_reagent_amount(type) * 3))
|
||||
|
||||
/datum/reagent/medicine/cryoxadone/on_mob_life(mob/living/carbon/M)
|
||||
var/power = -0.00003 * (M.bodytemperature ** 2) + 3
|
||||
if(M.bodytemperature < T0C)
|
||||
@@ -935,6 +941,12 @@
|
||||
pH = 0
|
||||
value = REAGENT_VALUE_RARE
|
||||
|
||||
// FEED ME SEYMOUR
|
||||
/datum/reagent/medicine/strange_reagent/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray, mob/user)
|
||||
. = ..()
|
||||
if(chems.has_reagent(type, 1))
|
||||
mytray.spawnplant()
|
||||
|
||||
/datum/reagent/medicine/strange_reagent/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
|
||||
if(M.stat == DEAD)
|
||||
if(M.suiciding || M.hellbound) //they are never coming back
|
||||
|
||||
@@ -2545,7 +2545,7 @@
|
||||
M.drowsyness = max(M.drowsyness-5, 0)
|
||||
M.AdjustAllImmobility(-40, FALSE)
|
||||
M.adjustStaminaLoss(-15, FALSE)
|
||||
M.adjustToxLoss(-3, FALSE)
|
||||
M.adjustToxLoss(-3, FALSE, TRUE)
|
||||
M.adjustOxyLoss(-3, FALSE)
|
||||
M.adjustBruteLoss(-3, FALSE)
|
||||
M.adjustFireLoss(-3, FALSE)
|
||||
|
||||
@@ -32,6 +32,12 @@
|
||||
value = REAGENT_VALUE_VERY_COMMON
|
||||
taste_description = "metal"
|
||||
|
||||
//It has stable IN THE NAME. IT WAS MADE FOR THIS MOMENT.
|
||||
/datum/reagent/stabilizing_agent/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray, mob/user)
|
||||
. = ..()
|
||||
if(myseed && chems.has_reagent(type, 1))
|
||||
myseed.adjust_instability(-1)
|
||||
|
||||
/datum/reagent/clf3
|
||||
name = "Chlorine Trifluoride"
|
||||
description = "Makes a temporary 3x3 fireball when it comes into existence, so be careful when mixing. ClF3 applied to a surface burns things that wouldn't otherwise burn, sometimes through the very floors of the station and exposing it to the vacuum of space."
|
||||
@@ -167,6 +173,15 @@
|
||||
taste_description = "burning"
|
||||
value = REAGENT_VALUE_COMMON
|
||||
|
||||
// Smells like victory...
|
||||
/datum/reagent/napalm/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray, mob/user)
|
||||
. = ..()
|
||||
if(chems.has_reagent(type, 1))
|
||||
if(!(myseed.resistance_flags & FIRE_PROOF))
|
||||
mytray.adjustHealth(-round(chems.get_reagent_amount(type) * 6))
|
||||
mytray.adjustToxic(round(chems.get_reagent_amount(type) * 7))
|
||||
mytray.adjustWeeds(-rand(5,9)) //At least give them a small reward if they bother.
|
||||
|
||||
/datum/reagent/napalm/on_mob_life(mob/living/carbon/M)
|
||||
M.adjust_fire_stacks(1)
|
||||
..()
|
||||
|
||||
@@ -364,7 +364,9 @@
|
||||
set waitfor = FALSE
|
||||
if(!SSdbcore.Connect())
|
||||
return
|
||||
var/datum/DBQuery/query_round_shuttle_name = SSdbcore.NewQuery("UPDATE [format_table_name("round")] SET shuttle_name = '[name]' WHERE id = [GLOB.round_id]")
|
||||
var/datum/db_query/query_round_shuttle_name = SSdbcore.NewQuery({"
|
||||
UPDATE [format_table_name("round")] SET shuttle_name = :name WHERE id = :round_id
|
||||
"}, list("name" = name, "round_id" = GLOB.round_id))
|
||||
query_round_shuttle_name.Execute()
|
||||
qdel(query_round_shuttle_name)
|
||||
|
||||
@@ -396,7 +398,7 @@
|
||||
return
|
||||
mode = SHUTTLE_DOCKED
|
||||
setTimer(SSshuttle.emergencyDockTime)
|
||||
send2irc("Server", "The Emergency Shuttle has docked with the station.")
|
||||
send2adminchat("Server", "The Emergency Shuttle has docked with the station.")
|
||||
priority_announce("The Emergency Shuttle has docked with the station. You have [timeLeft(600)] minutes to board the Emergency Shuttle.", null, "shuttledock", "Priority")
|
||||
ShuttleDBStuff()
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
desc = "Take on the shape a lesser ash drake."
|
||||
invocation = "RAAAAAAAAWR!"
|
||||
|
||||
shapeshift_type = /mob/living/simple_animal/hostile/megafauna/dragon/lesser
|
||||
shapeshift_type = /mob/living/simple_animal/hostile/megafauna/dragon/lesser/transformed
|
||||
|
||||
|
||||
/obj/shapeshift_holder
|
||||
|
||||
@@ -24,6 +24,13 @@
|
||||
/datum/surgery_step/toxichealing/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
|
||||
user.visible_message("[user] starts rejuvenating some of [target]'s flesh back to life.", "<span class='notice'>You start knitting some of [target]'s flesh back to life.</span>")
|
||||
|
||||
/datum/surgery_step/toxichealing/initiate(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE)
|
||||
if(..())
|
||||
while((target.getToxLoss() >= 1) || (target.getOxyLoss() >= 1))
|
||||
. = ..()
|
||||
if(!.)
|
||||
break
|
||||
|
||||
/datum/surgery_step/toxichealing/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
|
||||
user.visible_message("[user] fixes some of [target]'s wounds.", "<span class='notice'>You succeed in fixing some of [target]'s wounds.</span>")
|
||||
target.heal_bodypart_damage(0,0,30) //Heals stam
|
||||
|
||||
@@ -381,6 +381,14 @@
|
||||
. = ..()
|
||||
LoadComponent(/datum/component/storage/concrete/tcg)
|
||||
|
||||
/obj/item/tcgcard_deck/ComponentInitialize()
|
||||
. = ..()
|
||||
var/datum/component/storage/STR = GetComponent(/datum/component/storage/concrete/tcg)
|
||||
STR.storage_flags = STORAGE_FLAGS_LEGACY_DEFAULT
|
||||
STR.max_volume = DEFAULT_VOLUME_TINY * 30
|
||||
STR.max_w_class = DEFAULT_VOLUME_TINY
|
||||
STR.max_items = 30
|
||||
|
||||
/obj/item/tcgcard_deck/update_icon_state()
|
||||
. = ..()
|
||||
if(flipped)
|
||||
@@ -548,6 +556,7 @@
|
||||
desc = "A TCG-branded card binder, specifically for your infinite collection of TCG cards!"
|
||||
icon = 'icons/obj/tcg/misc.dmi'
|
||||
icon_state = "binder"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
var/list/cards = list()
|
||||
var/list/decks = list()
|
||||
@@ -796,7 +805,13 @@
|
||||
var/list/card_types = list()
|
||||
for(var/obj/item/tcg_card/card in binder.cards)
|
||||
//if(!card.illegal) //Uncomment if you want to block syndie cards from saving
|
||||
card_types[card.datum_type] = card.illegal
|
||||
if(!(card.datum_type in card_types))
|
||||
card_types[card.datum_type] = card.illegal
|
||||
else
|
||||
if(islist(card_types[card.datum_type]))
|
||||
card_types[card.datum_type] += card.illegal
|
||||
else
|
||||
card_types[card.datum_type] = list(card_types[card.datum_type], card.illegal)
|
||||
|
||||
client.prefs.tcg_decks = binder.decks
|
||||
client.prefs.tcg_cards = card_types
|
||||
|
||||
@@ -98,19 +98,18 @@
|
||||
return json_encode(response)
|
||||
|
||||
/datum/tgs_api/v5/OnTopic(T)
|
||||
if(!initialized)
|
||||
return FALSE //continue world/Topic
|
||||
|
||||
var/list/params = params2list(T)
|
||||
var/json = params[DMAPI5_TOPIC_DATA]
|
||||
if(!json)
|
||||
return FALSE // continue to /world/Topic
|
||||
return FALSE
|
||||
|
||||
var/list/topic_parameters = json_decode(json)
|
||||
if(!topic_parameters)
|
||||
return TopicResponse("Invalid topic parameters json!");
|
||||
|
||||
if(!initialized)
|
||||
TGS_WARNING_LOG("Missed topic due to not being initialized: [T]")
|
||||
return TRUE // too early to handle, but it's still our responsibility
|
||||
|
||||
var/their_sCK = topic_parameters[DMAPI5_PARAMETER_ACCESS_IDENTIFIER]
|
||||
if(their_sCK != access_identifier)
|
||||
return TopicResponse("Failed to decode [DMAPI5_PARAMETER_ACCESS_IDENTIFIER] from: [json]!");
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#define BELLIES_MAX 20
|
||||
#define BELLIES_NAME_MIN 2
|
||||
#define BELLIES_NAME_MAX 12
|
||||
#define BELLIES_DESC_MAX 1024
|
||||
#define BELLIES_NAME_MAX 24
|
||||
#define BELLIES_DESC_MAX 4096
|
||||
|
||||
/mob/living/proc/insidePanel()
|
||||
set name = "Vore Panel"
|
||||
|
||||
Reference in New Issue
Block a user