safety? what's that?

* maybe table-breaking change
This commit is contained in:
Letter N
2021-01-04 11:57:12 +08:00
parent 6e060b13f5
commit cd5d558fad
30 changed files with 341 additions and 195 deletions
+74
View File
@@ -0,0 +1,74 @@
/*
Here's how to use the chat system with configs
send2adminchat is a simple function that broadcasts to admin channels
send2chat is a bit verbose but can be very specific
The second parameter is a string, this string should be read from a config.
What this does is dictacte which TGS4 channels can be sent to.
For example if you have the following channels in tgs4 set up
- Channel 1, Tag: asdf
- Channel 2, Tag: bombay,asdf
- Channel 3, Tag: Hello my name is asdf
- Channel 4, No Tag
- Channel 5, Tag: butts
and you make the call:
send2chat("I sniff butts", CONFIG_GET(string/where_to_send_sniff_butts))
and the config option is set like:
WHERE_TO_SEND_SNIFF_BUTTS asdf
It will be sent to channels 1 and 2
Alternatively if you set the config option to just:
WHERE_TO_SEND_SNIFF_BUTTS
it will be sent to all connected chats.
In TGS3 it will always be sent to all connected designated game chats.
*/
/**
* Sends a message to TGS chat channels.
*
* message - The message to send.
* channel_tag - Required. If "", the message with be sent to all connected (Game-type for TGS3) channels. Otherwise, it will be sent to TGS4 channels with that tag (Delimited by ','s).
*/
/proc/send2chat(message, channel_tag)
if(channel_tag == null || !world.TgsAvailable())
return
var/datum/tgs_version/version = world.TgsVersion()
if(channel_tag == "" || version.suite == 3)
world.TgsTargetedChatBroadcast(message, FALSE)
return
var/list/channels_to_use = list()
for(var/I in world.TgsChatChannelInfo())
var/datum/tgs_chat_channel/channel = I
var/list/applicable_tags = splittext(channel.custom_tag, ",")
if(channel_tag in applicable_tags)
channels_to_use += channel
if(channels_to_use.len)
world.TgsChatBroadcast(message, channels_to_use)
/**
* Sends a message to TGS admin chat channels.
*
* category - The category of the mssage.
* message - The message to send.
*/
/proc/send2adminchat(category, message, embed_links = FALSE)
category = replacetext(replacetext(category, "\proper", ""), "\improper", "")
message = replacetext(replacetext(message, "\proper", ""), "\improper", "")
// if(!embed_links)
// message = GLOB.has_discord_embeddable_links.Replace(replacetext(message, "`", ""), " ```$1``` ")
world.TgsTargetedChatBroadcast("[category] | [message]", TRUE)
+1 -1
View File
@@ -204,7 +204,7 @@
var/survival_rate = GLOB.joined_player_list.len ? "[PERCENT(popcount[POPCOUNT_SURVIVORS]/GLOB.joined_player_list.len)]%" : "there's literally no player"
send2irc("Server", "A round of [mode.name] just ended[mode_result == "undefined" ? "." : " with a [mode_result]."] Survival rate: [survival_rate]")
send2adminchat("Server", "A round of [mode.name] just ended[mode_result == "undefined" ? "." : " with a [mode_result]."] Survival rate: [survival_rate]")
if(length(CONFIG_GET(keyed_list/cross_server)))
send_news_report()
-4
View File
@@ -13,10 +13,6 @@
* SQL sanitization
*/
// Run all strings to be used in an SQL query through this proc first to properly escape out injection attempts.
/proc/sanitizeSQL(t)
return SSdbcore.Quote("[t]")
/proc/format_table_name(table as text)
return CONFIG_GET(string/feedback_tableprefix) + table
-27
View File
@@ -1575,33 +1575,6 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
for(var/i in 1 to items_list[each_item])
new each_item(where_to)
//sends a message to chat
//config_setting should be one of the following
//null - noop
//empty string - use TgsTargetBroadcast with admin_only = FALSE
//other string - use TgsChatBroadcast with the tag that matches config_setting, only works with TGS4, if using TGS3 the above method is used
/proc/send2chat(message, config_setting)
if(config_setting == null)
return
UNTIL(GLOB.tgs_initialized)
if(!world.TgsAvailable())
return
var/datum/tgs_version/version = world.TgsVersion()
if(config_setting == "" || version.suite == 3)
world.TgsTargetedChatBroadcast(message, FALSE)
return
var/list/channels_to_use = list()
for(var/I in world.TgsChatChannelInfo())
var/datum/tgs_chat_channel/channel = I
if(channel.tag == config_setting)
channels_to_use += channel
if(channels_to_use.len)
world.TgsChatBroadcast()
//Checks to see if either the victim has a garlic necklace or garlic in their blood
/proc/blood_sucking_checks(var/mob/living/carbon/target, check_neck, check_blood)
//Bypass this if the target isnt carbon.
+2 -2
View File
@@ -48,7 +48,7 @@
to_chat(src, "<span class='warning'>You're experiencing a bug. Reconnect immediately to fix it. Admins have been notified.</span>")
if(REALTIMEOFDAY >= chnotify + 9000)
chnotify = REALTIMEOFDAY
send2irc_adminless_only("NOCHEAT", message)
send2tgs_adminless_only("NOCHEAT", message)
return
var/list/modifiers = params2list(params)
@@ -113,7 +113,7 @@
A.AICtrlClick(src)
/mob/living/silicon/ai/AltClickOn(var/atom/A)
A.AIAltClick(src)
/*
The following criminally helpful code is just the previous code cleaned up;
@@ -319,6 +319,11 @@
/datum/config_entry/flag/panic_bunker // prevents people the server hasn't seen before from connecting
/datum/config_entry/number/panic_bunker_living // living time in minutes that a player needs to pass the panic bunker
/datum/config_entry/string/panic_bunker_message
config_entry_value = "Sorry but the server is currently not accepting connections from never before seen players."
/datum/config_entry/number/notify_new_player_age // how long do we notify admins of a new player
min_val = -1
+18 -9
View File
@@ -14,12 +14,14 @@ SUBSYSTEM_DEF(blackbox)
"explosion" = 2,
"time_dilation_current" = 3,
"science_techweb_unlock" = 2,
"round_end_stats" = 2) //associative list of any feedback variables that have had their format changed since creation and their current version, remember to update this
"round_end_stats" = 2,
"testmerged_prs" = 2) //associative list of any feedback variables that have had their format changed since creation and their current version, remember to update this
/datum/controller/subsystem/blackbox/Initialize()
triggertime = world.time
record_feedback("amount", "random_seed", Master.random_seed)
record_feedback("amount", "dm_version", DM_VERSION)
record_feedback("amount", "dm_build", DM_BUILD)
record_feedback("amount", "byond_version", world.byond_version)
record_feedback("amount", "byond_build", world.byond_build)
. = ..()
@@ -95,18 +97,24 @@ SUBSYSTEM_DEF(blackbox)
if (!SSdbcore.Connect())
return
var/list/special_columns = list(
"datetime" = "NOW()"
)
var/list/sqlrowlist = list()
for (var/datum/feedback_variable/FV in feedback)
var/sqlversion = 1
if(FV.key in versions)
sqlversion = versions[FV.key]
sqlrowlist += list(list("datetime" = "Now()", "round_id" = GLOB.round_id, "key_name" = "'[sanitizeSQL(FV.key)]'", "key_type" = "'[FV.key_type]'", "version" = "[sqlversion]", "json" = "'[sanitizeSQL(json_encode(FV.json))]'"))
sqlrowlist += list(list(
"round_id" = GLOB.round_id,
"key_name" = FV.key,
"key_type" = FV.key_type,
"version" = versions[FV.key] || 1,
"json" = json_encode(FV.json)
))
if (!length(sqlrowlist))
return
SSdbcore.MassInsert(format_table_name("feedback"), sqlrowlist, ignore_errors = TRUE, delayed = TRUE)
SSdbcore.MassInsert(format_table_name("feedback"), sqlrowlist, ignore_errors = TRUE, delayed = TRUE, special_columns = special_columns)
/datum/controller/subsystem/blackbox/proc/Seal()
if(sealed)
@@ -176,7 +184,7 @@ feedback data can be recorded in 5 formats:
"tally"
used to track the number of occurances of multiple related values i.e. how many times each type of gun is fired
further calls to the same key will:
add or subtract from the saved value of the data key if it already exists
add or subtract from the saved value of the data key if it already exists
append the key and it's value if it doesn't exist
calls: SSblackbox.record_feedback("tally", "example", 1, "sample data")
SSblackbox.record_feedback("tally", "example", 4, "sample data")
@@ -188,7 +196,7 @@ feedback data can be recorded in 5 formats:
the final element in the data list is used as the tracking key, all prior elements are used for nesting
all data list elements must be strings
further calls to the same key will:
add or subtract from the saved value of the data key if it already exists in the same multi-dimensional position
add or subtract from the saved value of the data key if it already exists in the same multi-dimensional position
append the key and it's value if it doesn't exist
calls: SSblackbox.record_feedback("nested tally", "example", 1, list("fruit", "orange", "apricot"))
SSblackbox.record_feedback("nested tally", "example", 2, list("fruit", "orange", "orange"))
@@ -289,6 +297,7 @@ Versioning
query_log_ahelp.Execute()
qdel(query_log_ahelp)
/datum/controller/subsystem/blackbox/proc/ReportDeath(mob/living/L)
set waitfor = FALSE
if(sealed)
+2 -2
View File
@@ -268,7 +268,7 @@ SUBSYSTEM_DEF(ticker)
if(!GLOB.Debug2)
if(!can_continue)
log_game("[mode.name] failed pre_setup, cause: [mode.setup_error]")
send2irc("SSticker", "[mode.name] failed pre_setup, cause: [mode.setup_error]")
send2adminchat("SSticker", "[mode.name] failed pre_setup, cause: [mode.setup_error]")
message_admins("<span class='notice'>[mode.name] failed pre_setup, cause: [mode.setup_error]</span>")
QDEL_NULL(mode)
to_chat(world, "<B>Error setting up [GLOB.master_mode].</B> Reverting to pre-game lobby.")
@@ -334,7 +334,7 @@ SUBSYSTEM_DEF(ticker)
var/list/adm = get_admin_counts()
var/list/allmins = adm["present"]
send2irc("Server", "Round [GLOB.round_id ? "#[GLOB.round_id]:" : "of"] [hide_mode ? "secret":"[mode.name]"] has started[allmins.len ? ".":" with no active admins online!"]")
send2adminchat("Server", "Round [GLOB.round_id ? "#[GLOB.round_id]:" : "of"] [hide_mode ? "secret":"[mode.name]"] has started[allmins.len ? ".":" with no active admins online!"]")
setup_done = TRUE
for(var/i in GLOB.start_landmarks_list)
+1 -1
View File
@@ -90,7 +90,7 @@
if(!is_new_ckey)
log_admin("AUTO BUNKER: [ckeytobypass] given access (incoming comms from [sender]).")
message_admins("AUTO BUNKER: [ckeytobypass] given access (incoming comms from [sender]).")
send2irc("Panic Bunker", "AUTO BUNKER: [ckeytobypass] given access (incoming comms from [sender]).")
send2adminchat("Panic Bunker", "AUTO BUNKER: [ckeytobypass] given access (incoming comms from [sender]).")
return "Success"
/datum/world_topic/ahelp_relay
+43 -27
View File
@@ -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/db_query/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/db_query/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/db_query/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/db_query/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
@@ -278,14 +284,12 @@
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
@@ -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/db_query/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/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]")
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
+2 -6
View File
@@ -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
+8 -2
View File
@@ -4,7 +4,10 @@
return FALSE
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 = '[sanitizeSQL(M.ckey)]' AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned) AND job = '[sanitizeSQL(rank)]'")
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/db_query/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
+15 -21
View File
@@ -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/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)")
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,32 +90,22 @@
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]'"))
switch(alert(" ",,"Add option","Finish", "Cancel"))
@@ -129,7 +117,13 @@
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/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]', '[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
+44 -21
View File
@@ -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,29 +596,52 @@ 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)
/proc/send2otherserver(source,msg,type = "Ahelp")
var/comms_key = CONFIG_GET(string/comms_key)
if(!comms_key)
/**
* Sends a message to a set of cross-communications-enabled servers using world topic calls
*
* Arguments:
* * source - Who sent this message
* * msg - The message body
* * type - The type of message, becomes the topic command under the hood
* * target_servers - A collection of servers to send the message to, defined in config
* * additional_data - An (optional) associated list of extra parameters and data to send with this world topic call
*/
/proc/send2otherserver(source, msg, type = "Ahelp", target_servers, list/additional_data = list())
if(!CONFIG_GET(string/comms_key))
debug_world_log("Server cross-comms message not sent for lack of configured key")
return
var/list/message = list()
message["message_sender"] = source
message["message"] = msg
message["source"] = "([CONFIG_GET(string/cross_comms_name)])"
message["key"] = comms_key
message += type
var/our_id = CONFIG_GET(string/cross_comms_name)
additional_data["message_sender"] = source
additional_data["message"] = msg
additional_data["source"] = "([our_id])"
additional_data += type
var/list/servers = CONFIG_GET(keyed_list/cross_server)
for(var/I in servers)
world.Export("[servers[I]]?[list2params(message)]")
if(I == our_id) //No sending to ourselves
continue
if(target_servers && !(I in target_servers))
continue
world.send_cross_comms(I, additional_data)
/// Sends a message to a given cross comms server by name (by name for security).
/world/proc/send_cross_comms(server_name, list/message, auth = TRUE)
set waitfor = FALSE
if (auth)
var/comms_key = CONFIG_GET(string/comms_key)
if(!comms_key)
debug_world_log("Server cross-comms message not sent for lack of configured key")
return
message["key"] = comms_key
var/list/servers = CONFIG_GET(keyed_list/cross_server)
var/server_url = servers[server_name]
if (!server_url)
CRASH("Invalid cross comms config: [server_name]")
world.Export("[server_url]?[list2params(message)]")
/proc/ircadminwho()
+1 -1
View File
@@ -161,7 +161,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.
+3 -3
View File
@@ -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.")
+2 -2
View File
@@ -318,7 +318,7 @@
/obj/item/clothing/under/suit/white, // white is a weird color for a groom but some people are weird
/obj/item/clothing/under/suit/polychromic,
/obj/item/clothing/under/suit/polychromic, // in case you can't be satisfied with the most fitting choices, of course.
/obj/item/clothing/under/dress/wedding,
/obj/item/clothing/under/dress/wedding,
/obj/item/clothing/under/dress/wedding, // this is what you actually bought the crate for. You can't get these anywhere else.
/obj/item/clothing/under/dress/wedding/orange,
/obj/item/clothing/under/dress/wedding/orange,
@@ -333,4 +333,4 @@
/obj/item/storage/fancy/ringbox/silver,
/obj/item/storage/fancy/ringbox/silver) //diamond rings cost the same price as this crate via cargo so we're not giving you two for free. Wedding rings are traditionally less valuable anyway.
crate_name = "wedding crate"
+33 -4
View File
@@ -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 ///////////////////////////////
//////////////////////////////////////////////////////////////////////////////
+4 -4
View File
@@ -415,7 +415,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)
@@ -423,7 +423,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()
@@ -519,7 +519,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
@@ -576,7 +576,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
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))
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>")
+6 -4
View File
@@ -1331,9 +1331,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/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 = '[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
@@ -1348,7 +1350,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
+1 -1
View File
@@ -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"
+8 -10
View File
@@ -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()
@@ -262,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)
@@ -289,4 +288,3 @@ GLOBAL_PROTECT(exp_to_update)
prefs.db_flags = 0 //This PROBABLY won't happen, but better safe than sorry.
qdel(flags_read)
return TRUE
+3 -3
View File
@@ -440,7 +440,7 @@
if(!GLOB.news_network)
alert("No news network found on station. Aborting.")
var/channelexists = 0
for(var/datum/newscaster/feed_channel/FC in GLOB.news_network.network_channels)
for(var/datum/news/feed_channel/FC in GLOB.news_network.network_channels)
if(FC.channel_name == "Nanotrasen Book Club")
channelexists = 1
break
@@ -490,9 +490,9 @@
if(href_list["printbible"])
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_inhand_icon_state)
if(GLOB.bible_icon_state && GLOB.bible_item_state)
B.icon_state = GLOB.bible_icon_state
B.inhand_icon_state = GLOB.bible_inhand_icon_state
B.item_state = GLOB.bible_item_state
B.name = GLOB.bible_name
B.deity_name = GLOB.deity
printer_cooldown = world.time + PRINTER_COOLDOWN
+35 -13
View File
@@ -456,20 +456,30 @@
//lets add the vote, first we generate an insert statement.
var/sqlrowlist = ""
var/list/sql_args = list("pollid" = pollid, "ckey" = ckey, "address" = address, "rank" = rank) // will always exist
var/__unique_N = 0
for (var/vote in numberedvotelist)
__unique_N++
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)]')"
sqlrowlist += "(Now(), :pollid, :vote[__unique_N], :ckey, INET_ATON(:address), :rank)"
sql_args["vote[__unique_N]"] = vote
//now lets delete their old votes (if any)
var/datum/db_query/query_irv_del_old = SSdbcore.NewQuery("DELETE FROM [format_table_name("poll_vote")] WHERE pollid = [pollid] AND ckey = '[ckey]'")
var/datum/db_query/query_irv_del_old = SSdbcore.NewQuery({"
DELETE FROM [format_table_name("poll_vote")]
WHERE pollid = :pollid AND ckey = :ckey
"}, list("pollid" = pollid, "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/db_query/query_irv_vote = SSdbcore.NewQuery("INSERT INTO [format_table_name("poll_vote")] (datetime, pollid, optionid, ckey, ip, adminrank) VALUES [sqlrowlist]")
var/datum/db_query/query_irv_vote = SSdbcore.NewQuery({"
INSERT INTO [format_table_name("poll_vote")] (datetime, pollid, optionid, ckey, ip, adminrank)
VALUES [sqlrowlist]
"}, sql_args)
if(!query_irv_vote.warn_execute())
qdel(query_irv_vote)
return 0
@@ -493,10 +503,13 @@
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/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('[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
@@ -522,18 +535,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/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
@@ -565,8 +583,10 @@
var/adminrank = "Player"
if(client.holder)
adminrank = client.holder.rank.name
adminrank = sanitizeSQL(adminrank)
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('[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
@@ -609,8 +629,10 @@
var/adminrank = "Player"
if(!QDELETED(client) && client.holder)
adminrank = client.holder.rank.name
adminrank = sanitizeSQL(adminrank)
var/datum/db_query/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]')")
var/datum/db_query/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(:address), :adminrank)
"}, list("pollid" = pollid, "optionid" = optionid, "ckey" = ckey, "address" = client.address, "adminrank" = adminrank))
if(!query_multi_vote.warn_execute())
qdel(query_multi_vote)
return 1
+1 -1
View File
@@ -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
+1 -1
View File
@@ -398,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()