From 29b1fa7bf9acba5fdf0d5571738a0ad1d7ae1fbd Mon Sep 17 00:00:00 2001 From: AffectedArc07 Date: Sun, 30 Dec 2018 09:39:51 +0000 Subject: [PATCH 1/9] Commit 1 (For debug) --- code/__DEFINES/preferences.dm | 1 + code/modules/client/client procs.dm | 56 +++++++++++++++++- .../client/preference/preferences_mysql.dm | 2 +- .../client/preference/preferences_toggles.dm | 14 ++++- icons/paradise.png | Bin 0 -> 1070 bytes interface/skin.dmf | 30 +++++----- 6 files changed, 85 insertions(+), 18 deletions(-) create mode 100644 icons/paradise.png diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm index f465317db9c..0e849bb3371 100644 --- a/code/__DEFINES/preferences.dm +++ b/code/__DEFINES/preferences.dm @@ -25,6 +25,7 @@ #define CHAT_NO_ADMINLOGS 16384 #define DONATOR_PUBLIC 32768 #define CHAT_NO_TICKETLOGS 65536 +#define UI_DARKMODE 131072 #define TOGGLES_DEFAULT (CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|CHAT_LOOC|MEMBER_PUBLIC|DONATOR_PUBLIC) diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 50176f96c5e..c6f057a982b 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -366,9 +366,16 @@ send_resources() + if(prefs.toggles & UI_DARKMODE) // activates dark mode if its flagged. -AA07 + if(establish_db_connection()) + activate_darkmode() + if(prefs.lastchangelog != changelog_hash) //bolds the changelog button on the interface so we know there are updates. -CP if(establish_db_connection()) - winset(src, "rpane.changelog", "background-color=#f4aa94;font-style=bold") + if(prefs.toggles & UI_DARKMODE) + winset(src, "rpane.changelog", "background-color=#bb7700;font-style=bold") + else + winset(src, "rpane.changelog", "background-color=#f4aa94;text-color=#FFFFFF;font-style=bold") to_chat(src, "Changelog has changed since your last visit.") if(!void) @@ -660,3 +667,50 @@ /client/proc/on_varedit() var_edited = TRUE + +///////////////// +// DARKMODE UI // +///////////////// +// IF YOU CHANGE ANYTHING IN ACTIVATE, MAKE SURE IT HAS A DEACTIVATE METHOD, -AA07 +/client/proc/activate_darkmode() + ///// BUTTONS ///// + /* Rpane */ + winset(src, "rpane.textb", "background-color=#40628a;text-color=#FFFFFF") + winset(src, "rpane.infob", "background-color=#40628a;text-color=#FFFFFF") + winset(src, "rpane.wikib", "background-color=#40628a;text-color=#FFFFFF") + winset(src, "rpane.forumb", "background-color=#40628a;text-color=#FFFFFF") + winset(src, "rpane.rulesb", "background-color=#40628a;text-color=#FFFFFF") + winset(src, "rpane.githubb", "background-color=#40628a;text-color=#FFFFFF") + winset(src, "rpane.changelog", "background-color=#40628a;text-color=#FFFFFF") + /* Mainwindow */ + winset(src, "mainwindow.saybutton", "background-color=#40628a;text-color=#FFFFFF") + winset(src, "mainwindow.mebutton", "background-color=#40628a;text-color=#FFFFFF") + winset(src, "mainwindow.hotkey_toggle", "background-color=#40628a;text-color=#FFFFFF") + ///// UI ELEMENTS ///// + /* Mainwindow */ + winset(src, "mainwindow.mainwindow", "background-color=#272727") + winset(src, "mainwindow.asset_cache_browser", "background-color=#272727") + winset(src, "mainwindow.mainvsplit", "background-color=#272727") + winset(src, "mainwindow.tooltip", "background-color=#272727") + /* Mapwindow */ + winset(src, "mapwindow.mapwindow", "background-color=#272727") + winset(src, "mapwindow.map", "background-color=#272727") + /* Outputwindow */ + winset(src, "outputwindow.outputwindow", "background-color=#272727") + winset(src, "outputwindow.browseroutput", "background-color=#272727") + /* Rpane */ + winset(src, "rpane.rpane", "background-color=#272727") + winset(src, "rpane.rpanewindow", "background-color=#272727") + /* Browserwindow */ + winset(src, "browserwindow.browserwindow", "background-color=#272727") + winset(src, "browserwindow.browser", "background-color=#272727") + /* Infowindow */ + winset(src, "infowindow.infowindow", "background-color=#272727;text-color=#FFFFFF") + winset(src, "infowindow.info", "background-color=#272727;text-color=#FFFFFF;highlight-color=#009900;tab-text-color=#FFFFFF;tab-background-color=#272727") + // NOTIFY USER + to_chat(src, "Darkmode Enabled") + +/client/proc/deactivate_darkmode() + ///// BUTTONS ///// + ///// NOTIFY USER ///// + to_chat(src, "Darkmode Disabled") // what a sick fuck \ No newline at end of file diff --git a/code/modules/client/preference/preferences_mysql.dm b/code/modules/client/preference/preferences_mysql.dm index 086040b5595..878cdb1f4a6 100644 --- a/code/modules/client/preference/preferences_mysql.dm +++ b/code/modules/client/preference/preferences_mysql.dm @@ -55,7 +55,7 @@ ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor)) UI_style = sanitize_inlist(UI_style, list("White", "Midnight"), initial(UI_style)) default_slot = sanitize_integer(default_slot, 1, max_save_slots, initial(default_slot)) - toggles = sanitize_integer(toggles, 0, 65535, initial(toggles)) + toggles = sanitize_integer(toggles, 0, 262143, initial(toggles)) sound = sanitize_integer(sound, 0, 65535, initial(sound)) UI_style_color = sanitize_hexcolor(UI_style_color, initial(UI_style_color)) UI_style_alpha = sanitize_integer(UI_style_alpha, 0, 255, initial(UI_style_alpha)) diff --git a/code/modules/client/preference/preferences_toggles.dm b/code/modules/client/preference/preferences_toggles.dm index 40804aa83b2..655f244e7bd 100644 --- a/code/modules/client/preference/preferences_toggles.dm +++ b/code/modules/client/preference/preferences_toggles.dm @@ -195,4 +195,16 @@ set category = "Preferences" set desc = "Allows you to access the Setup Character screen. Changes to your character won't take effect until next round, but other changes will." prefs.current_tab = 1 - prefs.ShowChoices(usr) \ No newline at end of file + prefs.ShowChoices(usr) + +/client/verb/toggle_darkmode() + set name = "Toggle Darkmode" + set category = "Preferences" + set desc = "Toggles UI style between dark and light" + prefs.toggles ^= UI_DARKMODE + prefs.save_preferences(src) + if(prefs.toggles & UI_DARKMODE) + activate_darkmode() + else + deactivate_darkmode() + feedback_add_details("admin_verb","TDarkmode") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! \ No newline at end of file diff --git a/icons/paradise.png b/icons/paradise.png new file mode 100644 index 0000000000000000000000000000000000000000..9b7e3b6db3d67bd0fdd836f61bf7ad3eb6eb78fa GIT binary patch literal 1070 zcmV+}1kwA6P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!TTQ zAt?lfP?iv-*-!@gQJI$GIC>M#Uzl^A%wwp9aPMz({+IXOyf=sWpZoPjo1}e4#j=nD z0W?3XMAL&tT*B{sc|oH0`^W3Wx3v$K07PriCcBQiB%BNZ=0uL>q{)3em}pTj^8Eh| z|9ocwL~C(1z!dG~rkoWuAR=<)*A~~mFh8M)kP1T)jcOy*@{Fqp6fvy+KoP0J)5R(a zidd~upqAiY*I5A3TC7iiHkG@$DI%gDj)K*K@nY%38>|%RzWDDS(QK$Z`3a+qFsG~B4*VB6!BTrK@rXZh}Pn2 zfH_bh<^nt?(HY)e-`fvGGz8Z{5pDUKposTVd@R4?(<>+?fM_kQ2AHFpS|F7x!2t@<~{QBXltx!bJ@P2$g%r`eRjTP(=GdzSo%e zSYJM$IA7EZ>wf_*0f^S3%`@?WzkJ_+LG-f;&d1*l@#}ZC@FFqIhYjj-1KG z Date: Sun, 27 Jan 2019 16:02:17 +0000 Subject: [PATCH 2/9] WORKING TOGGLEABLE DARKMODE (With <3 to Teri) --- code/modules/client/client procs.dm | 1461 ++++++++++++++------------- 1 file changed, 746 insertions(+), 715 deletions(-) diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index c6f057a982b..463559e5b96 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -1,716 +1,747 @@ - //////////// - //SECURITY// - //////////// -//debugging, uncomment for viewing topic calls -//#define TOPIC_DEBUGGING 1 - -#define TOPIC_SPAM_DELAY 2 //2 ticks is about 2/10ths of a second; it was 4 ticks, but that caused too many clicks to be lost due to lag -#define UPLOAD_LIMIT 10485760 //Restricts client uploads to the server to 10MB //Boosted this thing. What's the worst that can happen? -#define MIN_CLIENT_VERSION 0 //Just an ambiguously low version for now, I don't want to suddenly stop people playing. - //I would just like the code ready should it ever need to be used. -#define SUGGESTED_CLIENT_VERSION 511 // only integers (e.g: 510, 511) useful here. Does not properly handle minor versions (e.g: 510.58, 511.848) - - /* - When somebody clicks a link in game, this Topic is called first. - It does the stuff in this proc and then is redirected to the Topic() proc for the src=[0xWhatever] - (if specified in the link). ie locate(hsrc).Topic() - - Such links can be spoofed. - - Because of this certain things MUST be considered whenever adding a Topic() for something: - - Can it be fed harmful values which could cause runtimes? - - Is the Topic call an admin-only thing? - - If so, does it have checks to see if the person who called it (usr.client) is an admin? - - Are the processes being called by Topic() particularly laggy? - - If so, is there any protection against somebody spam-clicking a link? - If you have any questions about this stuff feel free to ask. ~Carn - */ -/client/Topic(href, href_list, hsrc) - if(!usr || usr != mob) //stops us calling Topic for somebody else's client. Also helps prevent usr=null - return - - // src should always be a UID; if it isn't, warn instead of failing entirely - if(href_list["src"]) - hsrc = locateUID(href_list["src"]) - // If there's a ]_ in the src, it's a UID, so don't try to locate it - if(!hsrc && !findtext(href_list["src"], "]_")) - hsrc = locate(href_list["src"]) - if(hsrc) - var/hsrc_info = datum_info_line(hsrc) || "[hsrc]" - log_runtime(EXCEPTION("Got \\ref-based src in topic from [src] for [hsrc_info], should be UID: [href]")) - - #if defined(TOPIC_DEBUGGING) - to_chat(world, "[src]'s Topic: [href] destined for [hsrc].") - #endif - - if(href_list["nano_err"]) //nano throwing errors - if(topic_debugging) - to_chat(src, "## NanoUI: " + html_decode(href_list["nano_err"]))//NANO DEBUG HOOK - - - - if(href_list["asset_cache_confirm_arrival"]) -// to_chat(src, "ASSET JOB [href_list["asset_cache_confirm_arrival"]] ARRIVED.") - var/job = text2num(href_list["asset_cache_confirm_arrival"]) - completed_asset_jobs += job - return - - if(href_list["_src_"] == "chat") - return chatOutput.Topic(href, href_list) - - //Reduces spamming of links by dropping calls that happen during the delay period - if(next_allowed_topic_time > world.time) - return - next_allowed_topic_time = world.time + TOPIC_SPAM_DELAY - - //search the href for script injection - if( findtext(href,"You are no longer able to use this, it's been more then 10 minutes since an admin on IRC has responded to you") - return - if(mute_irc) - to_chat(usr, "") - return - cmd_admin_irc_pm() - return - - - - //Logs all hrefs - if(config && config.log_hrefs) - log_href("[src] (usr:[usr]\[[COORD(usr)]\]) : [hsrc ? "[hsrc] " : ""][href]") - - if(href_list["karmashop"]) - if(config.disable_karma) - return - - switch(href_list["karmashop"]) - if("tab") - karma_tab = text2num(href_list["tab"]) - karmashopmenu() - return - if("shop") - if(href_list["KarmaBuy"]) - var/karma=verify_karma() - if(isnull(karma)) //Doesn't display anything if karma database is down. - return - switch(href_list["KarmaBuy"]) - if("1") - karma_purchase(karma,5,"job","Barber") - if("2") - karma_purchase(karma,5,"job","Brig Physician") - if("3") - karma_purchase(karma,30,"job","Nanotrasen Representative") - if("5") - karma_purchase(karma,30,"job","Blueshield") - if("6") - karma_purchase(karma,30,"job","Mechanic") - if("7") - karma_purchase(karma,45,"job","Magistrate") - if("9") - karma_purchase(karma,30,"job","Security Pod Pilot") - if(href_list["KarmaBuy2"]) - var/karma=verify_karma() - if(isnull(karma)) //Doesn't display anything if karma database is down. - return - switch(href_list["KarmaBuy2"]) - if("1") - karma_purchase(karma,15,"species","Machine People","Machine") - if("2") - karma_purchase(karma,30,"species","Kidan") - if("3") - karma_purchase(karma,30,"species","Grey") - if("4") - karma_purchase(karma,45,"species","Vox") - if("5") - karma_purchase(karma,45,"species","Slime People") - if("6") - karma_purchase(karma,100,"species","Plasmaman") - if("7") - karma_purchase(karma,30,"species","Drask") - if(href_list["KarmaRefund"]) - var/type = href_list["KarmaRefundType"] - var/job = href_list["KarmaRefund"] - var/cost = href_list["KarmaRefundCost"] - karmarefund(type,job,cost) - return - - switch(href_list["_src_"]) - if("holder") hsrc = holder - if("usr") hsrc = mob - if("prefs") return prefs.process_link(usr,href_list) - if("vars") return view_var_Topic(href,href_list,hsrc) - - //Polls and shit - if(href_list["showpoll"]) - handle_player_polling() - return - if(href_list["createpollwindow"]) - create_poll_window() - return - if(href_list["createpoll"]) - create_poll_function(href_list) - return - if(href_list["pollid"]) - var/pollid = href_list["pollid"] - if(istext(pollid)) - pollid = text2num(pollid) - if(isnum(pollid)) - poll_player(pollid) - return - if(href_list["pollresults"]) - var/pollid = href_list["pollresults"] - if(istext(pollid)) - pollid = text2num(pollid) - if(isnum(pollid)) - poll_results(pollid) - if(href_list["votepollid"] && href_list["votetype"]) - if(!can_vote()) - return // No voting. - var/pollid = text2num(href_list["votepollid"]) - var/votetype = href_list["votetype"] - switch(votetype) - if("OPTION") - var/optionid = text2num(href_list["voteoptionid"]) - vote_on_poll(pollid, optionid) - if("TEXT") - var/replytext = href_list["replytext"] - log_text_poll_reply(pollid, replytext) - if("NUMVAL") - var/id_min = text2num(href_list["minid"]) - var/id_max = text2num(href_list["maxid"]) - - if( (id_max - id_min) > 100 ) //Basic exploit prevention - to_chat(usr, "The option ID difference is too big. Please contact administration or the database admin.") - return - - for(var/optionid = id_min; optionid <= id_max; optionid++) - if(!isnull(href_list["o[optionid]"])) //Test if this optionid was replied to - var/rating - if(href_list["o[optionid]"] == "abstain") - rating = null - else - rating = text2num(href_list["o[optionid]"]) - if(!isnum(rating)) - return - - vote_on_numval_poll(pollid, optionid, rating) - if("MULTICHOICE") - var/id_min = text2num(href_list["minoptionid"]) - var/id_max = text2num(href_list["maxoptionid"]) - - if( (id_max - id_min) > 100 ) //Basic exploit prevention - to_chat(usr, "The option ID difference is too big. Please contact administration or the database admin.") - return - - for(var/optionid = id_min; optionid <= id_max; optionid++) - if(!isnull(href_list["option_[optionid]"])) //Test if this optionid was selected - vote_on_poll(pollid, optionid, 1) - src << browse(null, "window=playerpoll") - handle_player_polling() - - switch(href_list["action"]) - if("openLink") - src << link(href_list["link"]) - - ..() //redirect to hsrc.Topic() - -/client/proc/is_content_unlocked() - if(!prefs.unlock_content) - to_chat(src, "Become a BYOND member to access member-perks and features, as well as support the engine that makes this game possible. Click here to find out more.") - return 0 - return 1 - -//Like for /atoms, but clients are their own snowflake FUCK -/client/proc/setDir(newdir) - dir = newdir - -/client/proc/handle_spam_prevention(var/message, var/mute_type, var/throttle = 0) - if(throttle) - if((last_message_time + throttle > world.time) && !check_rights(R_ADMIN, 0)) - var/wait_time = round(((last_message_time + throttle) - world.time) / 10, 1) - to_chat(src, "You are sending messages to quickly. Please wait [wait_time] [wait_time == 1 ? "second" : "seconds"] before sending another message.") - return 1 - last_message_time = world.time - if(config.automute_on && !check_rights(R_ADMIN, 0) && last_message == message) - last_message_count++ - if(last_message_count >= SPAM_TRIGGER_AUTOMUTE) - to_chat(src, "You have exceeded the spam filter limit for identical messages. An auto-mute was applied.") - cmd_admin_mute(mob, mute_type, 1) - return 1 - if(last_message_count >= SPAM_TRIGGER_WARNING) - to_chat(src, "You are nearing the spam filter limit for identical messages.") - return 0 - else - last_message = message - last_message_count = 0 - return 0 - -//This stops files larger than UPLOAD_LIMIT being sent from client to server via input(), client.Import() etc. -/client/AllowUpload(filename, filelength) - if(filelength > UPLOAD_LIMIT) - to_chat(src, "Error: AllowUpload(): File Upload too large. Upload Limit: [UPLOAD_LIMIT/1024]KiB.") - return 0 -/* //Don't need this at the moment. But it's here if it's needed later. - //Helps prevent multiple files being uploaded at once. Or right after eachother. - var/time_to_wait = fileaccess_timer - world.time - if(time_to_wait > 0) - to_chat(src, "Error: AllowUpload(): Spam prevention. Please wait [round(time_to_wait/10)] seconds.") - return 0 - fileaccess_timer = world.time + FTPDELAY */ - return 1 - - - /////////// - //CONNECT// - /////////// -/client/New(TopicData) - var/tdata = TopicData //save this for later use - chatOutput = new /datum/chatOutput(src) // Right off the bat. - TopicData = null //Prevent calls to client.Topic from connect - - if(connection != "seeker") //Invalid connection type. - return null - if(byond_version < MIN_CLIENT_VERSION) // Too out of date to play at all. Unfortunately, we can't send them a message here. - return null - if(byond_version < SUGGESTED_CLIENT_VERSION) // Update is suggested, but not required. - to_chat(src,"Your BYOND client (v: [byond_version]) is out of date. This can cause glitches. We highly suggest you download the latest client from http://www.byond.com/ before playing. ") - - if(IsGuestKey(key)) - alert(src,"This server doesn't allow guest accounts to play. Please go to http://www.byond.com/ and register for a key.","Guest","OK") - del(src) - return - - // Change the way they should download resources. - if(config.resource_urls) - preload_rsc = pick(config.resource_urls) - else preload_rsc = 1 // If config.resource_urls is not set, preload like normal. - - to_chat(src, "If the title screen is black, resources are still downloading. Please be patient until the title screen appears.") - - - GLOB.clients += src - GLOB.directory[ckey] = src - - //Admin Authorisation - holder = admin_datums[ckey] - if(holder) - GLOB.admins += src - holder.owner = src - - donator_check() - - //preferences datum - also holds some persistant data for the client (because we may as well keep these datums to a minimum) - prefs = preferences_datums[ckey] - if(!prefs) - prefs = new /datum/preferences(src) - preferences_datums[ckey] = prefs - prefs.last_ip = address //these are gonna be used for banning - prefs.last_id = computer_id //these are gonna be used for banning - if(world.byond_version >= 511 && byond_version >= 511 && prefs.clientfps) - fps = prefs.clientfps - - spawn() // Goonchat does some non-instant checks in start() - chatOutput.start() - - if(custom_event_msg && custom_event_msg != "") - to_chat(src, "

Custom Event

") - to_chat(src, "

A custom event is taking place. OOC Info:

") - to_chat(src, "[html_encode(custom_event_msg)]") - to_chat(src, "
") - - if( (world.address == address || !address) && !host ) - host = key - world.update_status() - - if(holder) - on_holder_add() - add_admin_verbs() - admin_memo_output("Show", 0, 1) - if(custom_event_admin_msg && custom_event_admin_msg != "" && check_rights(R_EVENT)) - cmd_view_custom_event_info() - - // Forcibly enable hardware-accelerated graphics, as we need them for the lighting overlays. - // (but turn them off first, since sometimes BYOND doesn't turn them on properly otherwise) - spawn(5) // And wait a half-second, since it sounds like you can do this too fast. - if(src) - winset(src, null, "command=\".configure graphics-hwmode off\"") - winset(src, null, "command=\".configure graphics-hwmode on\"") - - log_client_to_db(tdata) - - . = ..() //calls mob.Login() - - if(ckey in clientmessages) - for(var/message in clientmessages[ckey]) - to_chat(src, message) - clientmessages.Remove(ckey) - - - send_resources() - - if(prefs.toggles & UI_DARKMODE) // activates dark mode if its flagged. -AA07 - if(establish_db_connection()) - activate_darkmode() - - if(prefs.lastchangelog != changelog_hash) //bolds the changelog button on the interface so we know there are updates. -CP - if(establish_db_connection()) - if(prefs.toggles & UI_DARKMODE) - winset(src, "rpane.changelog", "background-color=#bb7700;font-style=bold") - else - winset(src, "rpane.changelog", "background-color=#f4aa94;text-color=#FFFFFF;font-style=bold") - to_chat(src, "Changelog has changed since your last visit.") - - if(!void) - void = new() - - screen += void - - if(!winexists(src, "asset_cache_browser")) // The client is using a custom skin, tell them. - to_chat(src, "Unable to access asset cache browser, if you are using a custom skin file, please allow DS to download the updated version, if you are not, then make a bug report. This is not a critical issue but can cause issues with resource downloading, as it is impossible to know when extra resources arrived to you.") - - - //This is down here because of the browse() calls in tooltip/New() - if(!tooltips) - tooltips = new /datum/tooltip(src) - - Master.UpdateTickRate() - -////////////// -//DISCONNECT// -////////////// -/client/Del() - if(holder) - holder.owner = null - GLOB.admins -= src - GLOB.directory -= ckey - GLOB.clients -= src - Master.UpdateTickRate() - return ..() - - -/client/proc/donator_check() - if(IsGuestKey(key)) - return - - establish_db_connection() - if(!dbcon.IsConnected()) - return - - //Donator stuff. - var/DBQuery/query_donor_select = dbcon.NewQuery("SELECT ckey, tier, active FROM `[format_table_name("donators")]` WHERE ckey = '[ckey]'") - query_donor_select.Execute() - while(query_donor_select.NextRow()) - if(!text2num(query_donor_select.item[3])) - // Inactive donator. - donator_level = DONATOR_LEVEL_NONE - return - donator_level = text2num(query_donor_select.item[2]) - break - -/client/proc/log_client_to_db(connectiontopic) - if(IsGuestKey(key)) - return - - - establish_db_connection() - if(!dbcon.IsConnected()) - return - - - var/DBQuery/query = dbcon.NewQuery("SELECT id, datediff(Now(),firstseen) as age FROM [format_table_name("player")] WHERE ckey = '[ckey]'") - query.Execute() - var/sql_id = 0 - player_age = 0 // New players won't have an entry so knowing we have a connection we set this to zero to be updated if there is a record. - while(query.NextRow()) - sql_id = query.item[1] - player_age = text2num(query.item[2]) - break - - - var/DBQuery/query_ip = dbcon.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ip = '[address]'") - query_ip.Execute() - related_accounts_ip = list() - while(query_ip.NextRow()) - if(ckey != query_ip.item[1]) - related_accounts_ip.Add("[query_ip.item[1]]") - - - var/DBQuery/query_cid = dbcon.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE computerid = '[computer_id]'") - query_cid.Execute() - related_accounts_cid = list() - while(query_cid.NextRow()) - if(ckey != query_cid.item[1]) - related_accounts_cid.Add("[query_cid.item[1]]") - - - var/admin_rank = "Player" - if(holder) - admin_rank = holder.rank - // Admins don't get slammed by this, I guess - else - if(check_randomizer(connectiontopic)) - return - - - //Log all the alts - if(related_accounts_cid.len) - log_admin("[key_name(src)] alts:[jointext(related_accounts_cid, " - ")]") - - - var/watchreason = check_watchlist(ckey) - if(watchreason) - message_admins("Notice: [key_name_admin(src)] is on the watchlist and has just connected - Reason: [watchreason]") - send2irc(config.admin_notify_irc, "Watchlist - [key_name(src)] is on the watchlist and has just connected - Reason: [watchreason]") - - - //Just the standard check to see if it's actually a number - if(sql_id) - if(istext(sql_id)) - sql_id = text2num(sql_id) - if(!isnum(sql_id)) - return - - var/sql_ip = sanitizeSQL(address) - var/sql_computerid = sanitizeSQL(computer_id) - var/sql_admin_rank = sanitizeSQL(admin_rank) - - - if(sql_id) - //Player already identified previously, we need to just update the 'lastseen', 'ip' and 'computer_id' variables - var/DBQuery/query_update = dbcon.NewQuery("UPDATE [format_table_name("player")] SET lastseen = Now(), ip = '[sql_ip]', computerid = '[sql_computerid]', lastadminrank = '[sql_admin_rank]' WHERE id = [sql_id]") - if(!query_update.Execute()) - var/err = query_update.ErrorMsg() - log_game("SQL ERROR during log_client_to_db (update). Error : \[[err]\]\n") - message_admins("SQL ERROR during log_client_to_db (update). Error : \[[err]\]\n") - else - //New player!! Need to insert all the stuff - var/DBQuery/query_insert = dbcon.NewQuery("INSERT INTO [format_table_name("player")] (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, '[ckey]', Now(), Now(), '[sql_ip]', '[sql_computerid]', '[sql_admin_rank]')") - if(!query_insert.Execute()) - var/err = query_insert.ErrorMsg() - log_game("SQL ERROR during log_client_to_db (insert). Error : \[[err]\]\n") - message_admins("SQL ERROR during log_client_to_db (insert). Error : \[[err]\]\n") - - //Logging player access - var/serverip = "[world.internet_address]:[world.port]" - var/DBQuery/query_accesslog = dbcon.NewQuery("INSERT INTO `[format_table_name("connection_log")]`(`id`,`datetime`,`serverip`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),'[serverip]','[ckey]','[sql_ip]','[sql_computerid]');") - query_accesslog.Execute() - - -#undef TOPIC_SPAM_DELAY -#undef UPLOAD_LIMIT -#undef MIN_CLIENT_VERSION - -// Returns true if a randomizer is being used -/client/proc/check_randomizer(topic) - . = FALSE - if(connection != "seeker") //Invalid connection type. - return null - topic = params2list(topic) - if(!config.check_randomizer) - return - // Stash o' ckeys - var/static/cidcheck = list() - var/static/tokens = list() - // Ckeys that failed the test, stored to send acceptance messages only for atoners - var/static/cidcheck_failedckeys = list() - var/static/cidcheck_spoofckeys = list() - - var/oldcid = cidcheck[ckey] - - if(!oldcid) - var/DBQuery/query_cidcheck = dbcon.NewQuery("SELECT computerid FROM [format_table_name("player")] WHERE ckey = '[ckey]'") - query_cidcheck.Execute() - - var/lastcid = computer_id - if(query_cidcheck.NextRow()) - lastcid = query_cidcheck.item[1] - - if(computer_id != lastcid) - // Their current CID does not match what the DB says - OFF WITH THEIR HEAD - cidcheck[ckey] = computer_id - - // Disable the reconnect button to force a CID change - winset(src, "reconnectbutton", "is-disable=true") - - tokens[ckey] = cid_check_reconnect() - sleep(10) // Since browse is non-instant, and kinda async - - to_chat(src, "
you're a huge nerd. wakka wakka doodle doop nobody's ever gonna see this, the chat system shouldn't be online by this point
") - del(src) - return TRUE - else - if (!topic || !topic["token"] || !tokens[ckey] || topic["token"] != tokens[ckey]) - if (!cidcheck_spoofckeys[ckey]) - message_admins("[key_name(src)] appears to have attempted to spoof a cid randomizer check.") - cidcheck_spoofckeys[ckey] = TRUE - cidcheck[ckey] = computer_id - tokens[ckey] = cid_check_reconnect() - - sleep(10) //browse is queued, we don't want them to disconnect before getting the browse() command. - del(src) - return TRUE - // We DO have their cached CID handy - compare it, now - if(oldcid != computer_id) - // Change detected, they are randomizing - cidcheck -= ckey // To allow them to try again after removing CID randomization - - to_chat(src, "Connection Error:") - to_chat(src, "Invalid ComputerID(spoofed). Please remove the ComputerID spoofer from your BYOND installation and try again.") - - if(!cidcheck_failedckeys[ckey]) - message_admins("[key_name(src)] has been detected as using a CID randomizer. Connection rejected.") - send2irc(config.cidrandomizer_irc, "[key_name(src)] has been detected as using a CID randomizer. Connection rejected.") - cidcheck_failedckeys[ckey] = TRUE - note_randomizer_user() - - log_adminwarn("Failed Login: [key] [computer_id] [address] - CID randomizer confirmed (oldcid: [oldcid])") - - del(src) - return TRUE - else - // don't shoot, I'm innocent - if(cidcheck_failedckeys[ckey]) - // Atonement - message_admins("[key_name_admin(src)] has been allowed to connect after showing they removed their cid randomizer") - send2irc(config.cidrandomizer_irc, "[key_name(src)] has been allowed to connect after showing they removed their cid randomizer.") - cidcheck_failedckeys -= ckey - if (cidcheck_spoofckeys[ckey]) - message_admins("[key_name_admin(src)] has been allowed to connect after appearing to have attempted to spoof a cid randomizer check because it appears they aren't spoofing one this time") - cidcheck_spoofckeys -= ckey - cidcheck -= ckey - -/client/proc/note_randomizer_user() - var/const/adminckey = "CID-Error" - - // Check for notes in the last day - only 1 note per 24 hours - var/DBQuery/query_get_notes = dbcon.NewQuery("SELECT id from [format_table_name("notes")] WHERE ckey = '[ckey]' AND adminckey = '[adminckey]' AND timestamp + INTERVAL 1 DAY < NOW()") - if(!query_get_notes.Execute()) - var/err = query_get_notes.ErrorMsg() - log_game("SQL ERROR obtaining id from notes table. Error : \[[err]\]\n") - return - if(query_get_notes.NextRow()) - return - - // Only add a note if their most recent note isn't from the randomizer blocker, either - query_get_notes = dbcon.NewQuery("SELECT adminckey FROM [format_table_name("notes")] WHERE ckey = '[ckey]' ORDER BY timestamp DESC LIMIT 1") - if(!query_get_notes.Execute()) - var/err = query_get_notes.ErrorMsg() - log_game("SQL ERROR obtaining adminckey from notes table. Error : \[[err]\]\n") - return - if(query_get_notes.NextRow()) - if(query_get_notes.item[1] == adminckey) - return - add_note(ckey, "Detected as using a cid randomizer.", null, adminckey, logged = 0) - -/client/proc/cid_check_reconnect() - var/token = md5("[rand(0,9999)][world.time][rand(0,9999)][ckey][rand(0,9999)][address][rand(0,9999)][computer_id][rand(0,9999)]") - . = token - log_adminwarn("Failed Login: [key] [computer_id] [address] - CID randomizer check") - var/url = winget(src, null, "url") - //special javascript to make them reconnect under a new window. - src << browse("\ - byond://[url]?token=[token]\ - \ - ", - "border=0;titlebar=0;size=1x1") - to_chat(src, "You will be automatically taken to the game, if not, click here to be taken manually. Except you can't, since the chat window doesn't exist yet.") - -//checks if a client is afk -//3000 frames = 5 minutes -/client/proc/is_afk(duration=3000) - if(inactivity > duration) return inactivity - return 0 - -//Send resources to the client. -/client/proc/send_resources() - // Most assets are now handled through global_cache.dm - getFiles( - 'html/search.js', // Used in various non-NanoUI HTML windows for search functionality - 'html/panels.css' // Used for styling certain panels, such as in the new player panel - ) - spawn (10) //removing this spawn causes all clients to not get verbs. - //Precache the client with all other assets slowly, so as to not block other browse() calls - getFilesSlow(src, SSassets.preload, register_asset = FALSE) - -//For debugging purposes -/client/proc/list_all_languages() - for(var/L in GLOB.all_languages) - var/datum/language/lang = GLOB.all_languages[L] - var/message = "[lang.name] : [lang.type]" - if(lang.flags & RESTRICTED) - message += " (RESTRICTED)" - to_chat(world, "[message]") - -/client/proc/colour_transition(var/list/colour_to = null, var/time = 10) //Call this with no parameters to reset to default. - animate(src, color=colour_to, time=time, easing=SINE_EASING) - -/client/proc/on_varedit() - var_edited = TRUE - -///////////////// -// DARKMODE UI // -///////////////// -// IF YOU CHANGE ANYTHING IN ACTIVATE, MAKE SURE IT HAS A DEACTIVATE METHOD, -AA07 -/client/proc/activate_darkmode() - ///// BUTTONS ///// - /* Rpane */ - winset(src, "rpane.textb", "background-color=#40628a;text-color=#FFFFFF") - winset(src, "rpane.infob", "background-color=#40628a;text-color=#FFFFFF") - winset(src, "rpane.wikib", "background-color=#40628a;text-color=#FFFFFF") - winset(src, "rpane.forumb", "background-color=#40628a;text-color=#FFFFFF") - winset(src, "rpane.rulesb", "background-color=#40628a;text-color=#FFFFFF") - winset(src, "rpane.githubb", "background-color=#40628a;text-color=#FFFFFF") - winset(src, "rpane.changelog", "background-color=#40628a;text-color=#FFFFFF") - /* Mainwindow */ - winset(src, "mainwindow.saybutton", "background-color=#40628a;text-color=#FFFFFF") - winset(src, "mainwindow.mebutton", "background-color=#40628a;text-color=#FFFFFF") - winset(src, "mainwindow.hotkey_toggle", "background-color=#40628a;text-color=#FFFFFF") - ///// UI ELEMENTS ///// - /* Mainwindow */ - winset(src, "mainwindow.mainwindow", "background-color=#272727") - winset(src, "mainwindow.asset_cache_browser", "background-color=#272727") - winset(src, "mainwindow.mainvsplit", "background-color=#272727") - winset(src, "mainwindow.tooltip", "background-color=#272727") - /* Mapwindow */ - winset(src, "mapwindow.mapwindow", "background-color=#272727") - winset(src, "mapwindow.map", "background-color=#272727") - /* Outputwindow */ - winset(src, "outputwindow.outputwindow", "background-color=#272727") - winset(src, "outputwindow.browseroutput", "background-color=#272727") - /* Rpane */ - winset(src, "rpane.rpane", "background-color=#272727") - winset(src, "rpane.rpanewindow", "background-color=#272727") - /* Browserwindow */ - winset(src, "browserwindow.browserwindow", "background-color=#272727") - winset(src, "browserwindow.browser", "background-color=#272727") - /* Infowindow */ - winset(src, "infowindow.infowindow", "background-color=#272727;text-color=#FFFFFF") - winset(src, "infowindow.info", "background-color=#272727;text-color=#FFFFFF;highlight-color=#009900;tab-text-color=#FFFFFF;tab-background-color=#272727") - // NOTIFY USER - to_chat(src, "Darkmode Enabled") - -/client/proc/deactivate_darkmode() - ///// BUTTONS ///// - ///// NOTIFY USER ///// + //////////// + //SECURITY// + //////////// +//debugging, uncomment for viewing topic calls +//#define TOPIC_DEBUGGING 1 + +#define TOPIC_SPAM_DELAY 2 //2 ticks is about 2/10ths of a second; it was 4 ticks, but that caused too many clicks to be lost due to lag +#define UPLOAD_LIMIT 10485760 //Restricts client uploads to the server to 10MB //Boosted this thing. What's the worst that can happen? +#define MIN_CLIENT_VERSION 0 //Just an ambiguously low version for now, I don't want to suddenly stop people playing. + //I would just like the code ready should it ever need to be used. +#define SUGGESTED_CLIENT_VERSION 511 // only integers (e.g: 510, 511) useful here. Does not properly handle minor versions (e.g: 510.58, 511.848) + + /* + When somebody clicks a link in game, this Topic is called first. + It does the stuff in this proc and then is redirected to the Topic() proc for the src=[0xWhatever] + (if specified in the link). ie locate(hsrc).Topic() + + Such links can be spoofed. + + Because of this certain things MUST be considered whenever adding a Topic() for something: + - Can it be fed harmful values which could cause runtimes? + - Is the Topic call an admin-only thing? + - If so, does it have checks to see if the person who called it (usr.client) is an admin? + - Are the processes being called by Topic() particularly laggy? + - If so, is there any protection against somebody spam-clicking a link? + If you have any questions about this stuff feel free to ask. ~Carn + */ +/client/Topic(href, href_list, hsrc) + if(!usr || usr != mob) //stops us calling Topic for somebody else's client. Also helps prevent usr=null + return + + // src should always be a UID; if it isn't, warn instead of failing entirely + if(href_list["src"]) + hsrc = locateUID(href_list["src"]) + // If there's a ]_ in the src, it's a UID, so don't try to locate it + if(!hsrc && !findtext(href_list["src"], "]_")) + hsrc = locate(href_list["src"]) + if(hsrc) + var/hsrc_info = datum_info_line(hsrc) || "[hsrc]" + log_runtime(EXCEPTION("Got \\ref-based src in topic from [src] for [hsrc_info], should be UID: [href]")) + + #if defined(TOPIC_DEBUGGING) + to_chat(world, "[src]'s Topic: [href] destined for [hsrc].") + #endif + + if(href_list["nano_err"]) //nano throwing errors + if(topic_debugging) + to_chat(src, "## NanoUI: " + html_decode(href_list["nano_err"]))//NANO DEBUG HOOK + + + + if(href_list["asset_cache_confirm_arrival"]) +// to_chat(src, "ASSET JOB [href_list["asset_cache_confirm_arrival"]] ARRIVED.") + var/job = text2num(href_list["asset_cache_confirm_arrival"]) + completed_asset_jobs += job + return + + if(href_list["_src_"] == "chat") + return chatOutput.Topic(href, href_list) + + //Reduces spamming of links by dropping calls that happen during the delay period + if(next_allowed_topic_time > world.time) + return + next_allowed_topic_time = world.time + TOPIC_SPAM_DELAY + + //search the href for script injection + if( findtext(href,"You are no longer able to use this, it's been more then 10 minutes since an admin on IRC has responded to you
") + return + if(mute_irc) + to_chat(usr, "") + return + cmd_admin_irc_pm() + return + + + + //Logs all hrefs + if(config && config.log_hrefs) + log_href("[src] (usr:[usr]\[[COORD(usr)]\]) : [hsrc ? "[hsrc] " : ""][href]") + + if(href_list["karmashop"]) + if(config.disable_karma) + return + + switch(href_list["karmashop"]) + if("tab") + karma_tab = text2num(href_list["tab"]) + karmashopmenu() + return + if("shop") + if(href_list["KarmaBuy"]) + var/karma=verify_karma() + if(isnull(karma)) //Doesn't display anything if karma database is down. + return + switch(href_list["KarmaBuy"]) + if("1") + karma_purchase(karma,5,"job","Barber") + if("2") + karma_purchase(karma,5,"job","Brig Physician") + if("3") + karma_purchase(karma,30,"job","Nanotrasen Representative") + if("5") + karma_purchase(karma,30,"job","Blueshield") + if("6") + karma_purchase(karma,30,"job","Mechanic") + if("7") + karma_purchase(karma,45,"job","Magistrate") + if("9") + karma_purchase(karma,30,"job","Security Pod Pilot") + if(href_list["KarmaBuy2"]) + var/karma=verify_karma() + if(isnull(karma)) //Doesn't display anything if karma database is down. + return + switch(href_list["KarmaBuy2"]) + if("1") + karma_purchase(karma,15,"species","Machine People","Machine") + if("2") + karma_purchase(karma,30,"species","Kidan") + if("3") + karma_purchase(karma,30,"species","Grey") + if("4") + karma_purchase(karma,45,"species","Vox") + if("5") + karma_purchase(karma,45,"species","Slime People") + if("6") + karma_purchase(karma,100,"species","Plasmaman") + if("7") + karma_purchase(karma,30,"species","Drask") + if(href_list["KarmaRefund"]) + var/type = href_list["KarmaRefundType"] + var/job = href_list["KarmaRefund"] + var/cost = href_list["KarmaRefundCost"] + karmarefund(type,job,cost) + return + + switch(href_list["_src_"]) + if("holder") hsrc = holder + if("usr") hsrc = mob + if("prefs") return prefs.process_link(usr,href_list) + if("vars") return view_var_Topic(href,href_list,hsrc) + + //Polls and shit + if(href_list["showpoll"]) + handle_player_polling() + return + if(href_list["createpollwindow"]) + create_poll_window() + return + if(href_list["createpoll"]) + create_poll_function(href_list) + return + if(href_list["pollid"]) + var/pollid = href_list["pollid"] + if(istext(pollid)) + pollid = text2num(pollid) + if(isnum(pollid)) + poll_player(pollid) + return + if(href_list["pollresults"]) + var/pollid = href_list["pollresults"] + if(istext(pollid)) + pollid = text2num(pollid) + if(isnum(pollid)) + poll_results(pollid) + if(href_list["votepollid"] && href_list["votetype"]) + if(!can_vote()) + return // No voting. + var/pollid = text2num(href_list["votepollid"]) + var/votetype = href_list["votetype"] + switch(votetype) + if("OPTION") + var/optionid = text2num(href_list["voteoptionid"]) + vote_on_poll(pollid, optionid) + if("TEXT") + var/replytext = href_list["replytext"] + log_text_poll_reply(pollid, replytext) + if("NUMVAL") + var/id_min = text2num(href_list["minid"]) + var/id_max = text2num(href_list["maxid"]) + + if( (id_max - id_min) > 100 ) //Basic exploit prevention + to_chat(usr, "The option ID difference is too big. Please contact administration or the database admin.") + return + + for(var/optionid = id_min; optionid <= id_max; optionid++) + if(!isnull(href_list["o[optionid]"])) //Test if this optionid was replied to + var/rating + if(href_list["o[optionid]"] == "abstain") + rating = null + else + rating = text2num(href_list["o[optionid]"]) + if(!isnum(rating)) + return + + vote_on_numval_poll(pollid, optionid, rating) + if("MULTICHOICE") + var/id_min = text2num(href_list["minoptionid"]) + var/id_max = text2num(href_list["maxoptionid"]) + + if( (id_max - id_min) > 100 ) //Basic exploit prevention + to_chat(usr, "The option ID difference is too big. Please contact administration or the database admin.") + return + + for(var/optionid = id_min; optionid <= id_max; optionid++) + if(!isnull(href_list["option_[optionid]"])) //Test if this optionid was selected + vote_on_poll(pollid, optionid, 1) + src << browse(null, "window=playerpoll") + handle_player_polling() + + switch(href_list["action"]) + if("openLink") + src << link(href_list["link"]) + + ..() //redirect to hsrc.Topic() + +/client/proc/is_content_unlocked() + if(!prefs.unlock_content) + to_chat(src, "Become a BYOND member to access member-perks and features, as well as support the engine that makes this game possible. Click here to find out more.") + return 0 + return 1 + +//Like for /atoms, but clients are their own snowflake FUCK +/client/proc/setDir(newdir) + dir = newdir + +/client/proc/handle_spam_prevention(var/message, var/mute_type, var/throttle = 0) + if(throttle) + if((last_message_time + throttle > world.time) && !check_rights(R_ADMIN, 0)) + var/wait_time = round(((last_message_time + throttle) - world.time) / 10, 1) + to_chat(src, "You are sending messages to quickly. Please wait [wait_time] [wait_time == 1 ? "second" : "seconds"] before sending another message.") + return 1 + last_message_time = world.time + if(config.automute_on && !check_rights(R_ADMIN, 0) && last_message == message) + last_message_count++ + if(last_message_count >= SPAM_TRIGGER_AUTOMUTE) + to_chat(src, "You have exceeded the spam filter limit for identical messages. An auto-mute was applied.") + cmd_admin_mute(mob, mute_type, 1) + return 1 + if(last_message_count >= SPAM_TRIGGER_WARNING) + to_chat(src, "You are nearing the spam filter limit for identical messages.") + return 0 + else + last_message = message + last_message_count = 0 + return 0 + +//This stops files larger than UPLOAD_LIMIT being sent from client to server via input(), client.Import() etc. +/client/AllowUpload(filename, filelength) + if(filelength > UPLOAD_LIMIT) + to_chat(src, "Error: AllowUpload(): File Upload too large. Upload Limit: [UPLOAD_LIMIT/1024]KiB.") + return 0 +/* //Don't need this at the moment. But it's here if it's needed later. + //Helps prevent multiple files being uploaded at once. Or right after eachother. + var/time_to_wait = fileaccess_timer - world.time + if(time_to_wait > 0) + to_chat(src, "Error: AllowUpload(): Spam prevention. Please wait [round(time_to_wait/10)] seconds.") + return 0 + fileaccess_timer = world.time + FTPDELAY */ + return 1 + + + /////////// + //CONNECT// + /////////// +/client/New(TopicData) + var/tdata = TopicData //save this for later use + chatOutput = new /datum/chatOutput(src) // Right off the bat. + TopicData = null //Prevent calls to client.Topic from connect + + if(connection != "seeker") //Invalid connection type. + return null + if(byond_version < MIN_CLIENT_VERSION) // Too out of date to play at all. Unfortunately, we can't send them a message here. + return null + if(byond_version < SUGGESTED_CLIENT_VERSION) // Update is suggested, but not required. + to_chat(src,"Your BYOND client (v: [byond_version]) is out of date. This can cause glitches. We highly suggest you download the latest client from http://www.byond.com/ before playing. ") + + if(IsGuestKey(key)) + alert(src,"This server doesn't allow guest accounts to play. Please go to http://www.byond.com/ and register for a key.","Guest","OK") + del(src) + return + + // Change the way they should download resources. + if(config.resource_urls) + preload_rsc = pick(config.resource_urls) + else preload_rsc = 1 // If config.resource_urls is not set, preload like normal. + + to_chat(src, "If the title screen is black, resources are still downloading. Please be patient until the title screen appears.") + + + GLOB.clients += src + GLOB.directory[ckey] = src + + //Admin Authorisation + holder = admin_datums[ckey] + if(holder) + GLOB.admins += src + holder.owner = src + + donator_check() + + //preferences datum - also holds some persistant data for the client (because we may as well keep these datums to a minimum) + prefs = preferences_datums[ckey] + if(!prefs) + prefs = new /datum/preferences(src) + preferences_datums[ckey] = prefs + prefs.last_ip = address //these are gonna be used for banning + prefs.last_id = computer_id //these are gonna be used for banning + if(world.byond_version >= 511 && byond_version >= 511 && prefs.clientfps) + fps = prefs.clientfps + + spawn() // Goonchat does some non-instant checks in start() + chatOutput.start() + + if(custom_event_msg && custom_event_msg != "") + to_chat(src, "

Custom Event

") + to_chat(src, "

A custom event is taking place. OOC Info:

") + to_chat(src, "[html_encode(custom_event_msg)]") + to_chat(src, "
") + + if( (world.address == address || !address) && !host ) + host = key + world.update_status() + + if(holder) + on_holder_add() + add_admin_verbs() + admin_memo_output("Show", 0, 1) + if(custom_event_admin_msg && custom_event_admin_msg != "" && check_rights(R_EVENT)) + cmd_view_custom_event_info() + + // Forcibly enable hardware-accelerated graphics, as we need them for the lighting overlays. + // (but turn them off first, since sometimes BYOND doesn't turn them on properly otherwise) + spawn(5) // And wait a half-second, since it sounds like you can do this too fast. + if(src) + winset(src, null, "command=\".configure graphics-hwmode off\"") + winset(src, null, "command=\".configure graphics-hwmode on\"") + + log_client_to_db(tdata) + + . = ..() //calls mob.Login() + + if(ckey in clientmessages) + for(var/message in clientmessages[ckey]) + to_chat(src, message) + clientmessages.Remove(ckey) + + + send_resources() + + if(prefs.toggles & UI_DARKMODE) // activates dark mode if its flagged. -AA07 + if(establish_db_connection()) + activate_darkmode() + + if(prefs.lastchangelog != changelog_hash) //bolds the changelog button on the interface so we know there are updates. -CP + if(establish_db_connection()) + to_chat(src, "Changelog has changed since your last visit.") + winset(src, "rpane.changelog", "background-color=#bb7700;font-style=bold") + else + if(establish_db_connection()) + if(prefs.toggles & UI_DARKMODE) + winset(src, "rpane.changelog", "background-color=#bb7700;font-style=bold") // makes changelog dark if its been set + else + winset(src, "rpane.changelog", "background-color=#ffffff;font-color=#000000") // makes changelog normal if it hasnt been set + else + winset(src, "rpane.changelog", "background-color=#ffffff;font-color=#000000") // makes changelog normal if DB isnt connected + + + if(!void) + void = new() + + screen += void + + if(!winexists(src, "asset_cache_browser")) // The client is using a custom skin, tell them. + to_chat(src, "Unable to access asset cache browser, if you are using a custom skin file, please allow DS to download the updated version, if you are not, then make a bug report. This is not a critical issue but can cause issues with resource downloading, as it is impossible to know when extra resources arrived to you.") + + + //This is down here because of the browse() calls in tooltip/New() + if(!tooltips) + tooltips = new /datum/tooltip(src) + + Master.UpdateTickRate() + +////////////// +//DISCONNECT// +////////////// +/client/Del() + if(holder) + holder.owner = null + GLOB.admins -= src + GLOB.directory -= ckey + GLOB.clients -= src + Master.UpdateTickRate() + return ..() + + +/client/proc/donator_check() + if(IsGuestKey(key)) + return + + establish_db_connection() + if(!dbcon.IsConnected()) + return + + //Donator stuff. + var/DBQuery/query_donor_select = dbcon.NewQuery("SELECT ckey, tier, active FROM `[format_table_name("donators")]` WHERE ckey = '[ckey]'") + query_donor_select.Execute() + while(query_donor_select.NextRow()) + if(!text2num(query_donor_select.item[3])) + // Inactive donator. + donator_level = DONATOR_LEVEL_NONE + return + donator_level = text2num(query_donor_select.item[2]) + break + +/client/proc/log_client_to_db(connectiontopic) + if(IsGuestKey(key)) + return + + + establish_db_connection() + if(!dbcon.IsConnected()) + return + + + var/DBQuery/query = dbcon.NewQuery("SELECT id, datediff(Now(),firstseen) as age FROM [format_table_name("player")] WHERE ckey = '[ckey]'") + query.Execute() + var/sql_id = 0 + player_age = 0 // New players won't have an entry so knowing we have a connection we set this to zero to be updated if there is a record. + while(query.NextRow()) + sql_id = query.item[1] + player_age = text2num(query.item[2]) + break + + + var/DBQuery/query_ip = dbcon.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ip = '[address]'") + query_ip.Execute() + related_accounts_ip = list() + while(query_ip.NextRow()) + if(ckey != query_ip.item[1]) + related_accounts_ip.Add("[query_ip.item[1]]") + + + var/DBQuery/query_cid = dbcon.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE computerid = '[computer_id]'") + query_cid.Execute() + related_accounts_cid = list() + while(query_cid.NextRow()) + if(ckey != query_cid.item[1]) + related_accounts_cid.Add("[query_cid.item[1]]") + + + var/admin_rank = "Player" + if(holder) + admin_rank = holder.rank + // Admins don't get slammed by this, I guess + else + if(check_randomizer(connectiontopic)) + return + + + //Log all the alts + if(related_accounts_cid.len) + log_admin("[key_name(src)] alts:[jointext(related_accounts_cid, " - ")]") + + + var/watchreason = check_watchlist(ckey) + if(watchreason) + message_admins("Notice: [key_name_admin(src)] is on the watchlist and has just connected - Reason: [watchreason]") + send2irc(config.admin_notify_irc, "Watchlist - [key_name(src)] is on the watchlist and has just connected - Reason: [watchreason]") + + + //Just the standard check to see if it's actually a number + if(sql_id) + if(istext(sql_id)) + sql_id = text2num(sql_id) + if(!isnum(sql_id)) + return + + var/sql_ip = sanitizeSQL(address) + var/sql_computerid = sanitizeSQL(computer_id) + var/sql_admin_rank = sanitizeSQL(admin_rank) + + + if(sql_id) + //Player already identified previously, we need to just update the 'lastseen', 'ip' and 'computer_id' variables + var/DBQuery/query_update = dbcon.NewQuery("UPDATE [format_table_name("player")] SET lastseen = Now(), ip = '[sql_ip]', computerid = '[sql_computerid]', lastadminrank = '[sql_admin_rank]' WHERE id = [sql_id]") + if(!query_update.Execute()) + var/err = query_update.ErrorMsg() + log_game("SQL ERROR during log_client_to_db (update). Error : \[[err]\]\n") + message_admins("SQL ERROR during log_client_to_db (update). Error : \[[err]\]\n") + else + //New player!! Need to insert all the stuff + var/DBQuery/query_insert = dbcon.NewQuery("INSERT INTO [format_table_name("player")] (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, '[ckey]', Now(), Now(), '[sql_ip]', '[sql_computerid]', '[sql_admin_rank]')") + if(!query_insert.Execute()) + var/err = query_insert.ErrorMsg() + log_game("SQL ERROR during log_client_to_db (insert). Error : \[[err]\]\n") + message_admins("SQL ERROR during log_client_to_db (insert). Error : \[[err]\]\n") + + //Logging player access + var/serverip = "[world.internet_address]:[world.port]" + var/DBQuery/query_accesslog = dbcon.NewQuery("INSERT INTO `[format_table_name("connection_log")]`(`id`,`datetime`,`serverip`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),'[serverip]','[ckey]','[sql_ip]','[sql_computerid]');") + query_accesslog.Execute() + + +#undef TOPIC_SPAM_DELAY +#undef UPLOAD_LIMIT +#undef MIN_CLIENT_VERSION + +// Returns true if a randomizer is being used +/client/proc/check_randomizer(topic) + . = FALSE + if(connection != "seeker") //Invalid connection type. + return null + topic = params2list(topic) + if(!config.check_randomizer) + return + // Stash o' ckeys + var/static/cidcheck = list() + var/static/tokens = list() + // Ckeys that failed the test, stored to send acceptance messages only for atoners + var/static/cidcheck_failedckeys = list() + var/static/cidcheck_spoofckeys = list() + + var/oldcid = cidcheck[ckey] + + if(!oldcid) + var/DBQuery/query_cidcheck = dbcon.NewQuery("SELECT computerid FROM [format_table_name("player")] WHERE ckey = '[ckey]'") + query_cidcheck.Execute() + + var/lastcid = computer_id + if(query_cidcheck.NextRow()) + lastcid = query_cidcheck.item[1] + + if(computer_id != lastcid) + // Their current CID does not match what the DB says - OFF WITH THEIR HEAD + cidcheck[ckey] = computer_id + + // Disable the reconnect button to force a CID change + winset(src, "reconnectbutton", "is-disable=true") + + tokens[ckey] = cid_check_reconnect() + sleep(10) // Since browse is non-instant, and kinda async + + to_chat(src, "
you're a huge nerd. wakka wakka doodle doop nobody's ever gonna see this, the chat system shouldn't be online by this point
") + del(src) + return TRUE + else + if (!topic || !topic["token"] || !tokens[ckey] || topic["token"] != tokens[ckey]) + if (!cidcheck_spoofckeys[ckey]) + message_admins("[key_name(src)] appears to have attempted to spoof a cid randomizer check.") + cidcheck_spoofckeys[ckey] = TRUE + cidcheck[ckey] = computer_id + tokens[ckey] = cid_check_reconnect() + + sleep(10) //browse is queued, we don't want them to disconnect before getting the browse() command. + del(src) + return TRUE + // We DO have their cached CID handy - compare it, now + if(oldcid != computer_id) + // Change detected, they are randomizing + cidcheck -= ckey // To allow them to try again after removing CID randomization + + to_chat(src, "Connection Error:") + to_chat(src, "Invalid ComputerID(spoofed). Please remove the ComputerID spoofer from your BYOND installation and try again.") + + if(!cidcheck_failedckeys[ckey]) + message_admins("[key_name(src)] has been detected as using a CID randomizer. Connection rejected.") + send2irc(config.cidrandomizer_irc, "[key_name(src)] has been detected as using a CID randomizer. Connection rejected.") + cidcheck_failedckeys[ckey] = TRUE + note_randomizer_user() + + log_adminwarn("Failed Login: [key] [computer_id] [address] - CID randomizer confirmed (oldcid: [oldcid])") + + del(src) + return TRUE + else + // don't shoot, I'm innocent + if(cidcheck_failedckeys[ckey]) + // Atonement + message_admins("[key_name_admin(src)] has been allowed to connect after showing they removed their cid randomizer") + send2irc(config.cidrandomizer_irc, "[key_name(src)] has been allowed to connect after showing they removed their cid randomizer.") + cidcheck_failedckeys -= ckey + if (cidcheck_spoofckeys[ckey]) + message_admins("[key_name_admin(src)] has been allowed to connect after appearing to have attempted to spoof a cid randomizer check because it appears they aren't spoofing one this time") + cidcheck_spoofckeys -= ckey + cidcheck -= ckey + +/client/proc/note_randomizer_user() + var/const/adminckey = "CID-Error" + + // Check for notes in the last day - only 1 note per 24 hours + var/DBQuery/query_get_notes = dbcon.NewQuery("SELECT id from [format_table_name("notes")] WHERE ckey = '[ckey]' AND adminckey = '[adminckey]' AND timestamp + INTERVAL 1 DAY < NOW()") + if(!query_get_notes.Execute()) + var/err = query_get_notes.ErrorMsg() + log_game("SQL ERROR obtaining id from notes table. Error : \[[err]\]\n") + return + if(query_get_notes.NextRow()) + return + + // Only add a note if their most recent note isn't from the randomizer blocker, either + query_get_notes = dbcon.NewQuery("SELECT adminckey FROM [format_table_name("notes")] WHERE ckey = '[ckey]' ORDER BY timestamp DESC LIMIT 1") + if(!query_get_notes.Execute()) + var/err = query_get_notes.ErrorMsg() + log_game("SQL ERROR obtaining adminckey from notes table. Error : \[[err]\]\n") + return + if(query_get_notes.NextRow()) + if(query_get_notes.item[1] == adminckey) + return + add_note(ckey, "Detected as using a cid randomizer.", null, adminckey, logged = 0) + +/client/proc/cid_check_reconnect() + var/token = md5("[rand(0,9999)][world.time][rand(0,9999)][ckey][rand(0,9999)][address][rand(0,9999)][computer_id][rand(0,9999)]") + . = token + log_adminwarn("Failed Login: [key] [computer_id] [address] - CID randomizer check") + var/url = winget(src, null, "url") + //special javascript to make them reconnect under a new window. + src << browse("\ + byond://[url]?token=[token]\ + \ + ", + "border=0;titlebar=0;size=1x1") + to_chat(src, "You will be automatically taken to the game, if not, click here to be taken manually. Except you can't, since the chat window doesn't exist yet.") + +//checks if a client is afk +//3000 frames = 5 minutes +/client/proc/is_afk(duration=3000) + if(inactivity > duration) return inactivity + return 0 + +//Send resources to the client. +/client/proc/send_resources() + // Most assets are now handled through global_cache.dm + getFiles( + 'html/search.js', // Used in various non-NanoUI HTML windows for search functionality + 'html/panels.css' // Used for styling certain panels, such as in the new player panel + ) + spawn (10) //removing this spawn causes all clients to not get verbs. + //Precache the client with all other assets slowly, so as to not block other browse() calls + getFilesSlow(src, SSassets.preload, register_asset = FALSE) + +//For debugging purposes +/client/proc/list_all_languages() + for(var/L in GLOB.all_languages) + var/datum/language/lang = GLOB.all_languages[L] + var/message = "[lang.name] : [lang.type]" + if(lang.flags & RESTRICTED) + message += " (RESTRICTED)" + to_chat(world, "[message]") + +/client/proc/colour_transition(var/list/colour_to = null, var/time = 10) //Call this with no parameters to reset to default. + animate(src, color=colour_to, time=time, easing=SINE_EASING) + +/client/proc/on_varedit() + var_edited = TRUE + +///////////////// +// DARKMODE UI // +///////////////// +// IF YOU CHANGE ANYTHING IN ACTIVATE, MAKE SURE IT HAS A DEACTIVATE METHOD, -AA07 +/client/proc/activate_darkmode() + ///// BUTTONS ///// + /* Rpane */ + winset(src, "rpane.textb", "background-color=#40628a;text-color=#FFFFFF") + winset(src, "rpane.infob", "background-color=#40628a;text-color=#FFFFFF") + winset(src, "rpane.wikib", "background-color=#40628a;text-color=#FFFFFF") + winset(src, "rpane.forumb", "background-color=#40628a;text-color=#FFFFFF") + winset(src, "rpane.rulesb", "background-color=#40628a;text-color=#FFFFFF") + winset(src, "rpane.githubb", "background-color=#40628a;text-color=#FFFFFF") + /* Mainwindow */ + winset(src, "mainwindow.saybutton", "background-color=#40628a;text-color=#FFFFFF") + winset(src, "mainwindow.mebutton", "background-color=#40628a;text-color=#FFFFFF") + winset(src, "mainwindow.hotkey_toggle", "background-color=#40628a;text-color=#FFFFFF") + ///// UI ELEMENTS ///// + /* Mainwindow */ + winset(src, "mainwindow", "background-color=#272727") + winset(src, "mainwindow.mainvsplit", "background-color=#272727") + winset(src, "mainwindow.tooltip", "background-color=#272727") + /* Outputwindow */ + winset(src, "outputwindow.outputwindow", "background-color=#272727") + winset(src, "outputwindow.browseroutput", "background-color=#272727") + /* Rpane */ + winset(src, "rpane", "background-color=#272727") + winset(src, "rpane.rpane", "background-color=#272727") + winset(src, "rpane.rpanewindow", "background-color=#272727") + /* Browserwindow */ + winset(src, "browserwindow", "background-color=#272727") + winset(src, "browserwindow.browser", "background-color=#272727") + /* Infowindow */ + winset(src, "infowindow", "background-color=#272727;text-color=#FFFFFF") + winset(src, "infowindow.info", "background-color=#272727;text-color=#FFFFFF;highlight-color=#009900;tab-text-color=#FFFFFF;tab-background-color=#272727") + // NOTIFY USER + to_chat(src, "Darkmode Enabled") + +/client/proc/deactivate_darkmode() + ///// BUTTONS ///// + /* Rpane */ + winset(src, "rpane.textb", "background-color=#ffffff;text-color=#000000") + winset(src, "rpane.infob", "background-color=#ffffff;text-color=#000000") + winset(src, "rpane.wikib", "background-color=#ffffff;text-color=#000000") + winset(src, "rpane.forumb", "background-color=#ffffff;text-color=#000000") + winset(src, "rpane.rulesb", "background-color=#ffffff;text-color=#000000") + winset(src, "rpane.githubb", "background-color=#ffffff;text-color=#000000") + /* Mainwindow */ + winset(src, "mainwindow.saybutton", "background-color=#ffffff;text-color=#000000") + winset(src, "mainwindow.mebutton", "background-color=#ffffff;text-color=#000000") + winset(src, "mainwindow.hotkey_toggle", "background-color=#ffffff;text-color=#000000") + ///// UI ELEMENTS ///// + /* Mainwindow */ + winset(src, "mainwindow", "background-color=#ffffff") + winset(src, "mainwindow.mainvsplit", "background-color=#ffffff") + winset(src, "mainwindow.tooltip", "background-color=#ffffff") + /* Outputwindow */ + winset(src, "outputwindow.outputwindow", "background-color=#ffffff") + winset(src, "outputwindow.browseroutput", "background-color=#ffffff") + /* Rpane */ + winset(src, "rpane", "background-color=#ffffff") + winset(src, "rpane.rpane", "background-color=#ffffff") + winset(src, "rpane.rpanewindow", "background-color=#ffffff") + /* Browserwindow */ + winset(src, "browserwindow", "background-color=#ffffff") + winset(src, "browserwindow.browser", "background-color=#ffffff") + /* Infowindow */ + winset(src, "infowindow", "background-color=#ffffff;text-color=#000000") + winset(src, "infowindow.info", "background-color=#ffffff;text-color=#000000;highlight-color=#007700;tab-text-color=#000000;tab-background-color=#ffffff") + ///// NOTIFY USER ///// to_chat(src, "Darkmode Disabled") // what a sick fuck \ No newline at end of file From b078d356c4be91f2ef60bd890e7412c536bf0a2a Mon Sep 17 00:00:00 2001 From: AffectedArc07 Date: Sun, 27 Jan 2019 16:07:28 +0000 Subject: [PATCH 3/9] oops forgot that --- code/modules/client/client procs.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 463559e5b96..bd12082dd7e 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -373,11 +373,11 @@ if(prefs.lastchangelog != changelog_hash) //bolds the changelog button on the interface so we know there are updates. -CP if(establish_db_connection()) to_chat(src, "Changelog has changed since your last visit.") - winset(src, "rpane.changelog", "background-color=#bb7700;font-style=bold") + winset(src, "rpane.changelog", "background-color=#bb7700;font-color=#FFFFFF;font-style=bold") else if(establish_db_connection()) if(prefs.toggles & UI_DARKMODE) - winset(src, "rpane.changelog", "background-color=#bb7700;font-style=bold") // makes changelog dark if its been set + winset(src, "rpane.changelog", "background-color=#bb7700;font-color=#FFFFFF;font-style=bold") // makes changelog dark if its been set else winset(src, "rpane.changelog", "background-color=#ffffff;font-color=#000000") // makes changelog normal if it hasnt been set else From 640a30e32567346b347682a39cc4f43cda061ffc Mon Sep 17 00:00:00 2001 From: Terilia Date: Tue, 29 Jan 2019 18:47:33 +0000 Subject: [PATCH 4/9] inverted chat v1 --- goon/browserassets/css/browserOutput-dark.css | 409 ++++++++++++++++++ goon/browserassets/html/browserOutput.html | 3 +- goon/browserassets/js/browserOutput.js | 31 +- goon/code/datums/browserOutput.dm | 1 + 4 files changed, 442 insertions(+), 2 deletions(-) create mode 100644 goon/browserassets/css/browserOutput-dark.css diff --git a/goon/browserassets/css/browserOutput-dark.css b/goon/browserassets/css/browserOutput-dark.css new file mode 100644 index 00000000000..c33e0b1c76f --- /dev/null +++ b/goon/browserassets/css/browserOutput-dark.css @@ -0,0 +1,409 @@ +/***************************************** +* +* GLOBAL STYLES +* +******************************************/ +html, body { + padding: 0; + margin: 0; + height: 100%; + color: #fff; +} +body { + background: #151515; + font-family: Verdana, "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 9pt; + line-height: 1.2; + overflow-x: hidden; + overflow-y: scroll; + word-wrap: break-word; +} +h1, h2, h3, h4, h5, h6 {color: #06f; font-family: Georgia, Verdana, sans-serif;} + +img { + margin: 0; + padding: 0; + line-height: 1; +} +img.icon { + width: 16px; + height: 16px; +} +a {color: #06f;} +a:visited {color: #ff00ff;} +a.popt {text-decoration: none;} + +/***************************************** +* +* CUSTOM FONTS +* +******************************************/ +@font-face { font-family: PxPlus IBM MDA; src: url('PxPlus_IBM_MDA.ttf'); } + +/***************************************** +* +* OUTPUT NOT RELATED TO ACTUAL MESSAGES +* +******************************************/ +#loading { + position: fixed; + width: 300px; + height: 150px; + text-align: center; + left: 50%; + top: 50%; + margin: -75px 0 0 -150px; +} +#loading i {display: block; padding-bottom: 3px;} + +#messages { + font-size: 14px; + padding: 3px; + margin: 0; + word-wrap: break-word; +} +#newMessages { + position: fixed; + display: block; + bottom: 0; + right: 0; + padding: 8px; + background: #ddd; + text-decoration: none; + font-variant: small-caps; + font-size: 1.1em; + font-weight: bold; + color: #333; +} +#newMessages:hover {background: #ccc;} +#newMessages i {vertical-align: middle; padding-left: 3px;} +#ping { + position: fixed; + top: 0; + right: 40px; + width: 45px; + background: #ddd; + height: 30px; + padding: 8px 0 2px 0; +} +#ping i {display: block; text-align: center;} +#ping .ms { + display: block; + text-align: center; + font-size: 8pt; + padding-top: 2px; +} +#options { + position: fixed; + top: 0; + right: 0; +} +#options a { + background: #ddd; + height: 30px; + padding: 5px 0; + display: block; + color: #333; + text-decoration: none; + line-height: 28px; + border-top: 1px solid #b4b4b4; +} +#options a:hover {background: #ccc;} +#options .toggle { + width: 40px; + background: #ccc; + border-top: 0; + float: right; + text-align: center; +} +#options .sub {clear: both; display: none; width: 160px;} +#options .sub.scroll {overflow-y: scroll;} +#options .sub a {padding: 5px 0 5px 8px; line-height: 30px; font-size: 0.9em; clear: both;} +#options .sub span { + display: block; + line-height: 30px; + float: left; +} +#options .sub i { + display: block; + padding: 0 5px; + font-size: 1.1em; + width: 22px; + text-align: center; + line-height: 30px; + float: right; +} +#options .decreaseFont {border-top: 0;} + +/* POPUPS */ +.popup { + position: fixed; + top: 50%; + left: 50%; + background: #ddd; +} +.popup .close { + position: absolute; + background: #aaa; + top: 0; + right: 0; + color: #333; + text-decoration: none; + z-index: 2; + padding: 0 10px; + height: 30px; + line-height: 30px; +} +.popup .close:hover {background: #999;} +.popup .head { + background: #999; + color: #ddd; + padding: 0 10px; + height: 30px; + line-height: 30px; + text-transform: uppercase; + font-size: 0.9em; + font-weight: bold; + border-bottom: 2px solid green; +} +.popup input {border: 1px solid #999; background: #fff; margin: 0; padding: 5px; outline: none; color: #333;} +.popup input[type=text]:hover, .popup input[type=text]:active, .popup input[type=text]:focus {border-color: green;} +.popup input[type=submit] {padding: 5px 10px; background: #999; color: #ddd; text-transform: uppercase; font-size: 0.9em; font-weight: bold;} +.popup input[type=submit]:hover, .popup input[type=submit]:focus, .popup input[type=submit]:active {background: #aaa; cursor: pointer;} + +.changeFont {padding: 10px;} +.changeFont a {display: block; text-decoration: none; padding: 3px; color: #333;} +.changeFont a:hover {background: #ccc;} + +.highlightPopup {padding: 10px; text-align: center;} +.highlightPopup input[type=text] {display: block; width: 215px; text-align: left; margin-top: 5px;} +.highlightPopup input.highlightColor {background-color: #FFFF00;} +.highlightPopup input.highlightTermSubmit {margin-top: 5px;} + +/* ADMIN CONTEXT MENU */ +.contextMenu { + background-color: #ddd; + position: fixed; + margin: 2px; + width: 150px; +} +.contextMenu a { + display: block; + padding: 2px 5px; + text-decoration: none; + color: #333; +} + +.contextMenu a:hover { + background-color: #ccc; +} + +/* ADMIN FILTER MESSAGES MENU */ +.filterMessages {padding: 5px;} +.filterMessages div {padding: 2px 0;} +.filterMessages input {} +.filterMessages label {} + +.icon-stack {height: 1em; line-height: 1em; width: 1em; vertical-align: middle; margin-top: -2px;} + + +/***************************************** +* +* OUTPUT ACTUALLY RELATED TO MESSAGES +* +******************************************/ + +/* MOTD */ +.motd {color: #638500;} +.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 {color: #638500; text-decoration: underline;} +.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover {color: #638500;} + +/* ADD HERE FOR BOLD */ +.bold, .name, .prefix, .ooc, .looc, .adminooc, .adminlooc, .admin, .gfartooc, .gfartlooc, .gfartadmin, .mentorooc, .mentorlooc, .medal {font-weight: bold;} + +/* ADD HERE FOR ITALIC */ +.italic, .ghostdronesay.broadcast {font-style: italic;} + +/* BADGE */ +.repeatBadge { + display: inline-block; + min-width: 0.5em; + font-size: 0.7em; + padding: 0.2em 0.3em; + line-height: 1; + color: white; + text-align: center; + white-space: nowrap; + vertical-align: middle; + background-color: crimson; + border-radius: 10px; +} + +/* OUTPUT COLORS */ +.highlight {background: yellow;} +h1, h2, h3, h4, h5, h6 {color: #06f;font-family: Georgia, Verdana, sans-serif;} +em {font-style: normal; font-weight: bold;} +.motd {color: #638500; font-family: Verdana, sans-serif;} +.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 + {color: #638500; text-decoration: underline;} +.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover + {color: #638500;} +.prefix { font-weight: bold;} +.ooc { font-weight: bold;} +.looc {color: #6699CC;} +.adminobserverooc {color: #0099cc; font-weight: bold;} +.adminooc {color: #b82e00; font-weight: bold;} +.adminobserver {color: #996600; font-weight: bold;} +.admin {color: #386aff; font-weight: bold;} +.adminsay {color: #9611D4; font-weight: bold;} +.mentorhelp {color: #0077bb; font-weight: bold;} +.adminhelp {color: #aa0000; font-weight: bold;} +.playerreply {color: #8800bb; font-weight: bold;} +.name { font-weight: bold;} +.say {} +.yell { font-weight: bold;} +.siliconsay {font-family: 'Courier New', Courier, monospace;} +.deadsay {color: #cc00c6;} +.radio {color: #408010;} +.deptradio {color: #993399;} +.comradio {color: #2040ff;} +.syndradio {color: #993F40;} +.dsquadradio {color: #998599;} +.resteamradio {color: #18BC46;} +.airadio {color: #FF00FF;} +.centradio {color: #5C5C7C;} +.secradio {color: #CF0000;} +.engradio {color: #A66300;} +.medradio {color: #009190;} +.sciradio {color: #993399;} +.supradio {color: #9F8545;} +.srvradio {color: #80A000;} +.admin_channel {color: #9A04D1; font-weight: bold;} +.mentor_channel {color: #775BFF; font-weight: bold;} +.mentor_channel_admin {color: #A35CFF; font-weight: bold;} +.djradio {color: #996600;} +.binaryradio {color: #1B00FB; font-family: 'Courier New', Courier, monospace;} +.mommiradio {color: #1B00AB;} +.alert {color: #ff0000;} +h1.alert, h2.alert {color: #FFF;} +.ghostalert {color: #cc00c6; font-style: italic; font-weight: bold;} +.emote { font-style: italic;} +.selecteddna {color: #FFFFFF; background-color: #001B1B} + +.attack {color: #ff0000;} +.moderate {color: #CC0000;} +.disarm {color: #990000;} +.passive {color: #660000;} + +.warning {color: #ff0000; font-style: italic;} +.boldwarning {color: #ff0000; font-style: italic; font-weight: bold} +.danger {color: #ff0000; font-weight: bold;} +.userdanger {color: #ff0000; font-weight: bold; font-size: 120%;} +.biggerdanger {color: #ff0000; font-weight: bold; font-size: 150%;} + +.info {color: #0044DD;} +.notice {color: #0044DD;} +.bnotice {color: #0044DD; font-weight: bold;} +.boldnotice {color: #0044DD; font-weight: bold;} +.suicide {color: #ff5050; font-style: italic;} +.green {color: #03bb39;} +.announce {color: #228b22; font-weight: bold;} +.boldannounce {color: #ff0000; font-weight: bold;} +.greenannounce {color: #00ff00; font-weight: bold;} + +.alien {color: #C433C4;} +.noticealien {color: #00c000;} +.alertalien {color: #00c000; font-weight: bold;} +.terrorspider {color: #CF52FA;} + + +.sinister {color: #800080; font-weight: bold; font-style: italic;} /* /vg/ */ +.blob {color: #006221; font-weight: bold; font-style: italic;} +.confirm {color: #00af3b;} +.rose {color: #ff5050;} +.sans {font-family: 'Comic Sans MS', cursive, sans-serif;} +.wingdings {font-family: Wingdings, Webdings;} +.robot {font-family: 'PxPlus IBM MDA'; font-size: 1.15em;} +.ancient {color: #008B8B; font-stye: italic;} +.newscaster {color: #CC0000;} +.mod {color: #735638; font-weight: bold;} +.modooc {color: #184880; font-weight: bold;} +.adminmod {color: #F0AA14; font-weight: bold;} +.tajaran {color: #803B56;} +.skrell {color: #00CED1;} +.solcom {color: #8282FB;} +.soghun {color: #228B22;} +.changeling {color: #800080;} +.vox {color: #AA00AA;} +.diona {color: #804000; font-weight: bold;} +.trinary {color: #727272;} +.kidan {color: #C64C05;} +.slime {color: #0077AA;} +.drask {color: #a3d4eb; font-family: "Arial Black";} +.clown {color: #ff0000;} +.shadowling {color: #Cb2799;} +.vulpkanin {color: #B97A57;} +.abductor {color: #800080; font-style: italic;} +.mind_control {color: #A00D6F; font-size: 3; font-weight: bold; font-style: italic;} +.rough {font-family: 'Trebuchet MS', cursive, sans-serif;} +.say_quote {font-family: Georgia, Verdana, sans-serif;} +.cult {color: #800080; font-weight: bold; font-style: italic;} +.cultspeech {color: #AF0000; font-style: italic;} +.cultitalic {color: #A60000; font-style: italic;} +.cultlarge {color: #A60000; font-weight: bold; font-size: 120%;} +.narsie {color: #A60000; font-weight: bold; font-size: 300%;} +.narsiesmall {color: #A60000; font-weight: bold; font-size: 200%;} +.interface {color: #330033;} +.big {font-size: 150%;} +.reallybig {font-size: 175%;} +.greentext {color: #00FF00; font-size: 150%;} +.redtext {color: #FF0000; font-size: 150%;} +.bold {font-weight: bold;} +.center {text-align: center;} +.red {color: #FF0000;} +.skeleton {color: #C8C8C8; font-weight: bold; font-style: italic;} +.gutter {color: #7092BE; font-family: "Trebuchet MS", cursive, sans-serif;} +.orange {color: #ffa500;} +.orangei {color: #ffa500; font-style: italic;} +.orangeb {color: #ffa500; font-weight: bold;} + +.revennotice {color: #1d29C3;} +.revenboldnotice {color: #1d29C3; font-weight: bold;} +.revenbignotice {color: #1d29C3; font-weight: bold; font-size: 120%;} +.revenminor {color: #823abb} +.revenwarning {color: #760fbb; font-style: italic;} +.revendanger {color: #760fbb; font-weight: bold; font-size: 120%;} + +/* /vg/ */ +.good {color: green;} +.average {color: #FF8000;} +.bad {color: #FF0000;} +/* /vg/ Saycode Rewrite */ +.italics, .talkinto {font-style:italic;} +.whisper {font-style:italic;color:#CCCCCC;} +/* Recruiting stuff */ +.recruit {color: #5c00e6; font-weight: bold; font-style: italic;} +"} + +.memo {color: #638500; text-align: center;} +.memoedit {text-align: center; font-size: 75%;} + +.connectionClosed, .fatalError {background: red; color: white; padding: 5px;} +.connectionClosed.restored {background: green;} +.internal.boldnshit {color: blue; font-weight: bold;} + +/* HELPER CLASSES */ +.text-normal {font-weight: normal; font-style: normal;} +.hidden {display: none; visibility: hidden;} + +/* MEGAFAUNA */ +.colossus {color: #7F282A; font-size: 175%;} +.hierophant {color: #660099; font-weight: bold; font-size: 150%;} +.hierophant_warning {color: #660099; font-weight: bold; font-style: italic;} + +/* EMOJI STUFF */ +.emoji {max-height: 16px; max-width: 16px} + +/* ADMIN TICKETS */ + +.adminticket {color: #3daf21; font-weight: bold} diff --git a/goon/browserassets/html/browserOutput.html b/goon/browserassets/html/browserOutput.html index 496eac94a6c..98116a5667c 100644 --- a/goon/browserassets/html/browserOutput.html +++ b/goon/browserassets/html/browserOutput.html @@ -5,7 +5,7 @@ - + @@ -54,6 +54,7 @@ Highlight string Save chat log Clear all messages + Invert Colors diff --git a/goon/browserassets/js/browserOutput.js b/goon/browserassets/js/browserOutput.js index 06f968044fe..6c106ff2b79 100644 --- a/goon/browserassets/js/browserOutput.js +++ b/goon/browserassets/js/browserOutput.js @@ -573,8 +573,9 @@ $(function() { 'shighlightTerms': getCookie('highlightterms'), 'shighlightColor': getCookie('highlightcolor'), 'shideSpam': getCookie('hidespam'), + 'invert': getCookie('invert') }; - + if (savedConfig.sfontSize) { $messages.css('font-size', savedConfig.sfontSize); internalOutput('Loaded font size setting of: '+savedConfig.sfontSize+'', 'internal'); @@ -612,6 +613,24 @@ $(function() { opts.hideSpam = $.parseJSON(savedConfig.shideSpam); internalOutput('Loaded hide spam preference of: ' + savedConfig.shideSpam + '', 'internal'); } + if (savedConfig.invert == "on") { + $("head").append(""); + var css = $("head").children(":last"); + css.attr({ + rel: "stylesheet", + type: "text/css", + href: "./browserOutput-dark.css" + }); + + } else { + $("head").append(""); + var css = $("head").children(":last"); + css.attr({ + rel: "stylesheet", + type: "text/css", + href: "./browserOutput.css" + }); + } (function() { var dataCookie = getCookie('connData'); @@ -1012,6 +1031,16 @@ $(function() { opts.previousMessageCount = 1; }); + $('#toggleInvert').click(function(e) { + //set up color properties to iterate through + if(getCookie('invert') == "on"){ + setCookie('invert', "off", 365) + } else { + setCookie('invert', "on", 365) + } + internalOutput('Please reload for the colors to invert.', 'internal'); + }); + // Tell BYOND to give us a macro list. // I don't know why but for some retarded reason, // You need to activate hotkeymode before you can winget the macros in it. diff --git a/goon/code/datums/browserOutput.dm b/goon/code/datums/browserOutput.dm index 32a2dcd8b88..28a2690b5f6 100644 --- a/goon/code/datums/browserOutput.dm +++ b/goon/code/datums/browserOutput.dm @@ -11,6 +11,7 @@ var/list/chatResources = list( "goon/browserassets/css/fonts/PxPlus_IBM_MDA.ttf", "goon/browserassets/css/font-awesome.css", "goon/browserassets/css/browserOutput.css", + "goon/browserassets/css/browserOutput-dark.css", "goon/browserassets/json/unicode_9_annotations.json", "goon/browserassets/html/saveInstructions.html" ) From 56962c01b41815cf4d71b1cbadf5c024dc1b888e Mon Sep 17 00:00:00 2001 From: Terilia Date: Tue, 29 Jan 2019 20:06:50 +0000 Subject: [PATCH 5/9] Update browserOutput.js --- goon/browserassets/js/browserOutput.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/goon/browserassets/js/browserOutput.js b/goon/browserassets/js/browserOutput.js index 6c106ff2b79..3cdbff9ea7b 100644 --- a/goon/browserassets/js/browserOutput.js +++ b/goon/browserassets/js/browserOutput.js @@ -573,7 +573,8 @@ $(function() { 'shighlightTerms': getCookie('highlightterms'), 'shighlightColor': getCookie('highlightcolor'), 'shideSpam': getCookie('hidespam'), - 'invert': getCookie('invert') + 'invert': getCookie('invert'), + 'backlog': getCookie('backlog') }; if (savedConfig.sfontSize) { @@ -621,7 +622,6 @@ $(function() { type: "text/css", href: "./browserOutput-dark.css" }); - } else { $("head").append(""); var css = $("head").children(":last"); @@ -631,7 +631,10 @@ $(function() { href: "./browserOutput.css" }); } - + if(savedConfig.backlog != undefined){ + $messages.html(savedConfig.backlog) + setCookie('backlog', undefined, 365) + } (function() { var dataCookie = getCookie('connData'); if (dataCookie) { @@ -1032,13 +1035,15 @@ $(function() { }); $('#toggleInvert').click(function(e) { - //set up color properties to iterate through + var backlog = $messages.html() if(getCookie('invert') == "on"){ setCookie('invert', "off", 365) + setCookie('backlog', backlog, 365) } else { setCookie('invert', "on", 365) + setCookie('backlog', backlog, 365) } - internalOutput('Please reload for the colors to invert.', 'internal'); + location.reload(); }); // Tell BYOND to give us a macro list. From 0d0db48e887dca83f4cee4bb96621759d333c2b8 Mon Sep 17 00:00:00 2001 From: Terilia Date: Tue, 29 Jan 2019 20:31:37 +0000 Subject: [PATCH 6/9] Update browserOutput.js --- goon/browserassets/js/browserOutput.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/goon/browserassets/js/browserOutput.js b/goon/browserassets/js/browserOutput.js index 3cdbff9ea7b..e64c51871c1 100644 --- a/goon/browserassets/js/browserOutput.js +++ b/goon/browserassets/js/browserOutput.js @@ -631,9 +631,10 @@ $(function() { href: "./browserOutput.css" }); } - if(savedConfig.backlog != undefined){ - $messages.html(savedConfig.backlog) - setCookie('backlog', undefined, 365) + if(localStorage){ + var backlog = localStorage.getItem('backlog') + $messages.html(backlog) + localStorage.setItem('backlog', '') } (function() { var dataCookie = getCookie('connData'); @@ -1038,11 +1039,10 @@ $(function() { var backlog = $messages.html() if(getCookie('invert') == "on"){ setCookie('invert', "off", 365) - setCookie('backlog', backlog, 365) } else { setCookie('invert', "on", 365) - setCookie('backlog', backlog, 365) } + localStorage.setItem('backlog', backlog) location.reload(); }); From df93f0dac6aecadd3b305541fe33b42a8f7343b9 Mon Sep 17 00:00:00 2001 From: Terilia Date: Tue, 29 Jan 2019 20:33:33 +0000 Subject: [PATCH 7/9] Update browserOutput.js --- goon/browserassets/js/browserOutput.js | 1 - 1 file changed, 1 deletion(-) diff --git a/goon/browserassets/js/browserOutput.js b/goon/browserassets/js/browserOutput.js index e64c51871c1..fd85efd562b 100644 --- a/goon/browserassets/js/browserOutput.js +++ b/goon/browserassets/js/browserOutput.js @@ -574,7 +574,6 @@ $(function() { 'shighlightColor': getCookie('highlightcolor'), 'shideSpam': getCookie('hidespam'), 'invert': getCookie('invert'), - 'backlog': getCookie('backlog') }; if (savedConfig.sfontSize) { From 819a53b2af25489aaff0a34bc003321bb0c7c89f Mon Sep 17 00:00:00 2001 From: Terilia Date: Tue, 29 Jan 2019 20:42:54 +0000 Subject: [PATCH 8/9] -invert +darkchat --- goon/browserassets/html/browserOutput.html | 2 +- goon/browserassets/js/browserOutput.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/goon/browserassets/html/browserOutput.html b/goon/browserassets/html/browserOutput.html index 98116a5667c..cfa67167f88 100644 --- a/goon/browserassets/html/browserOutput.html +++ b/goon/browserassets/html/browserOutput.html @@ -54,7 +54,7 @@ Highlight string Save chat log Clear all messages - Invert Colors + Toggle Dark Chat diff --git a/goon/browserassets/js/browserOutput.js b/goon/browserassets/js/browserOutput.js index fd85efd562b..184420011d1 100644 --- a/goon/browserassets/js/browserOutput.js +++ b/goon/browserassets/js/browserOutput.js @@ -573,7 +573,7 @@ $(function() { 'shighlightTerms': getCookie('highlightterms'), 'shighlightColor': getCookie('highlightcolor'), 'shideSpam': getCookie('hidespam'), - 'invert': getCookie('invert'), + 'darkChat': getCookie('darkChat'), }; if (savedConfig.sfontSize) { @@ -613,7 +613,7 @@ $(function() { opts.hideSpam = $.parseJSON(savedConfig.shideSpam); internalOutput('Loaded hide spam preference of: ' + savedConfig.shideSpam + '', 'internal'); } - if (savedConfig.invert == "on") { + if (savedConfig.darkChat == "on") { $("head").append(""); var css = $("head").children(":last"); css.attr({ @@ -1034,12 +1034,12 @@ $(function() { opts.previousMessageCount = 1; }); - $('#toggleInvert').click(function(e) { + $('#toggleDarkChat').click(function(e) { var backlog = $messages.html() - if(getCookie('invert') == "on"){ - setCookie('invert', "off", 365) + if(getCookie('darkChat') == "on"){ + setCookie('darkChat', "off", 365) } else { - setCookie('invert', "on", 365) + setCookie('darkChat', "on", 365) } localStorage.setItem('backlog', backlog) location.reload(); From 82d4fb138897be43e8f9c77761d1976f4f1fd5e9 Mon Sep 17 00:00:00 2001 From: AffectedArc07 Date: Tue, 29 Jan 2019 22:10:37 +0000 Subject: [PATCH 9/9] Makes ping display readable --- goon/browserassets/css/browserOutput-dark.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/goon/browserassets/css/browserOutput-dark.css b/goon/browserassets/css/browserOutput-dark.css index c33e0b1c76f..30618df6fa5 100644 --- a/goon/browserassets/css/browserOutput-dark.css +++ b/goon/browserassets/css/browserOutput-dark.css @@ -83,6 +83,7 @@ a.popt {text-decoration: none;} right: 40px; width: 45px; background: #ddd; + color: #000; height: 30px; padding: 8px 0 2px 0; } @@ -91,6 +92,7 @@ a.popt {text-decoration: none;} display: block; text-align: center; font-size: 8pt; + color: #000; padding-top: 2px; } #options {