Merge pull request #6592 from VOREStation/vchat-rebase

VChat: Redone chat output in Vue.js
This commit is contained in:
Novacat
2020-03-01 10:51:29 -05:00
committed by GitHub
138 changed files with 15212 additions and 1745 deletions
+1 -1
View File
@@ -17,7 +17,7 @@
return
var/image/cross = image('icons/obj/storage.dmi',"bible")
msg = "<font color='blue'>\icon[cross] <b><font color=purple>PRAY: </font>[key_name(src, 1)] (<A HREF='?_src_=holder;adminmoreinfo=\ref[src]'>?</A>) (<A HREF='?_src_=holder;adminplayeropts=\ref[src]'>PP</A>) (<A HREF='?_src_=vars;Vars=\ref[src]'>VV</A>) (<A HREF='?_src_=holder;subtlemessage=\ref[src]'>SM</A>) ([admin_jump_link(src, src)]) (<A HREF='?_src_=holder;secretsadmin=check_antagonist'>CA</A>) (<A HREF='?_src_=holder;adminspawncookie=\ref[src]'>SC</a>) (<A HREF='?_src_=holder;adminsmite=\ref[src]'>SMITE</a>):</b> [msg]</font>"
msg = "<font color='blue'>[bicon(cross)] <b><font color=purple>PRAY: </font>[key_name(src, 1)] (<A HREF='?_src_=holder;adminmoreinfo=\ref[src]'>?</A>) (<A HREF='?_src_=holder;adminplayeropts=\ref[src]'>PP</A>) (<A HREF='?_src_=vars;Vars=\ref[src]'>VV</A>) (<A HREF='?_src_=holder;subtlemessage=\ref[src]'>SM</A>) ([admin_jump_link(src, src)]) (<A HREF='?_src_=holder;secretsadmin=check_antagonist'>CA</A>) (<A HREF='?_src_=holder;adminspawncookie=\ref[src]'>SC</a>) (<A HREF='?_src_=holder;adminsmite=\ref[src]'>SMITE</a>):</b> [msg]</font>"
for(var/client/C in admins)
if(R_ADMIN & C.holder.rights)
+1 -1
View File
@@ -203,7 +203,7 @@
/obj/item/device/assembly_holder/process_activation(var/obj/D, var/normal = 1, var/special = 1)
if(!D) return 0
if(!secured)
visible_message("\icon[src] *beep* *beep*", "*beep* *beep*")
visible_message("[bicon(src)] *beep* *beep*", "*beep* *beep*")
if((normal) && (a_right) && (a_left))
if(a_right != D)
a_right.pulsed(0)
+1 -1
View File
@@ -97,7 +97,7 @@
if((!secured)||(!on)||(cooldown > 0)) return 0
pulse(0)
if(!holder)
visible_message("\icon[src] *beep* *beep*")
visible_message("[bicon(src)] *beep* *beep*")
cooldown = 2
spawn(10)
process_cooldown()
+3 -3
View File
@@ -25,7 +25,7 @@
/obj/item/device/assembly/prox_sensor/toggle_secure()
secured = !secured
if(secured)
START_PROCESSING(SSobj, src)
START_PROCESSING(SSobj, src)
else
scanning = 0
timing = 0
@@ -46,11 +46,11 @@
/obj/item/device/assembly/prox_sensor/proc/sense()
var/turf/mainloc = get_turf(src)
// if(scanning && cooldown <= 0)
// mainloc.visible_message("\icon[src] *boop* *boop*", "*boop* *boop*")
// mainloc.visible_message("[bicon(src)] *boop* *boop*", "*boop* *boop*")
if((!holder && !secured)||(!scanning)||(cooldown > 0)) return 0
pulse(0)
if(!holder)
mainloc.visible_message("\icon[src] *beep* *beep*", "*beep* *beep*")
mainloc.visible_message("[bicon(src)] *beep* *beep*", "*beep* *beep*")
cooldown = 2
spawn(10)
process_cooldown()
+1 -1
View File
@@ -148,7 +148,7 @@ Code:
if(!holder)
for(var/mob/O in hearers(1, src.loc))
O.show_message(text("\icon[] *beep* *beep*", src), 3, "*beep* *beep*", 2)
O.show_message("[bicon(src)] *beep* *beep*", 3, "*beep* *beep*", 2)
return
+2 -2
View File
@@ -25,7 +25,7 @@
/obj/item/device/assembly/timer/toggle_secure()
secured = !secured
if(secured)
START_PROCESSING(SSobj, src)
START_PROCESSING(SSobj, src)
else
timing = 0
STOP_PROCESSING(SSobj, src)
@@ -37,7 +37,7 @@
if(!secured) return 0
pulse(0)
if(!holder)
visible_message("\icon[src] *beep* *beep*", "*beep* *beep*")
visible_message("[bicon(src)] *beep* *beep*", "*beep* *beep*")
cooldown = 2
spawn(10)
process_cooldown()
+2 -2
View File
@@ -12,7 +12,7 @@
recorded = msg
listening = 0
var/turf/T = get_turf(src) //otherwise it won't work in hand
T.visible_message("\icon[src] beeps, \"Activation message is '[recorded]'.\"")
T.visible_message("[bicon(src)] beeps, \"Activation message is '[recorded]'.\"")
else
if(findtext(msg, recorded))
pulse(0)
@@ -22,7 +22,7 @@
if(!holder)
listening = !listening
var/turf/T = get_turf(src)
T.visible_message("\icon[src] beeps, \"[listening ? "Now" : "No longer"] recording input.\"")
T.visible_message("[bicon(src)] beeps, \"[listening ? "Now" : "No longer"] recording input.\"")
/obj/item/device/assembly/voice/attack_self(mob/user)
+287
View File
@@ -0,0 +1,287 @@
/*
Asset cache quick users guide:
Make a datum at the bottom of this file with your assets for your thing.
The simple subsystem will most like be of use for most cases.
Then call get_asset_datum() with the type of the datum you created and store the return
Then call .send(client) on that stored return value.
You can set verify to TRUE if you want send() to sleep until the client has the assets.
*/
// Amount of time(ds) MAX to send per asset, if this get exceeded we cancel the sleeping.
// This is doubled for the first asset, then added per asset after
#define ASSET_CACHE_SEND_TIMEOUT 7
//When sending mutiple assets, how many before we give the client a quaint little sending resources message
#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8
//When passively preloading assets, how many to send at once? Too high creates noticable lag where as too low can flood the client's cache with "verify" files
#define ASSET_CACHE_PRELOAD_CONCURRENT 3
/client
var/list/cache = list() // List of all assets sent to this client by the asset cache.
var/list/completed_asset_jobs = list() // List of all completed jobs, awaiting acknowledgement.
var/list/sending = list()
var/last_asset_job = 0 // Last job done.
//This proc sends the asset to the client, but only if it needs it.
//This proc blocks(sleeps) unless verify is set to false
/proc/send_asset(var/client/client, var/asset_name, var/verify = TRUE)
if(!istype(client))
if(ismob(client))
var/mob/M = client
if(M.client)
client = M.client
else
return 0
else
return 0
if(client.cache.Find(asset_name) || client.sending.Find(asset_name))
return 0
client << browse_rsc(SSassets.cache[asset_name], asset_name)
if(!verify) // Can't access the asset cache browser, rip.
client.cache += asset_name
return 1
client.sending |= asset_name
var/job = ++client.last_asset_job
client << browse({"
<script>
window.location.href="?asset_cache_confirm_arrival=[job]"
</script>
"}, "window=asset_cache_browser")
var/t = 0
var/timeout_time = (ASSET_CACHE_SEND_TIMEOUT * client.sending.len) + ASSET_CACHE_SEND_TIMEOUT
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
sleep(1) // Lock up the caller until this is received.
t++
if(client)
client.sending -= asset_name
client.cache |= asset_name
client.completed_asset_jobs -= job
return 1
//This proc blocks(sleeps) unless verify is set to false
/proc/send_asset_list(var/client/client, var/list/asset_list, var/verify = TRUE)
if(!istype(client))
if(ismob(client))
var/mob/M = client
if(M.client)
client = M.client
else
return 0
else
return 0
var/list/unreceived = asset_list - (client.cache + client.sending)
if(!unreceived || !unreceived.len)
return 0
if(unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
to_chat(client, "Sending Resources...")
for(var/asset in unreceived)
if(asset in SSassets.cache)
client << browse_rsc(SSassets.cache[asset], asset)
if(!verify) // Can't access the asset cache browser, rip.
client.cache += unreceived
return 1
client.sending |= unreceived
var/job = ++client.last_asset_job
client << browse({"
<script>
window.location.href="?asset_cache_confirm_arrival=[job]"
</script>
"}, "window=asset_cache_browser")
var/t = 0
var/timeout_time = ASSET_CACHE_SEND_TIMEOUT * client.sending.len
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
sleep(1) // Lock up the caller until this is received.
t++
if(client)
client.sending -= unreceived
client.cache |= unreceived
client.completed_asset_jobs -= job
return 1
//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start.
//The proc calls procs that sleep for long times.
/proc/getFilesSlow(var/client/client, var/list/files, var/register_asset = TRUE)
var/concurrent_tracker = 1
for(var/file in files)
if(!client)
break
if(register_asset)
register_asset(file, files[file])
if(concurrent_tracker >= ASSET_CACHE_PRELOAD_CONCURRENT)
concurrent_tracker = 1
send_asset(client, file)
else
concurrent_tracker++
send_asset(client, file, verify = FALSE)
sleep(0) //queuing calls like this too quickly can cause issues in some client versions
//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up.
//if it's an icon or something be careful, you'll have to copy it before further use.
/proc/register_asset(var/asset_name, var/asset)
SSassets.cache[asset_name] = asset
//These datums are used to populate the asset cache, the proc "register()" does this.
//all of our asset datums, used for referring to these later
/var/global/list/asset_datums = list()
//get a assetdatum or make a new one
/proc/get_asset_datum(var/type)
if(!(type in asset_datums))
return new type()
return asset_datums[type]
/datum/asset/New()
asset_datums[type] = src
/datum/asset/proc/register()
return
/datum/asset/proc/send(client)
return
//If you don't need anything complicated.
/datum/asset/simple
var/assets = list()
var/verify = FALSE
/datum/asset/simple/register()
for(var/asset_name in assets)
register_asset(asset_name, assets[asset_name])
/datum/asset/simple/send(client)
send_asset_list(client,assets,verify)
//DEFINITIONS FOR ASSET DATUMS START HERE.
/datum/asset/simple/pda
assets = list(
"pda_atmos.png" = 'icons/pda_icons/pda_atmos.png',
"pda_back.png" = 'icons/pda_icons/pda_back.png',
"pda_bell.png" = 'icons/pda_icons/pda_bell.png',
"pda_blank.png" = 'icons/pda_icons/pda_blank.png',
"pda_boom.png" = 'icons/pda_icons/pda_boom.png',
"pda_bucket.png" = 'icons/pda_icons/pda_bucket.png',
"pda_crate.png" = 'icons/pda_icons/pda_crate.png',
"pda_cuffs.png" = 'icons/pda_icons/pda_cuffs.png',
"pda_eject.png" = 'icons/pda_icons/pda_eject.png',
"pda_exit.png" = 'icons/pda_icons/pda_exit.png',
"pda_flashlight.png" = 'icons/pda_icons/pda_flashlight.png',
"pda_honk.png" = 'icons/pda_icons/pda_honk.png',
"pda_mail.png" = 'icons/pda_icons/pda_mail.png',
"pda_medical.png" = 'icons/pda_icons/pda_medical.png',
"pda_menu.png" = 'icons/pda_icons/pda_menu.png',
"pda_mule.png" = 'icons/pda_icons/pda_mule.png',
"pda_notes.png" = 'icons/pda_icons/pda_notes.png',
"pda_power.png" = 'icons/pda_icons/pda_power.png',
"pda_rdoor.png" = 'icons/pda_icons/pda_rdoor.png',
"pda_reagent.png" = 'icons/pda_icons/pda_reagent.png',
"pda_refresh.png" = 'icons/pda_icons/pda_refresh.png',
"pda_scanner.png" = 'icons/pda_icons/pda_scanner.png',
"pda_signaler.png" = 'icons/pda_icons/pda_signaler.png',
"pda_status.png" = 'icons/pda_icons/pda_status.png'
)
/datum/asset/simple/generic
assets = list(
"search.js" = 'html/search.js',
"panels.css" = 'html/panels.css',
"loading.gif" = 'html/images/loading.gif',
"ntlogo.png" = 'html/images/ntlogo.png',
"sglogo.png" = 'html/images/sglogo.png',
"talisman.png" = 'html/images/talisman.png',
"paper_bg.png" = 'html/images/paper_bg.png',
"no_image32.png" = 'html/images/no_image32.png',
"sos_1.png" = 'icons/spideros_icons/sos_1.png',
"sos_2.png" = 'icons/spideros_icons/sos_2.png',
"sos_3.png" = 'icons/spideros_icons/sos_3.png',
"sos_4.png" = 'icons/spideros_icons/sos_4.png',
"sos_5.png" = 'icons/spideros_icons/sos_5.png',
"sos_6.png" = 'icons/spideros_icons/sos_6.png',
"sos_7.png" = 'icons/spideros_icons/sos_7.png',
"sos_8.png" = 'icons/spideros_icons/sos_8.png',
"sos_9.png" = 'icons/spideros_icons/sos_9.png',
"sos_10.png" = 'icons/spideros_icons/sos_10.png',
"sos_11.png" = 'icons/spideros_icons/sos_11.png',
"sos_12.png" = 'icons/spideros_icons/sos_12.png',
"sos_13.png" = 'icons/spideros_icons/sos_13.png',
"sos_14.png" = 'icons/spideros_icons/sos_14.png'
)
/datum/asset/simple/changelog
assets = list(
"88x31.png" = 'html/88x31.png',
"bug-minus.png" = 'html/bug-minus.png',
"cross-circle.png" = 'html/cross-circle.png',
"hard-hat-exclamation.png" = 'html/hard-hat-exclamation.png',
"image-minus.png" = 'html/image-minus.png',
"image-plus.png" = 'html/image-plus.png',
"map-pencil.png" = 'html/map-pencil.png',
"music-minus.png" = 'html/music-minus.png',
"music-plus.png" = 'html/music-plus.png',
"tick-circle.png" = 'html/tick-circle.png',
"wrench-screwdriver.png" = 'html/wrench-screwdriver.png',
"spell-check.png" = 'html/spell-check.png',
"burn-exclamation.png" = 'html/burn-exclamation.png',
"chevron.png" = 'html/chevron.png',
"chevron-expand.png" = 'html/chevron-expand.png',
"changelog.css" = 'html/changelog.css',
"changelog.js" = 'html/changelog.js',
"changelog.html" = 'html/changelog.html'
)
/datum/asset/nanoui
var/list/common = list()
var/list/common_dirs = list(
"nano/css/",
"nano/images/",
"nano/js/"
)
var/list/uncommon_dirs = list(
"nano/templates/"
)
/datum/asset/nanoui/register()
// Crawl the directories to find files.
for(var/path in common_dirs)
var/list/filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename)) != "/") // Ignore directories.
if(fexists(path + filename))
common[filename] = fcopy_rsc(path + filename)
register_asset(filename, common[filename])
for(var/path in uncommon_dirs)
var/list/filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename)) != "/") // Ignore directories.
if(fexists(path + filename))
register_asset(filename, fcopy_rsc(path + filename))
/datum/asset/nanoui/send(client, uncommon)
if(!islist(uncommon))
uncommon = list(uncommon)
send_asset_list(client, uncommon)
send_asset_list(client, common)
+2
View File
@@ -24,6 +24,8 @@
var/area = null
var/time_died_as_mouse = null //when the client last died as a mouse
var/datum/tooltip/tooltips = null
var/datum/chatOutput/chatOutput
var/chatOutputLoadedAt
var/adminhelped = 0
+44 -55
View File
@@ -34,6 +34,11 @@
#endif
if(href_list["asset_cache_confirm_arrival"])
var/job = text2num(href_list["asset_cache_confirm_arrival"])
completed_asset_jobs += job
return
//search the href for script injection
if( findtext(href,"<script",1,0) )
to_world_log("Attempted use of scripts within a topic call, by [src]")
@@ -60,8 +65,6 @@
send2adminirc(href_list["irc_msg"])
return
//Logs all hrefs
if(config && config.log_hrefs && href_logfile)
WRITE_LOG(href_logfile, "[src] (usr:[usr])</small> || [hsrc ? "[hsrc] " : ""][href]")
@@ -71,6 +74,11 @@
if("usr") hsrc = mob
if("prefs") return prefs.process_link(usr,href_list)
if("vars") return view_var_Topic(href,href_list,hsrc)
if("chat") return chatOutput.Topic(href, href_list)
switch(href_list["action"])
if("openLink")
src << link(href_list["link"])
..() //redirect to hsrc.Topic()
@@ -105,8 +113,14 @@
del(src)
return
to_chat(src, "<font color='red'>If the title screen is black, resources are still downloading. Please be patient until the title screen appears.</font>")
chatOutput = new /datum/chatOutput(src) //veechat
chatOutput.send_resources()
spawn()
chatOutput.start()
//Only show this if they are put into a new_player mob. Otherwise, "what title screen?"
if(isnewplayer(src.mob))
to_chat(src, "<font color='red'>If the title screen is black, resources are still downloading. Please be patient until the title screen appears.</font>")
GLOB.clients += src
GLOB.directory[ckey] = src
@@ -136,6 +150,8 @@
to_chat(src, "<span class='alert'>[custom_event_msg]</span>")
to_chat(src, "<br>")
if(!winexists(src, "asset_cache_browser")) // The client is using a custom skin, tell them.
to_chat(src, "<span class='warning'>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.</span>")
if(holder)
add_admin_verbs()
@@ -159,14 +175,14 @@
void.MakeGreed()
screen += void
if(prefs.lastchangelog != changelog_hash) //bolds the changelog button on the interface so we know there are updates.
if((prefs.lastchangelog != changelog_hash) && isnewplayer(src.mob)) //bolds the changelog button on the interface so we know there are updates.
to_chat(src, "<span class='info'>You have unread updates in the changelog.</span>")
winset(src, "rpane.changelog", "background-color=#eaeaea;font-style=bold")
if(config.aggressive_changelog)
src.changes()
hook_vr("client_new",list(src)) //VOREStation Code
if(config.paranoia_logging)
var/alert = FALSE //VOREStation Edit start.
if(isnum(player_age) && player_age == 0)
@@ -364,56 +380,9 @@
//send resources to the client. It's here in its own proc so we can move it around easiliy if need be
/client/proc/send_resources()
getFiles(
'html/search.js',
'html/panels.css',
'html/images/loading.gif',
'html/images/ntlogo.png',
'html/images/sglogo.png',
'html/images/talisman.png',
'html/images/paper_bg.png',
'html/images/no_image32.png',
'icons/pda_icons/pda_atmos.png',
'icons/pda_icons/pda_back.png',
'icons/pda_icons/pda_bell.png',
'icons/pda_icons/pda_blank.png',
'icons/pda_icons/pda_boom.png',
'icons/pda_icons/pda_bucket.png',
'icons/pda_icons/pda_crate.png',
'icons/pda_icons/pda_cuffs.png',
'icons/pda_icons/pda_eject.png',
'icons/pda_icons/pda_exit.png',
'icons/pda_icons/pda_flashlight.png',
'icons/pda_icons/pda_honk.png',
'icons/pda_icons/pda_mail.png',
'icons/pda_icons/pda_medical.png',
'icons/pda_icons/pda_menu.png',
'icons/pda_icons/pda_mule.png',
'icons/pda_icons/pda_notes.png',
'icons/pda_icons/pda_power.png',
'icons/pda_icons/pda_rdoor.png',
'icons/pda_icons/pda_reagent.png',
'icons/pda_icons/pda_refresh.png',
'icons/pda_icons/pda_scanner.png',
'icons/pda_icons/pda_signaler.png',
'icons/pda_icons/pda_status.png',
'icons/spideros_icons/sos_1.png',
'icons/spideros_icons/sos_2.png',
'icons/spideros_icons/sos_3.png',
'icons/spideros_icons/sos_4.png',
'icons/spideros_icons/sos_5.png',
'icons/spideros_icons/sos_6.png',
'icons/spideros_icons/sos_7.png',
'icons/spideros_icons/sos_8.png',
'icons/spideros_icons/sos_9.png',
'icons/spideros_icons/sos_10.png',
'icons/spideros_icons/sos_11.png',
'icons/spideros_icons/sos_12.png',
'icons/spideros_icons/sos_13.png',
'icons/spideros_icons/sos_14.png'
)
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)
mob/proc/MayRespawn()
return 0
@@ -449,6 +418,26 @@ client/verb/character_setup()
return FALSE
return ..()
/client/verb/reload_vchat()
set name = "Reload VChat"
set category = "OOC"
//Timing
if(src.chatOutputLoadedAt > (world.time - 10 SECONDS))
alert(src, "You can only try to reload VChat every 10 seconds at most.")
return
//Log, disable
log_debug("[key_name(src)] reloaded VChat.")
//The hard way
qdel_null(src.chatOutput)
chatOutput = new /datum/chatOutput(src) //veechat
chatOutput.send_resources()
spawn()
chatOutput.start()
//This is for getipintel.net.
//You're welcome to replace this proc with your own that does your own cool stuff.
//Just set the client's ip_reputation var and make sure it makes sense with your config settings (higher numbers are worse results)
+12 -12
View File
@@ -95,18 +95,18 @@
var/datum/effect/effect/system/spark_spread/spark_system
/obj/item/weapon/rig/examine()
to_chat(usr, "This is \icon[src][src.name].")
to_chat(usr, "This is [bicon(src)][src.name].")
to_chat(usr, "[src.desc]")
if(wearer)
for(var/obj/item/piece in list(helmet,gloves,chest,boots))
if(!piece || piece.loc != wearer)
continue
to_chat(usr, "\icon[piece] \The [piece] [piece.gender == PLURAL ? "are" : "is"] deployed.")
to_chat(usr, "[bicon(piece)] \The [piece] [piece.gender == PLURAL ? "are" : "is"] deployed.")
if(src.loc == usr)
to_chat(usr, "The access panel is [locked? "locked" : "unlocked"].")
to_chat(usr, "The maintenance panel is [open ? "open" : "closed"].")
to_chat(usr, "Hardsuit systems are [offline ? "<font color='red'>offline</font>" : "<font color='green'>online</font>"].")
to_chat(usr, "Hardsuit systems are [offline ? "<span class='warning'>offline</span>" : "<span class='notice'>online</span>"].")
to_chat(usr, "The cooling stystem is [cooling_on ? "active" : "inactive"].")
if(open)
@@ -265,7 +265,7 @@
if(!failed_to_seal)
if(!instant)
M.visible_message("<font color='blue'>[M]'s suit emits a quiet hum as it begins to adjust its seals.</font>","<font color='blue'>With a quiet hum, the suit begins running checks and adjusting components.</font>")
M.visible_message("<span class='notice'>[M]'s suit emits a quiet hum as it begins to adjust its seals.</span>","<span class='notice'>With a quiet hum, the suit begins running checks and adjusting components.</span>")
if(seal_delay && !do_after(M,seal_delay))
if(M)
to_chat(M, "<span class='warning'>You must remain still while the suit is adjusting the components.</span>")
@@ -297,16 +297,16 @@
piece.icon_state = "[suit_state][!seal_target ? "_sealed" : ""]"
switch(msg_type)
if("boots")
to_chat(M, "<font color='blue'>\The [piece] [!seal_target ? "seal around your feet" : "relax their grip on your legs"].</font>")
to_chat(M, "<span class='notice'>\The [piece] [!seal_target ? "seal around your feet" : "relax their grip on your legs"].</span>")
M.update_inv_shoes()
if("gloves")
to_chat(M, "<font color='blue'>\The [piece] [!seal_target ? "tighten around your fingers and wrists" : "become loose around your fingers"].</font>")
to_chat(M, "<span class='notice'>\The [piece] [!seal_target ? "tighten around your fingers and wrists" : "become loose around your fingers"].</span>")
M.update_inv_gloves()
if("chest")
to_chat(M, "<font color='blue'>\The [piece] [!seal_target ? "cinches tight again your chest" : "releases your chest"].</font>")
to_chat(M, "<span class='notice'>\The [piece] [!seal_target ? "cinches tight again your chest" : "releases your chest"].</span>")
M.update_inv_wear_suit()
if("helmet")
to_chat(M, "<font color='blue'>\The [piece] hisses [!seal_target ? "closed" : "open"].</font>")
to_chat(M, "<span class='notice'>\The [piece] hisses [!seal_target ? "closed" : "open"].</span>")
M.update_inv_head()
if(helmet)
helmet.update_light(wearer)
@@ -341,7 +341,7 @@
// Success!
canremove = seal_target
to_chat(M, "<font color='blue'><b>Your entire suit [canremove ? "loosens as the components relax" : "tightens around you as the components lock into place"].</b></font>")
to_chat(M, "<span class='notice'><b>Your entire suit [canremove ? "loosens as the components relax" : "tightens around you as the components lock into place"].</b></span>")
M.client.screen -= booting_L
qdel(booting_L)
booting_R.icon_state = "boot_done"
@@ -726,7 +726,7 @@
return
if(seal_delay > 0 && istype(M) && (M.back == src || M.belt == src))
M.visible_message("<font color='blue'>[M] starts putting on \the [src]...</font>", "<font color='blue'>You start putting on \the [src]...</font>")
M.visible_message("<span class='notice'>[M] starts putting on \the [src]...</span>", "<span class='notice'>You start putting on \the [src]...</span>")
if(!do_after(M,seal_delay))
if(M && (M.back == src || M.belt == src))
if(!M.unEquip(src))
@@ -735,7 +735,7 @@
return
if(istype(M) && (M.back == src || M.belt == src))
M.visible_message("<font color='blue'><b>[M] struggles into \the [src].</b></font>", "<font color='blue'><b>You struggle into \the [src].</b></font>")
M.visible_message("<span class='notice'><b>[M] struggles into \the [src].</b></span>", "<span class='notice'><b>You struggle into \the [src].</b></span>")
wearer = M
wearer.wearing_rig = src
update_icon()
@@ -785,7 +785,7 @@
holder = use_obj.loc
if(istype(holder))
if(use_obj && check_slot == use_obj)
to_chat(H, "<font color='blue'><b>Your [use_obj.name] [use_obj.gender == PLURAL ? "retract" : "retracts"] swiftly.</b></font>")
to_chat(H, "<span class='notice'><b>Your [use_obj.name] [use_obj.gender == PLURAL ? "retract" : "retracts"] swiftly.</b></span>")
use_obj.canremove = 1
holder.drop_from_inventory(use_obj)
use_obj.forceMove(get_turf(src))
@@ -115,7 +115,7 @@
last_process_worldtime = world.time
/obj/machinery/dnaforensics/proc/complete_scan()
src.visible_message("<span class='notice'>\icon[src] makes an insistent chime.</span>", 2)
src.visible_message("<span class='notice'>[bicon(src)] makes an insistent chime.</span>", 2)
update_icon()
if(bloodsamp)
var/obj/item/weapon/paper/P = new(src)
+12 -12
View File
@@ -76,7 +76,7 @@ log transactions
//display a message to the user
var/response = pick("Initiating withdraw. Have a nice day!", "CRITICAL ERROR: Activating cash chamber panic siphon.","PIN Code accepted! Emptying account balance.", "Jackpot!")
to_chat(user, "<span class='warning'>\icon[src] The [src] beeps: \"[response]\"</span>")
to_chat(user, "<span class='warning'>[bicon(src)] The [src] beeps: \"[response]\"</span>")
return 1
/obj/machinery/atm/attackby(obj/item/I as obj, mob/user as mob)
@@ -85,7 +85,7 @@ log transactions
if(istype(I, /obj/item/weapon/card))
if(emagged > 0)
//prevent inserting id into an emagged ATM
to_chat(user, "<font color='red'>\icon[src] CARD READER ERROR. This system has been compromised!</font>")
to_chat(user, "<font color='red'>[bicon(src)] CARD READER ERROR. This system has been compromised!</font>")
return
else if(istype(I,/obj/item/weapon/card/emag))
I.resolve_attackby(src, user)
@@ -234,7 +234,7 @@ log transactions
var/target_account_number = text2num(href_list["target_acc_number"])
var/transfer_purpose = href_list["purpose"]
if(charge_to_account(target_account_number, authenticated_account.owner_name, transfer_purpose, machine_id, transfer_amount))
to_chat(usr, "\icon[src]<span class='info'>Funds transfer successful.</span>")
to_chat(usr, "[bicon(src)]<span class='info'>Funds transfer successful.</span>")
authenticated_account.money -= transfer_amount
//create an entry in the account transaction log
@@ -247,10 +247,10 @@ log transactions
T.amount = "([transfer_amount])"
authenticated_account.transaction_log.Add(T)
else
to_chat(usr, "\icon[src]<span class='warning'>Funds transfer failed.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>Funds transfer failed.</span>")
else
to_chat(usr, "\icon[src]<span class='warning'>You don't have enough funds to do that!</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>You don't have enough funds to do that!</span>")
if("view_screen")
view_screen = text2num(href_list["view_screen"])
if("change_security_level")
@@ -288,11 +288,11 @@ log transactions
T.time = stationtime2text()
failed_account.transaction_log.Add(T)
else
to_chat(usr, "<font color='red'>\icon[src] Incorrect pin/account combination entered, [max_pin_attempts - number_incorrect_tries] attempts remaining.</font>")
to_chat(usr, "<font color='red'>[bicon(src)] Incorrect pin/account combination entered, [max_pin_attempts - number_incorrect_tries] attempts remaining.</font>")
previous_account_number = tried_account_num
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 1)
else
to_chat(usr, "<font color='red'>\icon[src] incorrect pin/account combination entered.</font>")
to_chat(usr, "<font color='red'>[bicon(src)] incorrect pin/account combination entered.</font>")
number_incorrect_tries = 0
else
playsound(src, 'sound/machines/twobeep.ogg', 50, 1)
@@ -308,7 +308,7 @@ log transactions
T.time = stationtime2text()
authenticated_account.transaction_log.Add(T)
to_chat(usr, "<font color='blue'>\icon[src] Access granted. Welcome user '[authenticated_account.owner_name].</font>'")
to_chat(usr, "<font color='blue'>[bicon(src)] Access granted. Welcome user '[authenticated_account.owner_name].</font>'")
previous_account_number = tried_account_num
if("e_withdrawal")
@@ -336,7 +336,7 @@ log transactions
T.time = stationtime2text()
authenticated_account.transaction_log.Add(T)
else
to_chat(usr, "\icon[src]<span class='warning'>You don't have enough funds to do that!</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>You don't have enough funds to do that!</span>")
if("withdrawal")
var/amount = max(text2num(href_list["funds_amount"]),0)
amount = round(amount, 0.01)
@@ -361,7 +361,7 @@ log transactions
T.time = stationtime2text()
authenticated_account.transaction_log.Add(T)
else
to_chat(usr, "\icon[src]<span class='warning'>You don't have enough funds to do that!</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>You don't have enough funds to do that!</span>")
if("balance_statement")
if(authenticated_account)
var/obj/item/weapon/paper/R = new(src.loc)
@@ -433,7 +433,7 @@ log transactions
if(!held_card)
//this might happen if the user had the browser window open when somebody emagged it
if(emagged > 0)
to_chat(usr, "<font color='red'>\icon[src] The ATM card reader rejected your ID because this machine has been sabotaged!</font>")
to_chat(usr, "<font color='red'>[bicon(src)] The ATM card reader rejected your ID because this machine has been sabotaged!</font>")
else
var/obj/item/I = usr.get_active_hand()
if (istype(I, /obj/item/weapon/card/id))
@@ -461,7 +461,7 @@ log transactions
if(I)
authenticated_account = attempt_account_access(I.associated_account_number)
if(authenticated_account)
to_chat(human_user, "<font color='blue'>\icon[src] Access granted. Welcome user '[authenticated_account.owner_name].</font>'")
to_chat(human_user, "<font color='blue'>[bicon(src)] Access granted. Welcome user '[authenticated_account.owner_name].</font>'")
//create a transaction log entry
var/datum/transaction/T = new()
+21 -21
View File
@@ -118,7 +118,7 @@
if(linked_account)
scan_card(I, O)
else
to_chat(usr, "\icon[src]<span class='warning'>Unable to connect to linked account.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>Unable to connect to linked account.</span>")
else if (istype(O, /obj/item/weapon/spacecash/ewallet))
var/obj/item/weapon/spacecash/ewallet/E = O
if (linked_account)
@@ -126,7 +126,7 @@
if(transaction_locked && !transaction_paid)
if(transaction_amount <= E.worth)
playsound(src, 'sound/machines/chime.ogg', 50, 1)
src.visible_message("\icon[src] \The [src] chimes.")
src.visible_message("[bicon(src)] \The [src] chimes.")
transaction_paid = 1
//transfer the money
@@ -143,11 +143,11 @@
T.time = stationtime2text()
linked_account.transaction_log.Add(T)
else
to_chat(usr, "\icon[src]<span class='warning'>\The [O] doesn't have that much money!</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>\The [O] doesn't have that much money!</span>")
else
to_chat(usr, "\icon[src]<span class='warning'>Connected account has been suspended.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>Connected account has been suspended.</span>")
else
to_chat(usr, "\icon[src]<span class='warning'>EFTPOS is not connected to an account.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>EFTPOS is not connected to an account.</span>")
else
..()
@@ -165,14 +165,14 @@
alert("That is not a valid code!")
print_reference()
else
to_chat(usr, "\icon[src]<span class='warning'>Incorrect code entered.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>Incorrect code entered.</span>")
if("change_id")
var/attempt_code = text2num(input("Re-enter the current EFTPOS access code", "Confirm EFTPOS code"))
if(attempt_code == access_code)
eftpos_name = sanitize(input("Enter a new terminal ID for this device", "Enter new EFTPOS ID"), MAX_NAME_LEN) + " EFTPOS scanner"
print_reference()
else
to_chat(usr, "\icon[src]<span class='warning'>Incorrect code entered.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>Incorrect code entered.</span>")
if("link_account")
var/attempt_account_num = input("Enter account number to pay EFTPOS charges into", "New account number") as num
var/attempt_pin = input("Enter pin code", "Account pin") as num
@@ -180,9 +180,9 @@
if(linked_account)
if(linked_account.suspended)
linked_account = null
to_chat(usr, "\icon[src]<span class='warning'>Account has been suspended.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>Account has been suspended.</span>")
else
to_chat(usr, "\icon[src]<span class='warning'>Account not found.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>Account not found.</span>")
if("trans_purpose")
var/choice = sanitize(input("Enter reason for EFTPOS transaction", "Transaction purpose"))
if(choice) transaction_purpose = choice
@@ -205,14 +205,14 @@
else if(linked_account)
transaction_locked = 1
else
to_chat(usr, "\icon[src]<span class='warning'>No account connected to send transactions to.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>No account connected to send transactions to.</span>")
if("scan_card")
if(linked_account)
var/obj/item/I = usr.get_active_hand()
if (istype(I, /obj/item/weapon/card))
scan_card(I)
else
to_chat(usr, "\icon[src]<span class='warning'>Unable to link accounts.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>Unable to link accounts.</span>")
if("reset")
//reset the access code - requires HoP/captain access
var/obj/item/I = usr.get_active_hand()
@@ -220,10 +220,10 @@
var/obj/item/weapon/card/id/C = I
if(access_cent_captain in C.access || access_hop in C.access || access_captain in C.access)
access_code = 0
to_chat(usr, "\icon[src]<span class='info'>Access code reset to 0.</span>")
to_chat(usr, "[bicon(src)]<span class='info'>Access code reset to 0.</span>")
else if (istype(I, /obj/item/weapon/card/emag))
access_code = 0
to_chat(usr, "\icon[src]<span class='info'>Access code reset to 0.</span>")
to_chat(usr, "[bicon(src)]<span class='info'>Access code reset to 0.</span>")
src.attack_self(usr)
@@ -247,7 +247,7 @@
if(!D.suspended)
if(transaction_amount <= D.money)
playsound(src, 'sound/machines/chime.ogg', 50, 1)
src.visible_message("\icon[src] \The [src] chimes.")
src.visible_message("[bicon(src)] \The [src] chimes.")
transaction_paid = 1
//transfer the money
@@ -276,25 +276,25 @@
T.time = stationtime2text()
linked_account.transaction_log.Add(T)
else
to_chat(usr, "\icon[src]<span class='warning'>You don't have that much money!</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>You don't have that much money!</span>")
else
to_chat(usr, "\icon[src]<span class='warning'>Your account has been suspended.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>Your account has been suspended.</span>")
else
to_chat(usr, "\icon[src]<span class='warning'>Unable to access account. Check security settings and try again.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>Unable to access account. Check security settings and try again.</span>")
else
to_chat(usr, "\icon[src]<span class='warning'>Connected account has been suspended.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>Connected account has been suspended.</span>")
else
to_chat(usr, "\icon[src]<span class='warning'>EFTPOS is not connected to an account.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>EFTPOS is not connected to an account.</span>")
else if (istype(I, /obj/item/weapon/card/emag))
if(transaction_locked)
if(transaction_paid)
to_chat(usr, "\icon[src]<span class='info'>You stealthily swipe \the [I] through \the [src].</span>")
to_chat(usr, "[bicon(src)]<span class='info'>You stealthily swipe \the [I] through \the [src].</span>")
transaction_locked = 0
transaction_paid = 0
else
usr.visible_message("<span class='info'>\The [usr] swipes a card through \the [src].</span>")
playsound(src, 'sound/machines/chime.ogg', 50, 1)
src.visible_message("\icon[src] \The [src] chimes.")
src.visible_message("[bicon(src)] \The [src] chimes.")
transaction_paid = 1
else
..()
+22 -22
View File
@@ -103,7 +103,7 @@
if(allowed(usr))
locked = !locked
else
to_chat(usr, "\icon[src]<span class='warning'>Insufficient access.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>Insufficient access.</span>")
if("toggle_cash_lock")
cash_locked = !cash_locked
if("link_account")
@@ -113,9 +113,9 @@
if(linked_account)
if(linked_account.suspended)
linked_account = null
src.visible_message("\icon[src]<span class='warning'>Account has been suspended.</span>")
src.visible_message("[bicon(src)]<span class='warning'>Account has been suspended.</span>")
else
to_chat(usr, "\icon[src]<span class='warning'>Account not found.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>Account not found.</span>")
if("custom_order")
var/t_purpose = sanitize(input("Enter purpose", "New purpose") as text)
if (!t_purpose || !Adjacent(usr)) return
@@ -126,7 +126,7 @@
transaction_amount += t_amount
price_list += t_amount
playsound(src, 'sound/machines/twobeep.ogg', 25)
src.visible_message("\icon[src][transaction_purpose]: [t_amount] Thaler\s.")
src.visible_message("[bicon(src)][transaction_purpose]: [t_amount] Thaler\s.")
if("set_amount")
var/item_name = locate(href_list["item"])
var/n_amount = round(input("Enter amount", "New amount") as num)
@@ -163,7 +163,7 @@
price_list.Cut()
if("reset_log")
transaction_logs.Cut()
to_chat(usr, "\icon[src]<span class='notice'>Transaction log reset.</span>")
to_chat(usr, "[bicon(src)]<span class='notice'>Transaction log reset.</span>")
updateDialog()
@@ -208,7 +208,7 @@
return 1
else
confirm_item = I
src.visible_message("\icon[src]<b>Total price:</b> [transaction_amount] Thaler\s. Swipe again to confirm.")
src.visible_message("[bicon(src)]<b>Total price:</b> [transaction_amount] Thaler\s. Swipe again to confirm.")
playsound(src, 'sound/machines/twobeep.ogg', 25)
return 0
@@ -219,14 +219,14 @@
if (cash_open)
playsound(src, 'sound/machines/buzz-sigh.ogg', 25)
to_chat(usr, "\icon[src]<span class='warning'>The cash box is open.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>The cash box is open.</span>")
return
if((item_list.len > 1 || item_list[item_list[1]] > 1) && !confirm(I))
return
if (!linked_account)
usr.visible_message("\icon[src]<span class='warning'>Unable to connect to linked account.</span>")
usr.visible_message("[bicon(src)]<span class='warning'>Unable to connect to linked account.</span>")
return
// Access account for transaction
@@ -239,13 +239,13 @@
D = attempt_account_access(I.associated_account_number, attempt_pin, 2)
if(!D)
src.visible_message("\icon[src]<span class='warning'>Unable to access account. Check security settings and try again.</span>")
src.visible_message("[bicon(src)]<span class='warning'>Unable to access account. Check security settings and try again.</span>")
else
if(D.suspended)
src.visible_message("\icon[src]<span class='warning'>Your account has been suspended.</span>")
src.visible_message("[bicon(src)]<span class='warning'>Your account has been suspended.</span>")
else
if(transaction_amount > D.money)
src.visible_message("\icon[src]<span class='warning'>Not enough funds.</span>")
src.visible_message("[bicon(src)]<span class='warning'>Not enough funds.</span>")
else
// Transfer the money
D.money -= transaction_amount
@@ -284,7 +284,7 @@
if (cash_open)
playsound(src, 'sound/machines/buzz-sigh.ogg', 25)
to_chat(usr, "\icon[src]<span class='warning'>The cash box is open.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>The cash box is open.</span>")
return
if((item_list.len > 1 || item_list[item_list[1]] > 1) && !confirm(E))
@@ -293,7 +293,7 @@
// Access account for transaction
if(check_account())
if(transaction_amount > E.worth)
src.visible_message("\icon[src]<span class='warning'>Not enough funds.</span>")
src.visible_message("[bicon(src)]<span class='warning'>Not enough funds.</span>")
else
// Transfer the money
E.worth -= transaction_amount
@@ -322,14 +322,14 @@
if (cash_open)
playsound(src, 'sound/machines/buzz-sigh.ogg', 25)
to_chat(usr, "\icon[src]<span class='warning'>The cash box is open.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>The cash box is open.</span>")
return
if((item_list.len > 1 || item_list[item_list[1]] > 1) && !confirm(SC))
return
if(transaction_amount > SC.worth)
src.visible_message("\icon[src]<span class='warning'>Not enough money.</span>")
src.visible_message("[bicon(src)]<span class='warning'>Not enough money.</span>")
else
// Insert cash into magical slot
SC.worth -= transaction_amount
@@ -351,20 +351,20 @@
/obj/machinery/cash_register/proc/scan_item_price(obj/O)
if(!istype(O)) return
if(item_list.len > 10)
src.visible_message("\icon[src]<span class='warning'>Only up to ten different items allowed per purchase.</span>")
src.visible_message("[bicon(src)]<span class='warning'>Only up to ten different items allowed per purchase.</span>")
return
if (cash_open)
playsound(src, 'sound/machines/buzz-sigh.ogg', 25)
to_chat(usr, "\icon[src]<span class='warning'>The cash box is open.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>The cash box is open.</span>")
return
// First check if item has a valid price
var/price = O.get_item_cost()
if(isnull(price))
src.visible_message("\icon[src]<span class='warning'>Unable to find item in database.</span>")
src.visible_message("[bicon(src)]<span class='warning'>Unable to find item in database.</span>")
return
// Call out item cost
src.visible_message("\icon[src]\A [O]: [price ? "[price] Thaler\s" : "free of charge"].")
src.visible_message("[bicon(src)]\A [O]: [price ? "[price] Thaler\s" : "free of charge"].")
// Note the transaction purpose for later use
if(transaction_purpose)
transaction_purpose += "<br>"
@@ -432,11 +432,11 @@
/obj/machinery/cash_register/proc/check_account()
if (!linked_account)
usr.visible_message("\icon[src]<span class='warning'>Unable to connect to linked account.</span>")
usr.visible_message("[bicon(src)]<span class='warning'>Unable to connect to linked account.</span>")
return 0
if(linked_account.suspended)
src.visible_message("\icon[src]<span class='warning'>Connected account has been suspended.</span>")
src.visible_message("[bicon(src)]<span class='warning'>Connected account has been suspended.</span>")
return 0
return 1
@@ -444,7 +444,7 @@
/obj/machinery/cash_register/proc/transaction_complete()
/// Visible confirmation
playsound(src, 'sound/machines/chime.ogg', 25)
src.visible_message("\icon[src]<span class='notice'>Transaction complete.</span>")
src.visible_message("[bicon(src)]<span class='notice'>Transaction complete.</span>")
flick("register_approve", src)
reset_memory()
updateDialog()
+17 -17
View File
@@ -100,7 +100,7 @@
if(allowed(usr))
locked = !locked
else
to_chat(usr, "\icon[src]<span class='warning'>Insufficient access.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>Insufficient access.</span>")
if("link_account")
var/attempt_account_num = input("Enter account number", "New account number") as num
var/attempt_pin = input("Enter PIN", "Account PIN") as num
@@ -108,9 +108,9 @@
if(linked_account)
if(linked_account.suspended)
linked_account = null
src.visible_message("\icon[src]<span class='warning'>Account has been suspended.</span>")
src.visible_message("[bicon(src)]<span class='warning'>Account has been suspended.</span>")
else
to_chat(usr, "\icon[src]<span class='warning'>Account not found.</span>")
to_chat(usr, "[bicon(src)]<span class='warning'>Account not found.</span>")
if("custom_order")
var/t_purpose = sanitize(input("Enter purpose", "New purpose") as text)
if (!t_purpose || !Adjacent(usr)) return
@@ -121,7 +121,7 @@
transaction_amount += t_amount
price_list += t_amount
playsound(src, 'sound/machines/twobeep.ogg', 25)
src.visible_message("\icon[src][transaction_purpose]: [t_amount] Thaler\s.")
src.visible_message("[bicon(src)][transaction_purpose]: [t_amount] Thaler\s.")
if("set_amount")
var/item_name = locate(href_list["item"])
var/n_amount = round(input("Enter amount", "New amount") as num)
@@ -158,7 +158,7 @@
price_list.Cut()
if("reset_log")
transaction_logs.Cut()
to_chat(usr, "\icon[src]<span class='notice'>Transaction log reset.</span>")
to_chat(usr, "[bicon(src)]<span class='notice'>Transaction log reset.</span>")
updateDialog()
@@ -191,7 +191,7 @@
return 1
else
confirm_item = I
src.visible_message("\icon[src]<b>Total price:</b> [transaction_amount] Thaler\s. Swipe again to confirm.")
src.visible_message("[bicon(src)]<b>Total price:</b> [transaction_amount] Thaler\s. Swipe again to confirm.")
playsound(src, 'sound/machines/twobeep.ogg', 25)
return 0
@@ -204,7 +204,7 @@
return
if (!linked_account)
usr.visible_message("\icon[src]<span class='warning'>Unable to connect to linked account.</span>")
usr.visible_message("[bicon(src)]<span class='warning'>Unable to connect to linked account.</span>")
return
// Access account for transaction
@@ -217,13 +217,13 @@
D = attempt_account_access(I.associated_account_number, attempt_pin, 2)
if(!D)
src.visible_message("\icon[src]<span class='warning'>Unable to access account. Check security settings and try again.</span>")
src.visible_message("[bicon(src)]<span class='warning'>Unable to access account. Check security settings and try again.</span>")
else
if(D.suspended)
src.visible_message("\icon[src]<span class='warning'>Your account has been suspended.</span>")
src.visible_message("[bicon(src)]<span class='warning'>Your account has been suspended.</span>")
else
if(transaction_amount > D.money)
src.visible_message("\icon[src]<span class='warning'>Not enough funds.</span>")
src.visible_message("[bicon(src)]<span class='warning'>Not enough funds.</span>")
else
// Transfer the money
D.money -= transaction_amount
@@ -266,7 +266,7 @@
// Access account for transaction
if(check_account())
if(transaction_amount > E.worth)
src.visible_message("\icon[src]<span class='warning'>Not enough funds.</span>")
src.visible_message("[bicon(src)]<span class='warning'>Not enough funds.</span>")
else
// Transfer the money
E.worth -= transaction_amount
@@ -292,16 +292,16 @@
/obj/item/device/retail_scanner/proc/scan_item_price(var/obj/O)
if(!istype(O)) return
if(item_list.len > 10)
src.visible_message("\icon[src]<span class='warning'>Only up to ten different items allowed per purchase.</span>")
src.visible_message("[bicon(src)]<span class='warning'>Only up to ten different items allowed per purchase.</span>")
return
// First check if item has a valid price
var/price = O.get_item_cost()
if(isnull(price))
src.visible_message("\icon[src]<span class='warning'>Unable to find item in database.</span>")
src.visible_message("[bicon(src)]<span class='warning'>Unable to find item in database.</span>")
return
// Call out item cost
src.visible_message("\icon[src]\A [O]: [price ? "[price] Thaler\s" : "free of charge"].")
src.visible_message("[bicon(src)]\A [O]: [price ? "[price] Thaler\s" : "free of charge"].")
// Note the transaction purpose for later use
if(transaction_purpose)
transaction_purpose += "<br>"
@@ -369,11 +369,11 @@
/obj/item/device/retail_scanner/proc/check_account()
if (!linked_account)
usr.visible_message("\icon[src]<span class='warning'>Unable to connect to linked account.</span>")
usr.visible_message("[bicon(src)]<span class='warning'>Unable to connect to linked account.</span>")
return 0
if(linked_account.suspended)
src.visible_message("\icon[src]<span class='warning'>Connected account has been suspended.</span>")
src.visible_message("[bicon(src)]<span class='warning'>Connected account has been suspended.</span>")
return 0
return 1
@@ -381,7 +381,7 @@
/obj/item/device/retail_scanner/proc/transaction_complete()
/// Visible confirmation
playsound(src, 'sound/machines/chime.ogg', 25)
src.visible_message("\icon[src]<span class='notice'>Transaction complete.</span>")
src.visible_message("[bicon(src)]<span class='notice'>Transaction complete.</span>")
flick("retail_approve", src)
reset_memory()
updateDialog()
+2 -2
View File
@@ -115,7 +115,7 @@
if (!P.message_silent)
playsound(P.loc, 'sound/machines/twobeep.ogg', 50, 1)
for (var/mob/O in hearers(3, P.loc))
if(!P.message_silent) O.show_message(text("\icon[P] *[P.ttone]*"))
if(!P.message_silent) O.show_message(text("[bicon(P)] *[P.ttone]*"))
//Search for holder of the PDA.
var/mob/living/L = null
if(P.loc && isliving(P.loc))
@@ -125,4 +125,4 @@
L = get(P, /mob/living/silicon)
if(L)
to_chat(L, "\icon[P] <b>Message from [sender] (Unknown / spam?), </b>\"[message]\" (Unable to Reply)")
to_chat(L, "[bicon(P)] <b>Message from [sender] (Unknown / spam?), </b>\"[message]\" (Unable to Reply)")
+2 -2
View File
@@ -34,7 +34,7 @@
// Quickly adds the boilerplate code to add an image and padding for the image.
/proc/desc_panel_image(var/icon_state)
return "\icon[description_icons[icon_state]][EXAMINE_PANEL_PADDING]"
return "[bicon(description_icons[icon_state])][EXAMINE_PANEL_PADDING]"
/mob/living/get_description_fluff()
if(flavor_text) //Get flavor text for the green text.
@@ -56,7 +56,7 @@
description_holders["interactions"] = A.get_description_interaction()
description_holders["name"] = "[A.name]"
description_holders["icon"] = "\icon[A]"
description_holders["icon"] = "[bicon(A)]"
description_holders["desc"] = A.desc
/mob/Stat()
+1 -1
View File
@@ -92,7 +92,7 @@
var/obj/item/weapon/reagent_containers/food/snacks/icecream/I = O
if(!I.ice_creamed)
if(product_types[dispense_flavour] > 0)
src.visible_message("\icon[src] <span class='info'>[user] scoops delicious [flavour_name] icecream into [I].</span>")
src.visible_message("[bicon(src)] <span class='info'>[user] scoops delicious [flavour_name] icecream into [I].</span>")
product_types[dispense_flavour] -= 1
I.add_ice_cream(flavour_name)
// if(beaker)
+2 -2
View File
@@ -236,7 +236,7 @@
<A href='?src=\ref[src];action=dispose'>Eject ingredients!<BR>\
"}
to_chat(user, browse("<HEAD><TITLE>Microwave Controls</TITLE></HEAD><TT>[dat]</TT>", "window=microwave"))
user << browse("<HEAD><TITLE>Microwave Controls</TITLE></HEAD><TT>[dat]</TT>", "window=microwave")
onclose(user, "microwave")
return
@@ -422,4 +422,4 @@
/obj/machinery/microwave/advanced/Initialize()
..()
reagents.maximum_volume = 1000
reagents.maximum_volume = 1000
@@ -115,7 +115,7 @@
if (!P.message_silent)
playsound(P.loc, 'sound/machines/twobeep.ogg', 50, 1)
for (var/mob/O in hearers(3, P.loc))
if(!P.message_silent) O.show_message(text("\icon[P] *[P.ttone]*"))
if(!P.message_silent) O.show_message(text("[bicon(P)] *[P.ttone]*"))
//Search for holder of the PDA.
var/mob/living/L = null
if(P.loc && isliving(P.loc))
@@ -125,7 +125,7 @@
L = get(P, /mob/living/silicon)
if(L)
to_chat(L, "\icon[P] <b>Message from [sender] (Unknown / spam?), </b>\"[message]\" (Unable to Reply)")
to_chat(L, "[bicon(P)] <b>Message from [sender] (Unknown / spam?), </b>\"[message]\" (Unable to Reply)")
/datum/gm_action/pda_spam/get_weight()
return 25 * metric.count_people_in_department(ROLE_EVERYONE)
+5 -5
View File
@@ -68,15 +68,15 @@
active = 0
if(failed_task)
failed_task = 0
visible_message("\icon[src] [src] pings unhappily, flashing a red warning light.")
visible_message("[bicon(src)] [src] pings unhappily, flashing a red warning light.")
else
visible_message("\icon[src] [src] pings happily.")
visible_message("[bicon(src)] [src] pings happily.")
if(eject_disk)
eject_disk = 0
if(loaded_disk)
loaded_disk.loc = get_turf(src)
visible_message("\icon[src] [src] beeps and spits out [loaded_disk].")
visible_message("[bicon(src)] [src] beeps and spits out [loaded_disk].")
loaded_disk = null
/obj/machinery/botany/attackby(obj/item/weapon/W as obj, mob/user as mob)
@@ -190,14 +190,14 @@
plant_controller.seeds[seed.seed.name] = seed.seed
seed.update_seed()
visible_message("\icon[src] [src] beeps and spits out [seed].")
visible_message("[bicon(src)] [src] beeps and spits out [seed].")
seed = null
if(href_list["eject_disk"])
if(!loaded_disk) return
loaded_disk.loc = get_turf(src)
visible_message("\icon[src] [src] beeps and spits out [loaded_disk].")
visible_message("[bicon(src)] [src] beeps and spits out [loaded_disk].")
loaded_disk = null
usr.set_machine(src)
@@ -416,7 +416,7 @@
if(loc)
for(var/mob/O in hearers(1, get_turf(src)))
O.show_message(text("\icon[] *beep* *beep*", src), 3, "*beep* *beep*", 2)
O.show_message("[bicon(src)] *beep* *beep*", 3, "*beep* *beep*", 2)
/obj/item/integrated_circuit/input/EPv2
name = "\improper EPv2 circuit"
@@ -43,7 +43,7 @@
var/list/nearby_things = range(0, get_turf(src))
for(var/mob/M in nearby_things)
var/obj/O = assembly ? assembly : src
to_chat(M, "<span class='notice'>\icon[O] [stuff_to_display]</span>")
to_chat(M, "<span class='notice'>[bicon(O)] [stuff_to_display]</span>")
/obj/item/integrated_circuit/output/screen/large
name = "large screen"
@@ -56,7 +56,7 @@
/obj/item/integrated_circuit/output/screen/large/do_work()
..()
var/obj/O = assembly ? loc : assembly
O.visible_message("<span class='notice'>\icon[O] [stuff_to_display]</span>")
O.visible_message("<span class='notice'>[bicon(O)] [stuff_to_display]</span>")
/obj/item/integrated_circuit/output/light
name = "light"
@@ -134,7 +134,7 @@
text = get_pin_data(IC_INPUT, 1)
if(!isnull(text))
var/obj/O = assembly ? loc : assembly
audible_message("\icon[O] \The [O.name] states, \"[text]\"")
audible_message("[bicon(O)] \The [O.name] states, \"[text]\"")
/obj/item/integrated_circuit/output/text_to_speech/advanced
name = "advanced text-to-speech circuit"
+1 -1
View File
@@ -45,7 +45,7 @@
if(ore_type) metals[ore_type] += T.resources[metal]
to_chat(user, "\icon[src] <span class='notice'>The scanner beeps and displays a readout.</span>")
to_chat(user, "[bicon(src)] <span class='notice'>The scanner beeps and displays a readout.</span>")
for(var/ore_type in metals)
var/result = "no sign"
+1 -1
View File
@@ -16,7 +16,7 @@
input = message
if(input)
log_emote(message,src) //Log before we add junk
message = "<B>[src]</B> [input]"
message = "<span class='emote'><B>[src]</B> [input]</span>"
else
return
+1 -1
View File
@@ -197,7 +197,7 @@
if(!..(user))
return
var/msg = "<span class='info'>*---------*</span>\nThis is \icon[src] \a <EM>[src]</EM>!\n[desc]\n"
var/msg = "<span class='info'>*---------*</span>\nThis is [bicon(src)] \a <EM>[src]</EM>!\n[desc]\n"
msg += "<span class='warning'>"
if(src.brainmob && src.brainmob.key)
@@ -89,7 +89,7 @@
if(!..(user))
return
var/msg = "<span class='info'>*---------*</span>\nThis is \icon[src] \a <EM>[src]</EM>!\n[desc]\n"
var/msg = "<span class='info'>*---------*</span>\nThis is [bicon(src)] \a <EM>[src]</EM>!\n[desc]\n"
msg += "<span class='warning'>"
if(src.brainmob && src.brainmob.key)
+2 -2
View File
@@ -143,8 +143,8 @@
var/mob/living/carbon/human/H = src
var/datum/gender/T = gender_datums[H.get_visible_gender()]
src.visible_message( \
"<font color='blue'>[src] examines [T.himself].</font>", \
"<font color='blue'>You check yourself for injuries.</font>" \
"<span class='notice'>[src] examines [T.himself].</span>", \
"<span class='notice'>You check yourself for injuries.</span>" \
)
for(var/obj/item/organ/external/org in H.organs)
+32 -33
View File
@@ -77,8 +77,7 @@
var/list/msg = list("<span class='info'>*---------*<br>This is ")
if(icon)
msg += "\icon[icon] " //fucking BYOND: this should stop dreamseeker crashing if we -somehow- examine somebody before their icon is generated
msg += "[bicon(src)] " //fucking BYOND: this should stop dreamseeker crashing if we -somehow- examine somebody before their icon is generated
msg += "<EM>[src.name]</EM>"
@@ -143,16 +142,16 @@
tie_msg += " Attached to it is [english_list(accessories_visible)]."
if(w_uniform.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] wearing \icon[w_uniform] [w_uniform.gender==PLURAL?"some":"a"] [(w_uniform.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [w_uniform.name]![tie_msg]</span><br>"
msg += "<span class='warning'>[T.He] [T.is] wearing [bicon(w_uniform)] [w_uniform.gender==PLURAL?"some":"a"] [(w_uniform.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [w_uniform.name]![tie_msg]</span><br>"
else
msg += "[T.He] [T.is] wearing \icon[w_uniform] \a [w_uniform].[tie_msg]<br>"
msg += "[T.He] [T.is] wearing [bicon(w_uniform)] \a [w_uniform].[tie_msg]<br>"
//head
if(head && !(skip_gear & EXAMINE_SKIPHELMET) && head.show_examine)
if(head.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] wearing \icon[head] [head.gender==PLURAL?"some":"a"] [(head.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [head.name] on [T.his] head!</span><br>"
msg += "<span class='warning'>[T.He] [T.is] wearing [bicon(head)] [head.gender==PLURAL?"some":"a"] [(head.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [head.name] on [T.his] head!</span><br>"
else
msg += "[T.He] [T.is] wearing \icon[head] \a [head] on [T.his] head.<br>"
msg += "[T.He] [T.is] wearing [bicon(head)] \a [head] on [T.his] head.<br>"
//suit/armour
if(wear_suit)
@@ -163,71 +162,71 @@
tie_msg += " Attached to it is [english_list(U.accessories)]."
if(wear_suit.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] wearing \icon[wear_suit] [wear_suit.gender==PLURAL?"some":"a"] [(wear_suit.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [wear_suit.name][tie_msg]!</span><br>"
msg += "<span class='warning'>[T.He] [T.is] wearing [bicon(wear_suit)] [wear_suit.gender==PLURAL?"some":"a"] [(wear_suit.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [wear_suit.name][tie_msg]!</span><br>"
else
msg += "[T.He] [T.is] wearing \icon[wear_suit] \a [wear_suit].[tie_msg]<br>"
msg += "[T.He] [T.is] wearing [bicon(wear_suit)] \a [wear_suit].[tie_msg]<br>"
//suit/armour storage
if(s_store && !(skip_gear & EXAMINE_SKIPSUITSTORAGE) && s_store.show_examine)
if(s_store.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] carrying \icon[s_store] [s_store.gender==PLURAL?"some":"a"] [(s_store.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [s_store.name] on [T.his] [wear_suit.name]!</span><br>"
msg += "<span class='warning'>[T.He] [T.is] carrying [bicon(s_store)] [s_store.gender==PLURAL?"some":"a"] [(s_store.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [s_store.name] on [T.his] [wear_suit.name]!</span><br>"
else
msg += "[T.He] [T.is] carrying \icon[s_store] \a [s_store] on [T.his] [wear_suit.name].<br>"
msg += "[T.He] [T.is] carrying [bicon(s_store)] \a [s_store] on [T.his] [wear_suit.name].<br>"
//back
if(back && !(skip_gear & EXAMINE_SKIPBACKPACK) && back.show_examine)
if(back.blood_DNA)
msg += "<span class='warning'>[T.He] [T.has] \icon[back] [back.gender==PLURAL?"some":"a"] [(back.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [back] on [T.his] back.</span><br>"
msg += "<span class='warning'>[T.He] [T.has] [bicon(back)] [back.gender==PLURAL?"some":"a"] [(back.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [back] on [T.his] back.</span><br>"
else
msg += "[T.He] [T.has] \icon[back] \a [back] on [T.his] back.<br>"
msg += "[T.He] [T.has] [bicon(back)] \a [back] on [T.his] back.<br>"
//left hand
if(l_hand && l_hand.show_examine)
if(l_hand.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] holding \icon[l_hand] [l_hand.gender==PLURAL?"some":"a"] [(l_hand.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [l_hand.name] in [T.his] left hand!</span><br>"
msg += "<span class='warning'>[T.He] [T.is] holding [bicon(l_hand)] [l_hand.gender==PLURAL?"some":"a"] [(l_hand.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [l_hand.name] in [T.his] left hand!</span><br>"
else
msg += "[T.He] [T.is] holding \icon[l_hand] \a [l_hand] in [T.his] left hand.<br>"
msg += "[T.He] [T.is] holding [bicon(l_hand)] \a [l_hand] in [T.his] left hand.<br>"
//right hand
if(r_hand && r_hand.show_examine)
if(r_hand.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] holding \icon[r_hand] [r_hand.gender==PLURAL?"some":"a"] [(r_hand.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [r_hand.name] in [T.his] right hand!</span><br>"
msg += "<span class='warning'>[T.He] [T.is] holding [bicon(r_hand)] [r_hand.gender==PLURAL?"some":"a"] [(r_hand.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [r_hand.name] in [T.his] right hand!</span><br>"
else
msg += "[T.He] [T.is] holding \icon[r_hand] \a [r_hand] in [T.his] right hand.<br>"
msg += "[T.He] [T.is] holding [bicon(r_hand)] \a [r_hand] in [T.his] right hand.<br>"
//gloves
if(gloves && !(skip_gear & EXAMINE_SKIPGLOVES) && gloves.show_examine)
if(gloves.blood_DNA)
msg += "<span class='warning'>[T.He] [T.has] \icon[gloves] [gloves.gender==PLURAL?"some":"a"] [(gloves.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [gloves.name] on [T.his] hands!</span><br>"
msg += "<span class='warning'>[T.He] [T.has] [bicon(gloves)] [gloves.gender==PLURAL?"some":"a"] [(gloves.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [gloves.name] on [T.his] hands!</span><br>"
else
msg += "[T.He] [T.has] \icon[gloves] \a [gloves] on [T.his] hands.<br>"
msg += "[T.He] [T.has] [bicon(gloves)] \a [gloves] on [T.his] hands.<br>"
else if(blood_DNA && !(skip_body & EXAMINE_SKIPHANDS))
msg += "<span class='warning'>[T.He] [T.has] [(hand_blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained hands!</span><br>"
//handcuffed?
if(handcuffed && handcuffed.show_examine)
if(istype(handcuffed, /obj/item/weapon/handcuffs/cable))
msg += "<span class='warning'>[T.He] [T.is] \icon[handcuffed] restrained with cable!</span><br>"
msg += "<span class='warning'>[T.He] [T.is] [bicon(handcuffed)] restrained with cable!</span><br>"
else
msg += "<span class='warning'>[T.He] [T.is] \icon[handcuffed] handcuffed!</span><br>"
msg += "<span class='warning'>[T.He] [T.is] [bicon(handcuffed)] handcuffed!</span><br>"
//buckled
if(buckled)
msg += "<span class='warning'>[T.He] [T.is] \icon[buckled] buckled to [buckled]!</span><br>"
msg += "<span class='warning'>[T.He] [T.is] [bicon(buckled)] buckled to [buckled]!</span><br>"
//belt
if(belt && !(skip_gear & EXAMINE_SKIPBELT) && belt.show_examine)
if(belt.blood_DNA)
msg += "<span class='warning'>[T.He] [T.has] \icon[belt] [belt.gender==PLURAL?"some":"a"] [(belt.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [belt.name] about [T.his] waist!</span><br>"
msg += "<span class='warning'>[T.He] [T.has] [bicon(belt)] [belt.gender==PLURAL?"some":"a"] [(belt.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [belt.name] about [T.his] waist!</span><br>"
else
msg += "[T.He] [T.has] \icon[belt] \a [belt] about [T.his] waist.<br>"
msg += "[T.He] [T.has] [bicon(belt)] \a [belt] about [T.his] waist.<br>"
//shoes
if(shoes && !(skip_gear & EXAMINE_SKIPSHOES) && shoes.show_examine)
if(shoes.blood_DNA)
msg += "<span class='warning'>[T.He] [T.is] wearing \icon[shoes] [shoes.gender==PLURAL?"some":"a"] [(shoes.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [shoes.name] on [T.his] feet!</span><br>"
msg += "<span class='warning'>[T.He] [T.is] wearing [bicon(shoes)] [shoes.gender==PLURAL?"some":"a"] [(shoes.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [shoes.name] on [T.his] feet!</span><br>"
else
msg += "[T.He] [T.is] wearing \icon[shoes] \a [shoes] on [T.his] feet.<br>"
msg += "[T.He] [T.is] wearing [bicon(shoes)] \a [shoes] on [T.his] feet.<br>"
else if(feet_blood_DNA && !(skip_body & EXAMINE_SKIPHANDS))
msg += "<span class='warning'>[T.He] [T.has] [(feet_blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained feet!</span><br>"
@@ -238,24 +237,24 @@
descriptor = "in [T.his] mouth"
if(wear_mask.blood_DNA)
msg += "<span class='warning'>[T.He] [T.has] \icon[wear_mask] [wear_mask.gender==PLURAL?"some":"a"] [(wear_mask.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [wear_mask.name] [descriptor]!</span><br>"
msg += "<span class='warning'>[T.He] [T.has] [bicon(wear_mask)] [wear_mask.gender==PLURAL?"some":"a"] [(wear_mask.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [wear_mask.name] [descriptor]!</span><br>"
else
msg += "[T.He] [T.has] \icon[wear_mask] \a [wear_mask] [descriptor].<br>"
msg += "[T.He] [T.has] [bicon(wear_mask)] \a [wear_mask] [descriptor].<br>"
//eyes
if(glasses && !(skip_gear & EXAMINE_SKIPEYEWEAR) && glasses.show_examine)
if(glasses.blood_DNA)
msg += "<span class='warning'>[T.He] [T.has] \icon[glasses] [glasses.gender==PLURAL?"some":"a"] [(glasses.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [glasses] covering [T.his] eyes!</span><br>"
msg += "<span class='warning'>[T.He] [T.has] [bicon(glasses)] [glasses.gender==PLURAL?"some":"a"] [(glasses.blood_color != SYNTH_BLOOD_COLOUR) ? "blood" : "oil"]-stained [glasses] covering [T.his] eyes!</span><br>"
else
msg += "[T.He] [T.has] \icon[glasses] \a [glasses] covering [T.his] eyes.<br>"
msg += "[T.He] [T.has] [bicon(glasses)] \a [glasses] covering [T.his] eyes.<br>"
//left ear
if(l_ear && !(skip_gear & EXAMINE_SKIPEARS) && l_ear.show_examine)
msg += "[T.He] [T.has] \icon[l_ear] \a [l_ear] on [T.his] left ear.<br>"
msg += "[T.He] [T.has] [bicon(l_ear)] \a [l_ear] on [T.his] left ear.<br>"
//right ear
if(r_ear && !(skip_gear & EXAMINE_SKIPEARS) && r_ear.show_examine)
msg += "[T.He] [T.has] \icon[r_ear] \a [r_ear] on [T.his] right ear.<br>"
msg += "[T.He] [T.has] [bicon(r_ear)] \a [r_ear] on [T.his] right ear.<br>"
//ID
if(wear_id && wear_id.show_examine)
@@ -267,9 +266,9 @@
var/obj/item/weapon/card/id/idcard = wear_id
id = idcard.registered_name
if(id && (id != real_name) && (get_dist(src, usr) <= 1) && prob(10))
msg += "<span class='warning'>[T.He] [T.is] wearing \icon[wear_id] \a [wear_id] yet something doesn't seem right...</span><br>"
msg += "<span class='warning'>[T.He] [T.is] wearing [bicon(wear_id)] \a [wear_id] yet something doesn't seem right...</span><br>"
else*/
msg += "[T.He] [T.is] wearing \icon[wear_id] \a [wear_id].<br>"
msg += "[T.He] [T.is] wearing [bicon(wear_id)] \a [wear_id].<br>"
//Jitters
if(is_jittery)
@@ -519,7 +519,7 @@
if(href_list["send"])
P.sradio.send_signal("ACTIVATE")
for(var/mob/O in hearers(1, P.loc))
O.show_message(text("\icon[] *beep* *beep*", P), 3, "*beep* *beep*", 2)
O.show_message("[bicon(P)] *beep* *beep*", 3, "*beep* *beep*", 2)
return 1
else if(href_list["freq"])
@@ -64,7 +64,7 @@
if( ishuman(AM) )
if(!stat)
var/mob/M = AM
M.visible_message("<font color='blue'>\icon[src] Squeek!</font>")
M.visible_message("<font color='blue'>[bicon(src)] Squeek!</font>")
playsound(src, 'sound/effects/mouse_squeak.ogg', 35, 1)
..()
@@ -134,7 +134,7 @@
/mob/living/simple_mob/construct/examine(mob/user)
..(user)
var/msg = "<span cass='info'>*---------*\nThis is \icon[src] \a <EM>[src]</EM>!\n"
var/msg = "<span cass='info'>*---------*\nThis is [bicon(src)] \a <EM>[src]</EM>!\n"
if (src.health < src.getMaxHealth())
msg += "<span class='warning'>"
if (src.health >= src.getMaxHealth()/2)
+1 -1
View File
@@ -83,7 +83,7 @@
var/new_name = sanitizeSafe(input(src, "Who would you like to be now?", "Communicator", src.client.prefs.real_name) as text, MAX_NAME_LEN)
if(new_name)
if(comm)
comm.visible_message("<span class='notice'>\icon[comm] [src.name] has left, and now you see [new_name].</span>")
comm.visible_message("<span class='notice'>[bicon(comm)] [src.name] has left, and now you see [new_name].</span>")
//Do a bit of logging in-case anyone tries to impersonate other characters for whatever reason.
var/msg = "[src.client.key] ([src]) has changed their communicator identity's name to [new_name]."
message_admins(msg)
+2 -2
View File
@@ -17,10 +17,10 @@
spawn() alert("You have logged in already with another key this round, please log out of this one NOW or risk being banned!")
if(matches)
if(M.client)
message_admins("<font color='red'><B>Notice: </B></font><font color='blue'><A href='?src=\ref[usr];priv_msg=\ref[src]'>[key_name_admin(src)]</A> has the same [matches] as <A href='?src=\ref[usr];priv_msg=\ref[M]'>[key_name_admin(M)]</A>.</font>", 1)
message_admins("<font color='red'><B>Notice: </B></font><font color='blue'>[key_name_admin(src)] has the same [matches] as [key_name_admin(M)].</font>", 1)
log_adminwarn("Notice: [key_name(src)] has the same [matches] as [key_name(M)].")
else
message_admins("<font color='red'><B>Notice: </B></font><font color='blue'><A href='?src=\ref[usr];priv_msg=\ref[src]'>[key_name_admin(src)]</A> has the same [matches] as [key_name_admin(M)] (no longer logged in). </font>", 1)
message_admins("<font color='red'><B>Notice: </B></font><font color='blue'>[key_name_admin(src)] has the same [matches] as [key_name_admin(M)] (no longer logged in). </font>", 1)
log_adminwarn("Notice: [key_name(src)] has the same [matches] as [key_name(M)] (no longer logged in).")
/mob/Login()
+2 -22
View File
@@ -331,9 +331,9 @@
if (flavor_text && flavor_text != "")
var/msg = replacetext(flavor_text, "\n", " ")
if(length(msg) <= 40)
return "<font color='blue'>[msg]</font>"
return "<span class='notice'>[msg]</span>"
else
return "<font color='blue'>[copytext_preserve_html(msg, 1, 37)]... <a href='byond://?src=\ref[src];flavor_more=1'>More...</font></a>"
return "<span class='notice'>[copytext_preserve_html(msg, 1, 37)]... <a href='byond://?src=\ref[src];flavor_more=1'>More...</span></a>"
/*
/mob/verb/help()
@@ -408,26 +408,6 @@
/client/verb/changes()
set name = "Changelog"
set category = "OOC"
getFiles(
'html/88x31.png',
'html/bug-minus.png',
'html/cross-circle.png',
'html/hard-hat-exclamation.png',
'html/image-minus.png',
'html/image-plus.png',
'html/map-pencil.png',
'html/music-minus.png',
'html/music-plus.png',
'html/tick-circle.png',
'html/wrench-screwdriver.png',
'html/spell-check.png',
'html/burn-exclamation.png',
'html/chevron.png',
'html/chevron-expand.png',
'html/changelog.css',
'html/changelog.js',
'html/changelog.html'
)
src << browse('html/changelog.html', "window=changes;size=675x650")
if(prefs.lastchangelog != changelog_hash)
prefs.lastchangelog = changelog_hash
+2
View File
@@ -6,6 +6,8 @@ var/obj/effect/lobby_image = new /obj/effect/lobby_image
name = "Polaris"
desc = "How are you reading this?"
screen_loc = "1,1"
icon = 'icons/misc/loading.dmi' //VOREStation Add - Loading Screen
icon_state = "loading" //VOREStation Add - Loading Screen
/obj/effect/lobby_image/Initialize()
icon = using_map.lobby_icon
+1 -1
View File
@@ -37,7 +37,7 @@
if(input)
log_subtle(message,src)
message = "<B>[src]</B> <I>[input]</I>"
message = "<span class='emote'><B>[src]</B> <I>[input]</I></span>"
else
return
+1 -1
View File
@@ -354,7 +354,7 @@ You can also set the stat of a NIF to NIF_TEMPFAIL without any issues to disable
/obj/item/device/nif/proc/notify(var/message,var/alert = 0)
if(!human || stat == NIF_TEMPFAIL) return
to_chat(human,"<b>\[\icon[src.big_icon]NIF\]</b> displays, \"<span class='[alert ? "danger" : "notice"]'>[message]</span>\"")
to_chat(human,"<b>\[[bicon(src.big_icon)]NIF\]</b> displays, \"<span class='[alert ? "danger" : "notice"]'>[message]</span>\"")
if(prob(1)) human.visible_message("<span class='notice'>\The [human] [pick(look_messages)].</span>")
if(alert)
human << bad_sound
@@ -71,12 +71,12 @@
proc/notify_into(var/message)
var/sound = nif.good_sound
to_chat(nif.human,"<b>\[\icon[nif.big_icon]NIF\]</b> <b>Soulcatcher</b> displays, \"<span class='notice'>[message]</span>\"")
to_chat(nif.human,"<b>\[[bicon(nif.big_icon)]NIF\]</b> <b>Soulcatcher</b> displays, \"<span class='notice nif'>[message]</span>\"")
nif.human << sound
for(var/brainmob in brainmobs)
var/mob/living/carbon/brain/caught_soul/CS = brainmob
to_chat(CS,"<b>\[\icon[nif.big_icon]NIF\]</b> <b>Soulcatcher</b> displays, \"<span class='notice'>[message]</span>\"")
to_chat(CS,"<b>\[[bicon(nif.big_icon)]NIF\]</b> <b>Soulcatcher</b> displays, \"<span class='notice nif'>[message]</span>\"")
brainmob << sound
proc/say_into(var/message, var/mob/living/sender, var/mob/eyeobj)
@@ -88,10 +88,10 @@
//Not AR Projecting
else
to_chat(nif.human,"<b>\[\icon[nif.big_icon]NIF\]</b> <b>[sender_name]</b> speaks, \"[message]\"")
to_chat(nif.human,"<span class='game say nif'><b>\[[bicon(nif.big_icon)]NIF\]</b> <b>[sender_name]</b> speaks, \"[message]\"</span>")
for(var/brainmob in brainmobs)
var/mob/living/carbon/brain/caught_soul/CS = brainmob
to_chat(CS,"<b>\[\icon[nif.big_icon]NIF\]</b> <b>[sender_name]</b> speaks, \"[message]\"")
to_chat(CS,"<span class='game say nif'><b>\[[bicon(nif.big_icon)]NIF\]</b> <b>[sender_name]</b> speaks, \"[message]\"</span>")
log_nsay(message,nif.human.real_name,sender)
@@ -104,10 +104,10 @@
//Not AR Projecting
else
to_chat(nif.human,"<b>\[\icon[nif.big_icon]NIF\]</b> <b>[sender_name]</b> [message]")
to_chat(nif.human,"<span class='emote nif'><b>\[[bicon(nif.big_icon)]NIF\]</b> <b>[sender_name]</b> [message]</span>")
for(var/brainmob in brainmobs)
var/mob/living/carbon/brain/caught_soul/CS = brainmob
to_chat(CS,"<b>\[\icon[nif.big_icon]NIF\]</b> <b>[sender_name]</b> [message]")
to_chat(CS,"<span class='emote nif'><b>\[[bicon(nif.big_icon)]NIF\]</b> <b>[sender_name]</b> [message]</span>")
log_nme(message,nif.human.real_name,sender)
+2 -2
View File
@@ -86,9 +86,9 @@
var/name_used = M.GetVoice()
var/rendered = null
if(speaking) //Language being used
rendered = "<span class='game say'>\icon[icon_object] <span class='name'>[name_used]</span> [speaking.format_message(text, verb)]</span>"
rendered = "<span class='game say'>[bicon(icon_object)] <span class='name'>[name_used]</span> [speaking.format_message(text, verb)]</span>"
else
rendered = "<span class='game say'>\icon[icon_object] <span class='name'>[name_used]</span> [verb], <span class='message'>\"[text]\"</span></span>"
rendered = "<span class='game say'>[bicon(icon_object)] <span class='name'>[name_used]</span> [verb], <span class='message'>\"[text]\"</span></span>"
mob.show_message(rendered, 2)
//Not supported by the internal one
@@ -91,11 +91,19 @@
. = ..(user,2)
if(.)
switch(construction_stage)
if(2) to_chat(user, "<span class='notice'>It has a metal frame loosely shaped around the stock.</span>")
if(3) to_chat(user, "<span class='notice'>It has a metal frame duct-taped to the stock.</span>")
if(4) to_chat(user, "<span class='notice'>It has a length of pipe attached to the body.</span>")
if(4) to_chat(user, "<span class='notice'>It has a length of pipe welded to the body.</span>")
if(6) to_chat(user, "<span class='notice'>It has a cable mount and capacitor jack wired to the frame.</span>")
if(7) to_chat(user, "<span class='notice'>It has a single superconducting coil threaded onto the barrel.</span>")
if(8) to_chat(user, "<span class='notice'>It has a pair of superconducting coils threaded onto the barrel.</span>")
if(9) to_chat(user, "<span class='notice'>It has three superconducting coils attached to the body, waiting to be secured.</span>")
if(2)
to_chat(user, "<span class='notice'>It has a metal frame loosely shaped around the stock.</span>")
if(3)
to_chat(user, "<span class='notice'>It has a metal frame duct-taped to the stock.</span>")
if(4)
to_chat(user, "<span class='notice'>It has a length of pipe attached to the body.</span>")
if(4)
to_chat(user, "<span class='notice'>It has a length of pipe welded to the body.</span>")
if(6)
to_chat(user, "<span class='notice'>It has a cable mount and capacitor jack wired to the frame.</span>")
if(7)
to_chat(user, "<span class='notice'>It has a single superconducting coil threaded onto the barrel.</span>")
if(8)
to_chat(user, "<span class='notice'>It has a pair of superconducting coils threaded onto the barrel.</span>")
if(9)
to_chat(user, "<span class='notice'>It has three superconducting coils attached to the body, waiting to be secured.</span>")
+1 -1
View File
@@ -118,7 +118,7 @@
var/turf/T = get_turf(container)
var/list/seen = viewers(4, T)
for(var/mob/M in seen)
M.show_message("<span class='notice'>\icon[container] [mix_message]</span>", 1)
M.show_message("<span class='notice'>[bicon(container)] [mix_message]</span>", 1)
playsound(T, reaction_sound, 80, 1)
//obtains any special data that will be provided to the reaction products
+2 -2
View File
@@ -131,12 +131,12 @@ var/global/list/obj/machinery/message_server/message_servers = list()
if(2)
if(!Console.silent)
playsound(Console.loc, 'sound/machines/twobeep.ogg', 50, 1)
Console.audible_message(text("\icon[Console] *The Requests Console beeps: 'PRIORITY Alert in [sender]'"),,5)
Console.audible_message(text("[bicon(Console)] *The Requests Console beeps: 'PRIORITY Alert in [sender]'"),,5)
Console.message_log += "<B><FONT color='red'>High Priority message from <A href='?src=\ref[Console];write=[sender]'>[sender]</A></FONT></B><BR>[authmsg]"
else
if(!Console.silent)
playsound(Console.loc, 'sound/machines/twobeep.ogg', 50, 1)
Console.audible_message(text("\icon[Console] *The Requests Console beeps: 'Message from [sender]'"),,4)
Console.audible_message(text("[bicon(Console)] *The Requests Console beeps: 'Message from [sender]'"),,4)
Console.message_log += "<B>Message from <A href='?src=\ref[Console];write=[sender]'>[sender]</A></B><BR>[authmsg]"
Console.set_light(2)
@@ -328,7 +328,7 @@
if(href_list["send"])
P.sradio.send_signal("ACTIVATE")
for(var/mob/O in hearers(1, P.loc))
O.show_message(text("\icon[] *beep* *beep*", P), 3, "*beep* *beep*", 2)
O.show_message("[bicon(P)] *beep* *beep*", 3, "*beep* *beep*", 2)
return 1
else if(href_list["freq"])
+4 -4
View File
@@ -258,14 +258,14 @@
return
if (src.active)
user.visible_message("<font color='blue'>\icon[src] [user] deactivated the shield generator.</font>", \
"<font color='blue'>\icon[src] You deactivate the shield generator.</font>", \
user.visible_message("<font color='blue'>[bicon(src)] [user] deactivated the shield generator.</font>", \
"<font color='blue'>[bicon(src)] You deactivate the shield generator.</font>", \
"You hear heavy droning fade out.")
src.shields_down()
else
if(anchored)
user.visible_message("<font color='blue'>\icon[src] [user] activated the shield generator.</font>", \
"<font color='blue'>\icon[src] You activate the shield generator.</font>", \
user.visible_message("<font color='blue'>[bicon(src)] [user] activated the shield generator.</font>", \
"<font color='blue'>[bicon(src)] You activate the shield generator.</font>", \
"You hear heavy droning.")
src.shields_up()
else
+1 -1
View File
@@ -48,7 +48,7 @@
else if(W.is_wrench())
src.anchored = !src.anchored
playsound(src, W.usesound, 75, 1)
src.visible_message("<font color='blue'>\icon[src] [src] has been [anchored ? "bolted to the floor" : "unbolted from the floor"] by [user].</font>")
src.visible_message("<font color='blue'>[bicon(src)] [src] has been [anchored ? "bolted to the floor" : "unbolted from the floor"] by [user].</font>")
if(anchored)
spawn(0)
+3 -3
View File
@@ -67,7 +67,7 @@
else if(W.is_wrench())
src.anchored = !src.anchored
playsound(src, W.usesound, 75, 1)
src.visible_message("<font color='blue'>\icon[src] [src] has been [anchored?"bolted to the floor":"unbolted from the floor"] by [user].</font>")
src.visible_message("<font color='blue'>[bicon(src)] [src] has been [anchored?"bolted to the floor":"unbolted from the floor"] by [user].</font>")
if(active)
toggle()
@@ -248,7 +248,7 @@
covered_turfs = null
for(var/mob/M in view(5,src))
to_chat(M, "\icon[src] You hear heavy droning start up.")
to_chat(M, "[bicon(src)] You hear heavy droning start up.")
for(var/obj/effect/energy_field/E in field) // Update the icons here to ensure all the shields have been made already.
E.update_icon()
else
@@ -258,7 +258,7 @@
qdel(D)
for(var/mob/M in view(5,src))
to_chat(M, "\icon[src] You hear heavy droning fade out.")
to_chat(M, "[bicon(src)] You hear heavy droning fade out.")
/obj/machinery/shield_gen/update_icon()
if(stat & BROKEN)
+110
View File
@@ -0,0 +1,110 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="semantic.min.css" />
<link rel="stylesheet" type="text/css" href="vchat-font-embedded.css" />
<link rel="stylesheet" type="text/css" href="ss13styles.css" />
</head>
<body>
<div class="ui top fixed pointing menu">
<div class="item">
Main
</div>
<div class="item">
OOC
<div class="ui top right attached red label">15</div>
</div>
<div class="right menu">
<div class="item" style="cursor: pointer;" title="New Tab"><i class="icon-folder-add"></i></div>
<div class="item" style="cursor: pointer;" title="Pause Autoscroll">
<i class="icon-pause-outline" :class="{ blinkwarn: paused }"></i>
</div>
<div class="item" style="cursor: pointer;" title="Edit Mode">
<i class="icon-cog-outline" :class="{ blinkwarn: editing }"></i>
</div>
<div class="item" style="padding-left: 0px !important;"><span class="ui circular label" title="VChat Latency (Not exactly network latency)" :class="ping_classes">{{latency}}ms</span></div>
</div>
</div>
<div id="contentbox">
<div class="ui segment">
<span class='game say'><b>Test Person</b> says, "Testing say message."</span><br>
<span class='notice'>Testing notice message.</span><br>
<span class='danger'>Testing danger message.</span><br>
<span class='secradio'>[Security] <b>Secu Person</b> says, "Testing radio message."</span><br>
<span class='ooc'><span class='everyone'>Testing OOC message.</span></span><br>
<span class='ooc'><span class='looc'>Testing LOOC message.</span></span><br>
<span class='admin_channel'>Testing asay message.</span><br>
<span class='game say'><b>Test Person</b> says, "Testing say message 2."</span><br>
<span class='notice'>Testing notice message 2.</span><br>
<span class='danger'>Testing danger message 2.</span><br>
<span class='secradio'>[Security] <b>Secu Person</b> says, "Testing radio message 2".</span><br>
<span class='ooc'><span class='everyone'>Testing OOC message 2.</span></span><br>
<span class='ooc'><span class='looc'>Testing LOOC message 2.</span></span><br>
<span class='admin_channel'>Testing asay message 2.</span><br>
<span class='game say'><b>Test Person</b> says, "Testing say message 3."</span><br>
<span class='notice'>Testing notice message 3.</span><br>
<span class='danger'>Testing danger message 3.</span><br>
<span class='secradio'>[Security] <b>Secu Person</b> says, "Testing radio message 3".</span><br>
<span class='ooc'><span class='everyone'>Testing OOC message 3.</span></span><br>
<span class='ooc'><span class='looc'>Testing LOOC message 3.</span></span><br>
<span class='admin_channel'>Testing asay message 3.</span><br>
<span class='game say'><b>Test Person</b> says, "Testing say message 4."</span><br>
<span class='notice'>Testing notice message 4.</span><br>
<span class='danger'>Testing danger message 4.</span><br>
<span class='secradio'>[Security] <b>Secu Person</b> says, "Testing radio message 4".</span><br>
<span class='ooc'><span class='everyone'>Testing OOC message 4.</span></span><br>
<span class='ooc'><span class='looc'>Testing LOOC message 4.</span></span><br>
<span class='admin_channel'>Testing asay message 4.</span><br>
<span class='game say'><b>Test Person</b> says, "Testing say message 5."</span><br>
<span class='notice'>Testing notice message 5.</span><br>
<span class='danger'>Testing danger message 5.</span><br>
<span class='secradio'>[Security] <b>Secu Person</b> says, "Testing radio message 5".</span><br>
<span class='ooc'><span class='everyone'>Testing OOC message 5.</span></span><br>
<span class='ooc'><span class='looc'>Testing LOOC message 5.</span></span><br>
<span class='admin_channel'>Testing asay message 5.</span><br>
</div>
<div class="ui segment inverted">
<span class='game say'><b>Test Person</b> says, "Testing say message."</span><br>
<span class='notice'>Testing notice message.</span><br>
<span class='danger'>Testing danger message.</span><br>
<span class='secradio'>[Security] <b>Secu Person</b> says, "Testing radio message."</span><br>
<span class='ooc'><span class='everyone'>Testing OOC message.</span></span><br>
<span class='ooc'><span class='looc'>Testing LOOC message.</span></span><br>
<span class='admin_channel'>Testing asay message.</span><br>
<span class='game say'><b>Test Person</b> says, "Testing say message 2."</span><br>
<span class='notice'>Testing notice message 2.</span><br>
<span class='danger'>Testing danger message 2.</span><br>
<span class='secradio'>[Security] <b>Secu Person</b> says, "Testing radio message 2".</span><br>
<span class='ooc'><span class='everyone'>Testing OOC message 2.</span></span><br>
<span class='ooc'><span class='looc'>Testing LOOC message 2.</span></span><br>
<span class='admin_channel'>Testing asay message 2.</span><br>
<span class='game say'><b>Test Person</b> says, "Testing say message 3."</span><br>
<span class='notice'>Testing notice message 3.</span><br>
<span class='danger'>Testing danger message 3.</span><br>
<span class='secradio'>[Security] <b>Secu Person</b> says, "Testing radio message 3".</span><br>
<span class='ooc'><span class='everyone'>Testing OOC message 3.</span></span><br>
<span class='ooc'><span class='looc'>Testing LOOC message 3.</span></span><br>
<span class='admin_channel'>Testing asay message 3.</span><br>
<span class='game say'><b>Test Person</b> says, "Testing say message 4."</span><br>
<span class='notice'>Testing notice message 4.</span><br>
<span class='danger'>Testing danger message 4.</span><br>
<span class='secradio'>[Security] <b>Secu Person</b> says, "Testing radio message 4".</span><br>
<span class='ooc'><span class='everyone'>Testing OOC message 4.</span></span><br>
<span class='ooc'><span class='looc'>Testing LOOC message 4.</span></span><br>
<span class='admin_channel'>Testing asay message 4.</span><br>
<span class='game say'><b>Test Person</b> says, "Testing say message 5."</span><br>
<span class='notice'>Testing notice message 5.</span><br>
<span class='danger'>Testing danger message 5.</span><br>
<span class='secradio'>[Security] <b>Secu Person</b> says, "Testing radio message 5".</span><br>
<span class='ooc'><span class='everyone'>Testing OOC message 5.</span></span><br>
<span class='ooc'><span class='looc'>Testing LOOC message 5.</span></span><br>
<span class='admin_channel'>Testing asay message 5.</span><br>
</div>
</div>
</body>
</html>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+232
View File
@@ -0,0 +1,232 @@
/* VChat Styles */
#contentbox {
margin-top: 3rem; /* Make room for the fixed top menu */
overflow-wrap: break-word;
word-wrap: break-word; /* IE, blah */
}
.menu, .item {
padding-top: 0.2em !important;
padding-bottom: 0.2em !important;
}
.ui.menu .item > .label:not(.floating) {
margin-left: 0;
padding-bottom: 0;
padding-top: 0;
text-align: center;
font-size: 10px;
}
#app > .menu {
overflow-x: auto;
overflow-y: hidden;
}
.item {
cursor: pointer;
}
.icon-left-open-outline:hover, .icon-right-open-outline:hover, .icon-cancel-circled-outline:hover {
color: red;
}
body.inverted {
background-color: #111111;
}
.blinkwarn {
color: #FF0000;
animation: blink-animation 1s steps(5, start) infinite;
}
@keyframes blink-animation {
to {
visibility: hidden;
}
}
/* The chat message display classes */
#messagebox div { display: none; } /* Hide messages by default */
#messagebox.vc_showall div { display: block; } /* Unless we have vc_showall */
#messagebox.vc_localchat .vc_localchat { display: block; }
#messagebox.vc_radio .vc_radio { display: block; }
#messagebox.vc_warnings .vc_warnings { display: block; }
#messagebox.vc_info .vc_info { display: block; }
#messagebox.vc_deadchat .vc_deadchat { display: block; }
#messagebox.vc_globalooc .vc_globalooc { display: block; }
#messagebox.vc_adminpm .vc_adminpm { display: block; }
#messagebox.vc_adminchat .vc_adminchat { display: block; }
#messagebox.vc_modchat .vc_modchat { display: block; }
#messagebox.vc_eventchat .vc_eventchat { display: block; }
#messagebox.vc_system .vc_system { display: block; }
#messagebox.vc_nif .vc_nif { display: block; } /* VOREStation Add */
/* SS13 Styles */
#messagebox {font-family: Verdana, sans-serif;}
#messagebox h1, #messagebox h2, #messagebox h3, #messagebox h4, #messagebox h5, #messagebox h6 {color: #0000ff; font-family: Georgia, Verdana, sans-serif;}
#messagebox 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;}
.log_message {color: #386AFF; font-weight: bold;}
/*.inverted .message {color: #386AFF; font-weight: bold;}*/
/* OOC */
.ooc {font-weight: bold;}
.ooc img.text_tag {width: 32px; height: 10px;}
.ooc .everyone {color: #002eb8;}
.inverted .ooc .everyone {color: #004ed8;} /* Dark mode */
.ooc .looc {color: #3A9696;}
.ooc .elevated {color: #2e78d9;}
.ooc .moderator {color: #184880;}
.ooc .developer {color: #1b521f;}
.ooc .admin {color: #b82e00;}
.ooc .event_manager {color: #660033;}
.ooc .aooc {color: #960018;}
/* Admin: Private Messages */
.pm .howto {color: #ff0000; font-weight: bold; font-size: 200%;}
.pm .in {color: #ff0000;}
.pm .out {color: #ff0000;}
.pm .other {color: #0000ff;}
/* Admin: Channels */
.mod_channel {color: #735638; font-weight: bold;}
.mod_channel .admin {color: #b82e00; font-weight: bold;}
.admin_channel {color: #9611D4; font-weight: bold;}
.event_channel {color: #cc3399; font-weight: bold;}
/* Radio: Misc */
.deadsay {color: #530FAD;}
.inverted .deadsay {color: #732FCD;} /* Dark mode */
.radio {color: #008000;}
.deptradio {color: #ff00ff;} /* when all other department colors fail */
.newscaster {color: #750000;}
/* Radio Channels */
.comradio {color: #193A7A;}
.inverted .comradio {color: #395A9A;} /* Dark mode */
.syndradio {color: #6D3F40;}
.centradio {color: #5C5C8A;}
.airadio {color: #FF00FF;}
.entradio {color: #339966;}
.secradio {color: #A30000;}
.engradio {color: #A66300;}
.medradio {color: #008160;}
.sciradio {color: #993399;}
.supradio {color: #5F4519;}
.srvradio {color: #6eaa2c;}
.expradio {color: #555555;}
/* Miscellaneous */
.name {font-weight: bold;}
.say {}
.emote {}
.alert {color: #ff0000;}
h1.alert, h2.alert {color: #000000;}
.nif {} /* VOREStation Add */
/* Game Messages */
.attack {color: #ff0000;}
.moderate {color: #CC0000;}
.disarm {color: #990000;}
.passive {color: #660000;}
.critical {color: #ff0000; font-weight: bold; font-size: 150%;}
.danger {color: #ff0000; font-weight: bold;}
.warning {color: #ff0000; font-style: italic;}
.rose {color: #ff5050;}
.info {color: #0000CC;}
.inverted .info {color: #6060c9;} /* Dark mode */
.notice {color: #000099;}
.inverted .notice {color: #6060c9;} /* Dark mode */
.alium {color: #00ff00;}
.cult {color: #800080; font-weight: bold; font-style: italic;}
.reflex_shoot {color: #000099; font-style: italic;}
/* Languages */
.alien {color: #543354;}
.tajaran {color: #803B56;}
.tajaran_signlang {color: #941C1C;}
.akhani {color: #AC398C;}
.skrell {color: #00B0B3;}
.skrellfar {color: #70FCFF;}
.soghun {color: #228B22;}
.solcom {color: #22228B;}
.changeling {color: #800080;}
.sergal {color: #0077FF; font-family: "Comic Sans MS";}
.birdsongc {color: #CC9900;}
.vulpkanin {color: #B97A57;}
.enochian {color: #848A33; letter-spacing:-1pt; word-spacing:4pt; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;}
.daemon {color: #5E339E; letter-spacing:-1pt; word-spacing:0pt; font-family: "Courier New", Courier, monospace;}
.bug {color: #9e9e39;}
.vox {color: #AA00AA;}
.zaddat {color: #941C1C;}
.rough {font-family: "Trebuchet MS", cursive, sans-serif;}
.say_quote {font-family: Georgia, Verdana, sans-serif;}
.terminus {font-family: "Times New Roman", Times, serif, sans-serif}
.interface {color: #330033;}
/*BIG IMG.icon {width: 32px; height: 32px;}*/
img.icon {vertical-align: middle; max-height: 1em;}
img.icon.bigicon {max-height: 32px;}
/* Zoom levels */
.zoom_normal {
font-size: 0.9em;
line-height: 1.35;
}
.zoom_more {
font-size: 1.2em;
line-height: 1.4;
}
.zoom_less {
font-size: 0.8em;
line-height: 1.2;
}
/* Debug Logs */
.debug_error {color:#FF0000; font-weight:bold}
.debug_warning {color:#FF0000;}
.debug_info {}
.debug_debug {color:#0000FF;}
.debug_trace {color:#888888;}
/* Log animations */
.msgsanim-enter-active {
transition: opacity 0.5s, transform 0.5s;
}
.msgsanim-enter {
opacity: 0;
transform: translateX(15px);
}
/* Dog mode */
.woof {
background-color: rgba(255,255,255,0) !important;
background-image: url('dog.gif') !important;
background-size: cover !important;
transition: background-color 15s;
}
.woof div, .woof span {
background-color: rgba(0,0,0,0) !important;
transition: background-color 15s;
}
File diff suppressed because one or more lines are too long
+165
View File
@@ -0,0 +1,165 @@
<!DOCTYPE html>
<html debug="true">
<head>
<title>VChat</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<!-- Styles -->
<link rel="stylesheet" type="text/css" href="semantic.min.css" />
<link rel="stylesheet" type="text/css" href="vchat-font-embedded.css" />
<link rel="stylesheet" type="text/css" href="ss13styles.css" />
<!-- Important scripts -->
<script type="text/javascript" src="polyfills.js"></script>
<script type="text/javascript" src="vue.min.js"></script>
<script type="text/javascript" src="vchat.js"></script>
</head>
<body>
<div id="loader">
<p>VChat is still loading. If you see this for a very long time, try the OOC 'Reload VChat' verb, or reconnecting.</p>
<p>Sometimes if you're still caching resources, it will take longer than usual.</p>
</div>
<div id="app" @mouseup="on_mouseup" style="display: none;">
<!-- Top menu -->
<div class="ui top fixed pointing menu" :class="{ inverted: inverted }">
<div v-for="(tab,index) in tabs" class="item" :class="{ active: tab.active, inverted: inverted }" @click="switchtab(tab)" @click.ctrl="editmode">
<i v-show="editing && !tab.immutable && index >= 2" class="icon-left-open-outline" @click.stop.prevent="movetab(tab,-1)" title="Move tab left"></i>
{{tab.name}}
<i v-show="editing && !tab.immutable" class="icon-cancel-circled-outline" @click.stop.prevent="deltab(tab)" title="Delete tab"></i>
<i v-show="editing && !tab.immutable && index != tabs.length-1" class="icon-right-open-outline" @click.stop.prevent="movetab(tab,1)" title="Move tab right"></i>
<div v-if="tab_unread_count(tab) > 0" class="ui top right attached red label">{{tab_unread_count(tab)}}</div>
</div>
<div class="right menu">
<div class="item" :class="{ inverted: inverted }" @click="newtab" title="New Tab"><i class="icon-folder-add"></i></div>
<div class="item" :class="{ inverted: inverted }" @click="pause" title="Pause Autoscroll">
<i class="icon-pause-outline" :class="{ blinkwarn: paused }"></i>
</div>
<div class="item" :class="{ inverted: inverted }" @click="editmode" title="Edit Mode">
<i class="icon-cog-outline" :class="{ blinkwarn: editing }"></i>
</div>
<div class="item"><span class="ui circular label" title="VChat Latency (Not exactly network latency)" :class="ping_classes">{{latency}}ms</span></div>
</div>
</div>
<!-- Editor box -->
<div id="contentbox">
<div v-show="editing" id="editbox" class="ui segment" :class="{ inverted: inverted }">
<div class="ui internally celled grid">
<div class="row">
<div class="sixteen wide column">
<div class="ui center aligned header" :class="{ inverted: inverted }">
<h2>VChat Settings</h2>
</div>
<div style="text-align: center;"><a href="#" @click="editmode">Close Settings</a></div>
</div>
</div>
<div class="row">
<div class="eight wide column">
<h3>'{{active_tab.name}}' Tab Settings</h3>
<span v-show="active_tab.immutable">This tab is immutable. You cannot make changes.</span>
<div v-show="!active_tab.immutable">
<a href="#" @click="renametab">Rename Tab</a> - <a href="#" @click="deltab">Delete Tab</a>
<h5>Messages to display:</h5>
<div class="ui form">
<div class="grouped fields">
<div class="field" v-for="type in type_table">
<div v-show="!type.admin || is_admin" class="ui slider checkbox" :class="{ inverted: inverted, disabled: type.required || active_tab.immutable, checked: type.required || active_tab.immutable }">
<input type="checkbox" id="type.becomes" :value="type.becomes" v-model="active_tab.classes" :disabled="type.required || active_tab.immutable" :checked="type.required || active_tab.immutable"><label :for="type.becomes">{{type.pretty}}</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="eight wide column">
<h3>Global Settings</h3>
<div class="ui form" :class="{ inverted: inverted }">
<div class="grouped fields">
<div class="field">
<div class="ui slider checkbox" :class="{ inverted: inverted }">
<input type="checkbox" id="darkmode" v-model="inverted"><label for="darkmode">Dark Mode</label>
</div>
</div>
<div class="field">
<div class="ui slider checkbox" :class="{ inverted: inverted }">
<input type="checkbox" id="combining" v-model="crushing"><label for="combining">Combine Messages</label>
</div>
</div>
<div class="field">
<div class="ui slider checkbox" :class="{ inverted: inverted }">
<input type="checkbox" id="combining" v-model="animated"><label for="animated">Animate Messages</label>
</div>
</div>
</div>
<div class="inline fields">
<label>Font Size</label>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" id="fssmall" name="fontsize" v-model="fontsize" value="zoom_less">
<label for="fssmall">Small</label>
</div>
</div>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" id="fsstd" name="fontsize" v-model="fontsize" value="zoom_normal">
<label for="fsstd">Standard</label>
</div>
</div>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" id="fslarge" name="fontsize" v-model="fontsize" value="zoom_more">
<label for="fslarge">Large</label>
</div>
</div>
</div>
<div class="inline fields">
<div class="field">
<label># Shown Messages</label>
<input :class="{ inverted: inverted }" type="number" name="showingnum" placeholder="200" title="Will affect performance!" v-model.lazy.number="showingnum" required style="width: 5em; padding: 0.1em;">
</div>
</div>
</div>
<button class="ui button" :class="{ inverted: inverted }" @click="save_chatlog">Export Chatlog</button>
</div>
</div>
</div>
</div>
<!-- Messages box -->
<div v-show="!editing" id="messagebox" class="ui segment" :class="active_classes" @click="click_message">
<div v-show="messages.length > showingnum" class="vc_system">
<span class='notice'>[ {{messages.length - showingnum}} previous messages hidden due to display settings. ]</span>
</div>
<transition-group name="msgsanim" tag="span" :css="animated">
<div v-for="message in shown_messages" :class="[message.category, fontsize]" :key="message.id">
<span v-html="message.content"></span>
<span v-show="message.repeats > 1" class="ui grey circular label">x{{message.repeats}}</span>
</div>
</transition-group>
</div>
</div>
<!--
Tab: {{active_tab}}<br>
Classes: {{active_classes}}<br>
Fontsize: {{fontsize}}<br>
-->
</div>
<script type="text/javascript">
//Document Ready
(function(){
start_vchat();
document.getElementById("loader").style.display = 'none';
document.getElementById("app").style.display = 'block';
})();
</script>
</body>
</html>
+78
View File
@@ -0,0 +1,78 @@
// https://tc39.github.io/ecma262/#sec-array.prototype.find
if (!Array.prototype.find) {
Object.defineProperty(Array.prototype, 'find', {
value: function(predicate) {
// 1. Let O be ? ToObject(this value).
if (this == null) {
throw TypeError('"this" is null or not defined');
}
var o = Object(this);
// 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0;
// 3. If IsCallable(predicate) is false, throw a TypeError exception.
if (typeof predicate !== 'function') {
throw TypeError('predicate must be a function');
}
// 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
var thisArg = arguments[1];
// 5. Let k be 0.
var k = 0;
// 6. Repeat, while k < len
while (k < len) {
// a. Let Pk be ! ToString(k).
// b. Let kValue be ? Get(O, Pk).
// c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
// d. If testResult is true, return kValue.
var kValue = o[k];
if (predicate.call(thisArg, kValue, k, o)) {
return kValue;
}
// e. Increase k by 1.
k++;
}
// 7. Return undefined.
return undefined;
},
configurable: true,
writable: true
});
}
if (!Date.now) {
Date.now = function now() {
return new Date().getTime();
};
}
//IE ugh
function storageAvailable(type) {
var storage;
try {
storage = window[type];
var x = '__storage_test__';
storage.setItem(x, x);
storage.removeItem(x);
return true;
}
catch(e) {
return e instanceof DOMException && (
// everything except Firefox
e.code === 22 ||
// Firefox
e.code === 1014 ||
// test name field too, because code might not be present
// everything except Firefox
e.name === 'QuotaExceededError' ||
// Firefox
e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
// acknowledge QuotaExceededError only if there's something already stored
(storage && storage.length !== 0);
}
}
+759
View File
@@ -0,0 +1,759 @@
//The 'V' is for 'VORE' but you can pretend it's for Vue.js if you really want.
(function(){
var oldLog = console.log;
console.log = function (message) {
send_debug(message);
oldLog.apply(console, arguments);
};
var oldError = console.error;
console.error = function (message) {
send_debug(message);
oldError.apply(console, arguments);
}
window.onerror = function (message, url, line, col, error) {
var stacktrace = "";
if(error && error.stack) {
stacktrace = error.stack;
}
send_debug(message+" ("+url+"@"+line+":"+col+") "+error+"|UA: "+navigator.userAgent+"|Stack: "+stacktrace);
return true;
}
})();
//Options for vchat
var vchat_opts = {
crush_messages: 3, //How many messages back should we try to combine if crushing is on
pingThisOften: 10000, //ms
pingDropsAllowed: 2,
cookiePrefix: "vst-" //If you're another server, you can change this if you want.
};
var DARKMODE_COLORS = {
buttonBgColor: "#40628a",
buttonTextColor: "#FFFFFF",
windowBgColor: "#272727",
highlightColor: "#009900",
tabTextColor: "#FFFFFF",
tabBackgroundColor: "#272727"
};
var LIGHTMODE_COLORS = {
buttonBgColor: "none",
buttonTextColor: "#000000",
windowBgColor: "none",
highlightColor: "#007700",
tabTextColor: "#000000",
tabBackgroundColor: "none"
};
/***********
*
* Setup Methods
*
************/
var set_storage = set_cookie;
var get_storage = get_cookie;
var domparser = new DOMParser();
//Upgrade to LS
if (storageAvailable('localStorage')) {
set_storage = set_localstorage;
get_storage = get_localstorage;
}
//State-tracking variables
var vchat_state = {
ready: false,
//Userinfo as reported by byond
byond_ip: null,
byond_cid: null,
byond_ckey: null,
//Ping status
lastPingAttempt: 0,
lastPingReply: 0,
missedPings: 0,
latency: 0,
reconnecting: false,
//Last ID
lastId: 0
}
function start_vchat() {
//Instantiate Vue.js
start_vue();
//Inform byond we're done
vchat_state.ready = true;
push_Topic('done_loading');
//I'll do my own winsets
doWinset("htmloutput", {"is-visible": true});
doWinset("oldoutput", {"is-visible": false});
doWinset("chatloadlabel", {"is-visible": false});
//Commence the pingening
send_ping();
setInterval(send_ping, vchat_opts.pingThisOften);
//For fun
send_debug("VChat Loaded!");
//throw new Error("VChat Loaded!");
}
//Loads vue for chat usage
var vueapp;
function start_vue() {
vueapp = new Vue({
el: '#app',
data: {
messages: [], //List o messages from byond
tabs: [ //Our tabs
{name: "Main", classes: ["vc_showall"], immutable: true, active: true}
],
always_show: ["vc_looc", "vc_system"], //Classes to always display on every tab
unread_messages: {}, //Message categories that haven't been looked at since we got one of them
editing: false, //If we're in settings edit mode
paused: false, //Autoscrolling
latency: 0, //Not necessarily network latency, since the game server has to align the responses into ticks
ext_styles: "", //Styles for chat downloaded files
is_admin: false,
//Settings
inverted: false, //Dark mode
crushing: true, //Combine similar messages
showingnum: 200, //How many messages to show
animated: true, //Small CSS animations for new messages
fontsize: "zoom_normal", //Font size nudging
//The table to map game css classes to our vchat classes
type_table: [
{
matches: ".say, .emote",
becomes: "vc_localchat",
pretty: "Local Chat",
required: false,
admin: false
},
{
matches: ".alert, .syndradio, .centradio, .airadio, .entradio, .comradio, .secradio, .engradio, .medradio, .sciradio, .supradio, .srvradio, .expradio, .radio, .deptradio, .newscaster",
becomes: "vc_radio",
pretty: "Radio Comms",
required: false,
admin: false
},
{
matches: ".notice, .adminnotice, .info, .sinister, .cult",
becomes: "vc_info",
pretty: "Notices",
required: false,
admin: false
},
{
matches: ".critical, .danger, .userdanger, .warning, .italics",
becomes: "vc_warnings",
pretty: "Warnings",
required: false,
admin: false
},
{
matches: ".deadsay",
becomes: "vc_deadchat",
pretty: "Deadchat",
required: false,
admin: false
},
{
matches: ".ooc:not(.looc)",
becomes: "vc_globalooc",
pretty: "Global OOC",
required: false,
admin: false
},
//VOREStation Add Start
{
matches: ".nif",
becomes: "vc_nif",
pretty: "NIF Messages",
required: false,
admin: false
},
//VOREStation Add End
{
matches: ".pm",
becomes: "vc_adminpm",
pretty: "Admin PMs",
required: false,
admin: false
},
{
matches: ".admin_channel",
becomes: "vc_adminchat",
pretty: "Admin Chat",
required: false,
admin: true
},
{
matches: ".mod_channel",
becomes: "vc_modchat",
pretty: "Mod Chat",
required: false,
admin: true
},
{
matches: ".event_channel",
becomes: "vc_eventchat",
pretty: "Event Chat",
required: false,
admin: true
},
{
matches: ".ooc.looc, .ooc .looc", //Dumb game
becomes: "vc_looc",
pretty: "Local OOC",
required: true
},
{
matches: ".boldannounce",
becomes: "vc_system",
pretty: "System Messages",
required: true
}
],
},
created: function() {
/*Dog mode
setTimeout(function(){
document.body.className += " woof";
},5000);
*/
/* Stress test
var varthis = this;
setInterval( function() {
if(varthis.messages.length > 10000) {
return;
}
var stringymessages = JSON.stringify(varthis.messages);
var unstringy = JSON.parse(stringymessages);
unstringy.forEach( function(message) {
message.id = ++vchat_state.lastId;
varthis.messages.push(message);
});
varthis.internal_message("Now have " + varthis.messages.length + " messages in array.");
}, 10000);
*/
},
mounted: function() {
//Load our settings
this.load_settings();
var xhr = new XMLHttpRequest();
xhr.open('GET', 'ss13styles.css');
xhr.onreadystatechange = (function() {
this.ext_styles = xhr.responseText;
}).bind(this);
xhr.send();
},
updated: function() {
if(!this.editing && !this.paused) {
window.scrollTo(0,document.getElementById("messagebox").scrollHeight);
}
},
watch: {
//Save the inverted setting to LS
inverted: function (newSetting) {
set_storage("darkmode",newSetting);
if(newSetting) { //Special treatment for <body> which is outside Vue's scope and has custom css
document.body.classList.add("inverted");
switch_ui_mode(DARKMODE_COLORS);
} else {
document.body.classList.remove("inverted");
switch_ui_mode(LIGHTMODE_COLORS);
}
},
crushing: function (newSetting) {
set_storage("crushing",newSetting);
},
animated: function (newSetting) {
set_storage("animated",newSetting);
},
fontsize: function (newSetting) {
set_storage("fontsize",newSetting);
},
showingnum: function (newSetting, oldSetting) {
if(!isFinite(newSetting)) {
this.showingnum = oldSetting;
return;
}
newSetting = Math.floor(newSetting);
if(newSetting <= 50) {
this.showingnum = 50;
} else if(newSetting > 2000) {
this.showingnum = 2000;
}
set_storage("showingnum",this.showingnum);
}
},
computed: {
//Which tab is active?
active_tab: function() {
//Had to polyfill this stupid .find since IE doesn't have EC6
let tab = this.tabs.find( function(tab) {
return tab.active;
});
return tab;
},
//Which classes does the active tab need?
active_classes: function() {
let classarray = this.active_tab.classes;
let classtext = classarray.toString(); //Convert to a string
let classproper = classtext.replace(/,/g," ");
if(this.inverted) classproper += " inverted";
return classproper; //Swap commas for spaces
},
//What color does the latency pip get?
ping_classes: function() {
if(this.latency === 0) { return "grey"; }
else if(this.latency < 0 ) {return "red"; }
else if(this.latency <= 200) { return "green"; }
else if(this.latency <= 400) { return "yellow"; }
else { return "red"; }
},
shown_messages: function() {
if(this.messages.length <= this.showingnum) {
return this.messages;
} else {
return this.messages.slice(-1*this.showingnum);
}
}
},
methods: {
//Load the chat settings
load_settings: function() {
this.inverted = get_storage("darkmode", false);
this.crushing = get_storage("crushing", true);
this.showingnum = get_storage("showingnum", 200);
this.animated = get_storage("animated", true);
this.fontsize = get_storage("fontsize", 'zoom_normal');
},
//Change to another tab
switchtab: function(tab) {
if(tab == this.active_tab) return;
this.active_tab.active = false;
tab.active = true;
tab.classes.forEach( function(cls) {
this.unread_messages[cls] = 0;
}, this);
},
//Toggle edit mode
editmode: function() {
this.editing = !this.editing;
},
//Toggle autoscroll
pause: function() {
this.paused = !this.paused;
},
//Create a new tab (stupid lack of classes in ES5...)
newtab: function() {
this.tabs.push({
name: "New Tab",
classes: this.always_show,
immutable: false,
active: false
});
this.switchtab(this.tabs[this.tabs.length - 1]);
},
//Rename an existing tab
renametab: function() {
if(this.active_tab.immutable) {
return;
}
var tabtorename = this.active_tab;
var newname = window.prompt("Type the desired tab name:", tabtorename.name);
if(newname === null || newname === "" || tabtorename === null) {
return;
}
tabtorename.name = newname;
},
//Delete the currently active tab
deltab: function(tab) {
if(!tab) {
tab = this.active_tab;
}
if(tab.immutable) {
return;
}
this.switchtab(this.tabs[0]);
this.tabs.splice(this.tabs.indexOf(tab), 1);
},
movetab: function(tab, shift) {
if(!tab || tab.immutable) {
return;
}
var at = this.tabs.indexOf(tab);
var to = at + shift;
this.tabs.splice(to, 0, this.tabs.splice(at, 1)[0]);
},
tab_unread_count: function(tab) {
var unreads = 0;
var thisum = this.unread_messages;
tab.classes.find( function(cls){
if(thisum[cls]) {
unreads += thisum[cls];
}
});
return unreads;
},
tab_unread_classes: function(tab) {
var unreads = false;
var thisum = this.unread_messages;
tab.classes.find( function(cls){
if(thisum[cls]) {
unreads = true;
return true;
}
});
return { red: unreads, grey: !unreads};
},
//Push a new message into our array
add_message: function(message) {
//IE doesn't support the 'class' syntactic sugar so we're left making our own object.
let newmessage = {
time: message.time,
category: "error",
content: message.message,
repeats: 1
};
//Get a category
newmessage.category = this.get_category(newmessage.content);
if(!this.active_tab.classes.some(function(cls) { return (cls == newmessage.category || cls == "vc_showall"); })) {
if (isNaN(this.unread_messages[newmessage.category])) {
this.unread_messages[newmessage.category] = 0;
}
this.unread_messages[newmessage.category] += 1;
}
//Try to crush it with one of the last few
if(this.crushing) {
let crushwith = this.messages.slice(-(vchat_opts.crush_messages));
for (let i = crushwith.length - 1; i >= 0; i--) {
let oldmessage = crushwith[i];
if(oldmessage.content == newmessage.content) {
newmessage.repeats += oldmessage.repeats;
this.messages.splice(this.messages.indexOf(oldmessage), 1);
}
}
}
//Append to vue's messages
newmessage.id = ++vchat_state.lastId;
this.messages.push(newmessage);
},
//Push an internally generated message into our array
internal_message: function(message) {
let newmessage = {
time: this.messages.length ? this.messages.slice(-1).time+1 : 0,
category: "vc_system",
content: "<span class='notice'>[VChat Internal] " + message + "</span>"
};
newmessage.id = ++vchat_state.lastId;
this.messages.push(newmessage);
},
on_mouseup: function(event) {
// Focus map window on mouseup so hotkeys work. Exception for if they highlighted text or clicked an input.
let ele = event.target;
let textSelected = ('getSelection' in window) && window.getSelection().isCollapsed === false;
if (!textSelected && !(ele && (ele.tagName === 'INPUT' || ele.tagName === 'TEXTAREA'))) {
focusMapWindow();
// Okay focusing map window appears to prevent click event from being fired. So lets do it ourselves.
event.preventDefault();
event.target.click();
}
},
click_message: function(event) {
let ele = event.target;
if(ele.tagName === "A") {
event.stopPropagation();
event.preventDefault ? event.preventDefault() : (event.returnValue = false); //The second one is the weird IE method.
var href = ele.getAttribute('href'); // Gets actual href without transformation into fully qualified URL
if (href[0] == '?' || (href.length >= 8 && href.substring(0,8) == "byond://")) {
window.location = href; //Internal byond link
} else { //It's an external link
window.location = "byond://?action=openLink&link="+encodeURIComponent(href);
}
}
},
//Derive a vchat category based on css classes
get_category: function(message) {
if(!vchat_state.ready) {
push_Topic('not_ready');
return;
}
let doc = domparser.parseFromString(message, 'text/html');
let evaluating = doc.querySelector('span');
let category = "nomatch"; //What we use if the classes aren't anything we know.
if(!evaluating) return category;
this.type_table.find( function(type) {
if(evaluating.msMatchesSelector(type.matches)) {
category = type.becomes;
return true;
}
});
return category;
},
save_chatlog: function() {
var textToSave = "<html><head><style>"+this.ext_styles+"</style></head><body>";
this.messages.forEach( function(message) {
textToSave += message.content;
if(message.repeats > 1) {
textToSave += "(x"+message.repeats+")";
}
textToSave += "<br>\n";
});
textToSave += "</body></html>";
var hiddenElement = document.createElement('a');
hiddenElement.href = 'data:attachment/text,' + encodeURI(textToSave);
hiddenElement.target = '_blank';
var filename = "chat_export.html";
//Unlikely to work unfortunately, not supported in any version of IE, only Edge
if (hiddenElement.download !== undefined){
hiddenElement.download = filename;
hiddenElement.click();
//Probably what will end up getting used
} else {
let blob = new Blob([textToSave], {type: 'text/html;charset=utf8;'});
saved = window.navigator.msSaveBlob(blob, filename);
}
}
}
});
}
/***********
*
* Actual Methods
*
************/
//Send a 'ping' to byond and check to see if we got the last one back in a timely manner
function send_ping() {
vchat_state.latency = (Math.min(Math.max(vchat_state.lastPingReply - vchat_state.lastPingAttempt, -1), 999));
//If their last reply was in the previous ping window or earlier.
if(vchat_state.latency < 0) {
vchat_state.missedPings++;
if((vchat_state.missedPings >= vchat_opts.pingDropsAllowed) && !vchat_state.reconnecting) {
system_message("Your client has lost connection with the server. It will reconnect automatically if possible.");
vchat_state.reconnecting = true;
}
}
vueapp.latency = vchat_state.latency;
push_Topic("keepalive_client");
vchat_state.lastPingAttempt = Date.now();
}
//We accept double-url-encoded JSON strings because Byond is garbage and UTF-8 encoded url_encode() text has crazy garbage in it.
function byondDecode(message) {
//Byond encodes spaces as pluses?! This is 1998 I guess.
message = message.replace(/\+/g, "%20");
try {
message = decodeURIComponent(message);
} catch (err) {
message = unescape(message);
}
return JSON.parse(message);
}
//This is the function byond actually communicates with using byond's client << output() method.
function putmessage(messages) {
messages = byondDecode(messages);
if (Array.isArray(messages)) {
messages.forEach(function(message) {
vueapp.add_message(message);
});
} else if (typeof messages === 'object') {
vueapp.add_message(messages);
}
}
//Send an internal message generated in the javascript
function system_message(message) {
vueapp.internal_message(message);
}
//This is the other direction of communication, to push a Topic message back
function push_Topic(topic_uri) {
window.location = '?_src_=chat&proc=' + topic_uri; //Yes that's really how it works.
}
//Tells byond client to focus the main map window.
function focusMapWindow() {
window.location = 'byond://winset?mapwindow.map.focus=true';
}
//Debug event
function send_debug(message) {
push_Topic("debug&param[message]="+encodeURIComponent(message));
}
//A side-channel to send events over that aren't just chat messages, if necessary.
function get_event(event) {
if(!vchat_state.ready) {
push_Topic('not_ready');
return;
}
var parsed_event = {evttype: 'internal_error', event: event};
parsed_event = byondDecode(event);
switch(parsed_event.evttype) {
//We didn't parse it very well
case 'internal_error':
system_message("Event parse error: " + event);
break;
//They provided byond data.
case 'byond_player':
send_client_data();
vueapp.is_admin = (parsed_event.admin === 'true');
vchat_state.byond_ip = parsed_event.address;
vchat_state.byond_cid = parsed_event.cid;
vchat_state.byond_ckey = parsed_event.ckey;
set_storage("ip",vchat_state.byond_ip);
set_storage("cid",vchat_state.byond_cid);
set_storage("ckey",vchat_state.byond_ckey);
break;
//Just a ping.
case 'keepalive_server':
vchat_state.lastPingReply = Date.now();
vchat_state.missedPings = 0;
reconnecting = false;
break;
default:
system_message("Didn't know what to do with event: " + event);
}
}
//Send information retrieved from storage
function send_client_data() {
let client_data = {
ip: get_storage("ip"),
cid: get_storage("cid"),
ckey: get_storage("ckey")
};
push_Topic("ident&param[clientdata]="+JSON.stringify(client_data));
}
//Newer localstorage methods
function set_localstorage(key, value) {
let localstorage = window.localStorage;
localstorage.setItem(vchat_opts.cookiePrefix+key,value);
}
function get_localstorage(key, deffo) {
let localstorage = window.localStorage;
let value = localstorage.getItem(vchat_opts.cookiePrefix+key);
//localstorage only stores strings.
if(value === "null" || value === null) {
value = deffo;
} else if(value === "true") {
value = true;
} else if(value === "false") {
value = false;
}
return value;
}
//Older cookie methods
function set_cookie(key, value) {
let now = new Date();
now.setFullYear(now.getFullYear() + 1);
let then = now.toUTCString();
document.cookie = vchat_opts.cookiePrefix+key+"="+value+";expires="+then+";path=/";
}
function get_cookie(key, deffo) {
var candidates = {cookie: null, localstorage: null, indexeddb: null};
let cookie_array = document.cookie.split(';');
let cookie_object = {};
cookie_array.forEach( function(element) {
let clean = element.replace(vchat_opts.cookiePrefix,"").trim(); //Strip the prefix, trim whitespace
let equals = clean.search("="); //Find the equals
let left = decodeURIComponent(clean.substring(0,equals)); //From start to one char before equals
let right = decodeURIComponent(clean.substring(equals+1)); //From one char after equals to end
//cookies only stores strings.
if(right == "null" || right === null) {
right = deffo;
} else if(right === "true") {
right = true;
} else if(right === "false") {
right = false;
}
cookie_object[left] = right; //Stick into object
});
candidates.cookie = cookie_object[key]; //Return value of that key in our object (or undefined)
}
// Button Controls that need background-color and text-color set.
var SKIN_BUTTONS = [
/* Rpane */ "rpane.textb", "rpane.infob", "rpane.wikib", "rpane.forumb", "rpane.rulesb", "rpane.github", "rpane.mapb", "rpane.changelog",
/* Mainwindow */ "mainwindow.saybutton", "mainwindow.mebutton", "mainwindow.hotkey_toggle"
];
// Windows or controls that need background-color set.
var SKIN_ELEMENTS = [
/* Mainwindow */ "mainwindow", "mainwindow.mainvsplit", "mainwindow.tooltip",
/* Rpane */ "rpane", "rpane.rpanewindow", "rpane.mediapanel",
];
function switch_ui_mode(options) {
doWinset(SKIN_BUTTONS.reduce(function(params, ctl) {params[ctl + ".background-color"] = options.buttonBgColor; return params;}, {}));
doWinset(SKIN_BUTTONS.reduce(function(params, ctl) {params[ctl + ".text-color"] = options.buttonTextColor; return params;}, {}));
doWinset(SKIN_ELEMENTS.reduce(function(params, ctl) {params[ctl + ".background-color"] = options.windowBgColor; return params;}, {}));
doWinset("infowindow", {
"background-color": options.tabBackgroundColor,
"text-color": options.tabTextColor
});
doWinset("infowindow.info", {
"background-color": options.tabBackgroundColor,
"text-color": options.tabTextColor,
"highlight-color": options.highlightColor,
"tab-text-color": options.tabTextColor,
"tab-background-color": options.tabBackgroundColor
});
}
function doWinset(control_id, params) {
if (typeof params === 'undefined') {
params = control_id; // Handle single-argument use case.
control_id = null;
}
var url = "byond://winset?";
if (control_id) {
url += ("id=" + control_id + "&");
}
url += Object.keys(params).map(function(ctl) {
return ctl + "=" + encodeURIComponent(params[ctl]);
}).join("&");
window.location = url;
}
+11965
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+328
View File
@@ -0,0 +1,328 @@
#define BACKLOG_LENGTH 20 MINUTES
//The 'V' is for 'VORE' but you can pretend it's for Vue.js if you really want.
//These are sent to the client via browse_rsc() in advance so the HTML can access them.
GLOBAL_LIST_INIT(vchatFiles, list(
"code/modules/vchat/css/vchat-font-embedded.css",
"code/modules/vchat/css/semantic.min.css",
"code/modules/vchat/css/ss13styles.css",
"code/modules/vchat/js/polyfills.js",
"code/modules/vchat/js/vue.min.js",
"code/modules/vchat/js/vchat.js"
))
// The to_chat() macro calls this proc
/proc/__to_chat(var/target, var/message)
// First do logging in database
if(isclient(target))
var/client/C = target
vchat_add_message(C.ckey,message)
else if(ismob(target))
var/mob/M = target
if(M.ckey)
vchat_add_message(M.ckey,message)
// Now lets either queue it for sending, or send it right now
if(Master.current_runlevel == RUNLEVEL_INIT || !SSchat?.subsystem_initialized)
to_chat_immediate(target, world.time, message)
else
SSchat.queue(target, world.time, message)
//This is used to convert icons to base64 <image> strings, because byond stores icons in base64 in savefiles.
GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of icons for the browser output
//The main object attached to clients, created when they connect, and has start() called on it in client/New()
/datum/chatOutput
var/client/owner = null
var/loaded = FALSE
var/list/message_queue = list()
var/broken = FALSE
var/resources_sent = FALSE
var/last_topic_time = 0
var/too_many_topics = 0
var/topic_spam_limit = 10 //Just enough to get over the startup and such
/datum/chatOutput/New(client/C)
. = ..()
owner = C
update_vis()
/datum/chatOutput/Destroy()
owner = null
. = ..()
/datum/chatOutput/proc/update_vis()
if(!loaded && !broken)
winset(owner, null, "outputwindow.htmloutput.is-visible=false;outputwindow.oldoutput.is-visible=false;outputwindow.chatloadlabel.is-visible=true")
else if(broken)
winset(owner, null, "outputwindow.htmloutput.is-visible=false;outputwindow.oldoutput.is-visible=true;outputwindow.chatloadlabel.is-visible=false")
else if(loaded)
return //It can do it's own winsets from inside the JS if it's working.
//Shove all the assets at them
/datum/chatOutput/proc/send_resources()
for(var/filename in GLOB.vchatFiles)
owner << browse_rsc(file(filename))
resources_sent = TRUE
//Called from client/New() in a spawn()
/datum/chatOutput/proc/start()
if(!owner)
qdel(src)
return FALSE
if(!winexists(owner, "htmloutput"))
spawn()
alert(owner, "Updated chat window does not exist. If you are using a custom skin file please allow the game to update.")
become_broken()
return FALSE
if(!owner) // In case the client vanishes before winexists returns
qdel(src)
return FALSE
if(!resources_sent)
send_resources()
load()
return TRUE
//Attempts to actually load the HTML page into the client's UI
/datum/chatOutput/proc/load()
if(!owner)
qdel(src)
return
owner << browse(file2text("code/modules/vchat/html/vchat.html"), "window=htmloutput")
//Check back later
spawn(15 SECONDS)
if(!src)
return
if(!src.loaded)
src.become_broken()
//var/list/joins = list() //Just for testing with the below
//Called by Topic, when the JS in the HTML page finishes loading
/datum/chatOutput/proc/done_loading()
if(loaded)
return
loaded = TRUE
broken = FALSE
owner.chatOutputLoadedAt = world.time
//update_vis() //It does it's own winsets
send_playerinfo()
load_database()
//Perform DB shenanigans
/datum/chatOutput/proc/load_database()
set waitfor = FALSE
var/list/results = vchat_get_messages(owner.ckey, world.time - BACKLOG_LENGTH)
for(var/list/message in results)
to_chat_immediate(owner, message["time"], message["message"])
CHECK_TICK
//It din work
/datum/chatOutput/proc/become_broken()
broken = TRUE
loaded = FALSE
update_vis()
spawn()
alert(owner,"VChat didn't load after some time. Switching to use oldchat as a fallback. Try using 'Reload VChat' verb in OOC verbs, or reconnecting to try again.")
//Provide the JS with who we are
/datum/chatOutput/proc/send_playerinfo()
if(!owner)
qdel(src)
return
var/list/playerinfo = list("evttype" = "byond_player", "cid" = owner.computer_id, "ckey" = owner.ckey, "address" = owner.address, "admin" = owner.holder ? "true" : "false")
send_event(playerinfo)
//Ugh byond doesn't handle UTF-8 well so we have to do this.
/proc/jsEncode(var/list/message) {
if(!islist(message))
CRASH("Passed a non-list to encode.")
return; //Necessary?
return url_encode(url_encode(json_encode(message)))
}
//Send a side-channel event to the chat window
/datum/chatOutput/proc/send_event(var/event, var/client/C = owner)
C << output(jsEncode(event), "htmloutput:get_event")
//Just produces a message for using in keepalives from the server to the client
/datum/chatOutput/proc/keepalive()
return list("evttype" = "keepalive_server")
//Redirected from client/Topic when the user clicks a link that pertains directly to the chat (when src == "chat")
/datum/chatOutput/Topic(var/href, var/list/href_list)
if(usr.client != owner)
return 1
if(last_topic_time > (world.time - 3 SECONDS))
too_many_topics++
if(too_many_topics >= topic_spam_limit)
log_and_message_admins("Kicking [key_name(owner)] - VChat Topic() spam")
to_chat(owner,"<span class='danger'>You have been kicked due to VChat sending too many messages to the server. Try reconnecting.</span>")
qdel(owner)
qdel(src)
return
else
too_many_topics = 0
last_topic_time = world.time
var/list/params = list()
for(var/key in href_list)
if(length(key) > 7 && findtext(key, "param"))
var/param_name = copytext(key, 7, -1)
var/item = href_list[key]
params[param_name] = item
var/data
switch(href_list["proc"])
if("not_ready")
CRASH("Tried to send a message to [owner.ckey] chatOutput before it was ready!")
if("done_loading")
data = done_loading(arglist(params))
if("keepalive_client")
data = keepalive(arglist(params))
if("ident")
data = bancheck(arglist(params))
if("unloading")
loaded = FALSE
if("debug")
data = debugmsg(arglist(params))
if(data)
send_event(event = data)
//Print a message that was an error from a client
/datum/chatOutput/proc/debugmsg(var/message = "No String Provided")
log_debug("VChat: [owner] got: [message]")
//Check relevant client info reported from JS
/datum/chatOutput/proc/bancheck(var/clientdata)
var/list/info = json_decode(clientdata)
var/ckey = info["ckey"]
var/ip = info["ip"]
var/cid = info["cid"]
//Never connected? How sad!
if(!cid && !ip && !ckey)
return
var/list/ban = world.IsBanned(key = ckey, address = ip, computer_id = cid)
if(ban)
log_and_message_admins("[key_name(owner)] has a cookie from a banned account! (Cookie: [ckey], [ip], [cid])")
//Converts an icon to base64. Operates by putting the icon in the iconCache savefile,
// exporting it as text, and then parsing the base64 from that.
// (This relies on byond automatically storing icons in savefiles as base64)
/proc/icon2base64(var/icon/icon, var/iconKey = "misc")
if (!isicon(icon)) return FALSE
GLOB.iconCache[iconKey] << icon
var/iconData = GLOB.iconCache.ExportText(iconKey)
var/list/partial = splittext(iconData, "{")
return replacetext(copytext(partial[2], 3, -5), "\n", "")
/proc/bicon(var/obj, var/use_class = 1, var/custom_classes = "")
var/class = use_class ? "class='icon misc [custom_classes]'" : null
if (!obj)
return
var/static/list/bicon_cache = list()
if (isicon(obj))
if (!bicon_cache["\ref[obj]"]) // Doesn't exist yet, make it.
bicon_cache["\ref[obj]"] = icon2base64(obj)
return "<img [class] src='data:image/png;base64,[bicon_cache["\ref[obj]"]]'>"
// Either an atom or somebody fucked up and is gonna get a runtime, which I'm fine with.
var/atom/A = obj
var/key = "[istype(A.icon, /icon) ? "\ref[A.icon]" : A.icon]:[A.icon_state]"
if (!bicon_cache[key]) // Doesn't exist, make it.
var/icon/I = icon(A.icon, A.icon_state, SOUTH, 1)
if (ishuman(obj))
I = getFlatIcon(obj) //Ugly
bicon_cache[key] = icon2base64(I, key)
if(use_class)
class = "class='icon [A.icon_state] [custom_classes]'"
return "<img [class] src='data:image/png;base64,[bicon_cache[key]]'>"
//Checks if the message content is a valid to_chat message
/proc/is_valid_tochat_message(message)
return istext(message)
//Checks if the target of to_chat is something we can send to
/proc/is_valid_tochat_target(target)
return !istype(target, /savefile) && (ismob(target) || islist(target) || isclient(target) || target == world)
var/to_chat_filename
var/to_chat_line
var/to_chat_src
//This proc is only really used if the SSchat subsystem is unavailable (not started yet)
/proc/to_chat_immediate(target, time, message)
if(!is_valid_tochat_message(message) || !is_valid_tochat_target(target))
target << message
// Info about the "message"
if(isnull(message))
message = "(null)"
else if(istype(message, /datum))
var/datum/D = message
message = "([D.type]): '[D]'"
else if(!is_valid_tochat_message(message))
message = "(bad message) : '[message]'"
// Info about the target
var/targetstring = "'[target]'"
if(istype(target, /datum))
var/datum/D = target
targetstring += ", [D.type]"
// The final output
log_debug("to_chat called with invalid message/target: [to_chat_filename], [to_chat_line], [to_chat_src], Message: '[message]', Target: [targetstring]")
return
else if(is_valid_tochat_message(message))
if(istext(target))
log_debug("Somehow, to_chat got a text as a target")
return
var/original_message = message
message = replacetext(message, "\n", "<br>")
message = replacetext(message, "\improper", "")
message = replacetext(message, "\proper", "")
if(isnull(time))
time = world.time
var/client/C = CLIENT_FROM_VAR(target)
if(C && C.chatOutput)
if(C.chatOutput.broken)
DIRECT_OUTPUT(C, original_message)
return
// // Client still loading, put their messages in a queue - Actually don't, logged already in database.
// if(!C.chatOutput.loaded && C.chatOutput.message_queue && islist(C.chatOutput.message_queue))
// C.chatOutput.message_queue[++C.chatOutput.message_queue.len] = list("time" = time, "message" = message)
// return
var/list/tojson = list("time" = time, "message" = message);
target << output(jsEncode(tojson), "htmloutput:putmessage")
#undef BACKLOG_LENGTH
+122
View File
@@ -0,0 +1,122 @@
#define VCHAT_FILENAME "data/vchat.db"
GLOBAL_DATUM(vchatdb, /database)
//Boot up db file
/proc/init_vchat()
//Cleanup previous if exists
fdel(VCHAT_FILENAME)
fdel(VCHAT_FILENAME+"-shm") //Shared memory, and
fdel(VCHAT_FILENAME+"-wal") // write ahead. Only present on unclean stop.
//Create a new one
GLOB.vchatdb = new(VCHAT_FILENAME)
//Build our basic boring tables
vchat_create_tables()
//Check to see if it's init
/proc/check_vchat()
if(istype(GLOB.vchatdb))
return TRUE
else
return FALSE
//For INSERT/CREATE/DELETE, etc that return a RowsAffected.
/proc/vchat_exec_update(var/query)
if(!check_vchat())
log_debug("There's no vchat database open but you tried to query it with: [query]")
return FALSE
//Solidify our query
var/database/query/q = vchat_build_query(query)
//Run it
q.Execute(GLOB.vchatdb)
//Handle errors
if(q.Error())
log_debug("Query \"[islist(query)?query[1]:query]\" ended in error [q.ErrorMsg()]")
return FALSE
return q.RowsAffected()
//For SELECT, that return results.
/proc/vchat_exec_query(var/query)
if(!check_vchat())
log_debug("There's no vchat database open but you tried to query it!")
return FALSE
//Solidify our query
var/database/query/q = vchat_build_query(query)
//Run it
q.Execute(GLOB.vchatdb)
//Handle errors
if(q.Error())
log_debug("Query \"[islist(query)?query[1]:query]\" ended in error [q.ErrorMsg()]")
return FALSE
//Return any results
var/list/results = list()
//Return results if any.
while(q.NextRow())
results[++results.len] = q.GetRowData()
return results
//Create a query from string or list with params
/proc/vchat_build_query(var/query)
var/database/query/q
if(islist(query))
q = new(arglist(query))
else
q = new(query)
if(!istype(q))
return
return q
/proc/vchat_create_tables()
//Byond is so great half the time it doesn't delete the file
var/cleanup = "DROP TABLE IF EXISTS messages"
vchat_exec_update(cleanup)
cleanup = "VACUUM"
vchat_exec_update(cleanup)
//Messages table
var/tabledef = "CREATE TABLE messages(\
id INTEGER PRIMARY KEY AUTOINCREMENT,\
ckey VARCHAR(50) NOT NULL,\
worldtime INTEGER NOT NULL,\
message TEXT NOT NULL)"
vchat_exec_update(tabledef)
//Index on ckey
var/indexdef = "CREATE INDEX ckey_index ON messages (ckey)"
vchat_exec_update(indexdef)
//INSERT a new message
/proc/vchat_add_message(var/ckey, var/message)
if(!ckey || !message)
return
var/list/messagedef = list(
"INSERT INTO messages (ckey,worldtime,message) VALUES (?, ?, ?)",
ckey,
world.time,
message)
return vchat_exec_update(messagedef)
//Get a player's message history
/proc/vchat_get_messages(var/ckey, var/oldest = 0)
if(!ckey)
return
var/list/getdef = list("SELECT * FROM messages WHERE ckey = ? AND worldtime >= ?", ckey, oldest)
return vchat_exec_query(getdef)
#undef VCHAT_FILENAME
+1 -1
View File
@@ -17,4 +17,4 @@
I.loc = src.loc
for(var/mob/O in hearers(src, null))
O.show_message("\icon[src] <font color='blue'>The [src.name] beeps.</font>", 2)
O.show_message("[bicon(src)] <font color='blue'>The [src.name] beeps.</font>", 2)
+1 -1
View File
@@ -30,7 +30,7 @@
report("Antibodies detected: [antigens2string(C.antibodies)]", user)
/obj/item/device/antibody_scanner/proc/report(var/text, mob/user as mob)
to_chat(user, "<font color='blue'>\icon[src] \The [src] beeps,</font> \"<font color='blue'>[text]</font>\"")
to_chat(user, "<font color='blue'>[bicon(src)] \The [src] beeps,</font> \"<font color='blue'>[text]</font>\"")
///////////////VIRUS DISH///////////////
@@ -46,17 +46,17 @@
if(!previous_power_state)
previous_power_state = 1
icon_state = "cellold1"
src.visible_message("<span class='notice'>\icon[src] [src] suddenly comes to life!</span>")
src.visible_message("<span class='notice'>[bicon(src)] [src] suddenly comes to life!</span>")
//slowly grow a mob
if(prob(5))
src.visible_message("<span class='notice'>\icon[src] [src] [pick("gloops","glugs","whirrs","whooshes","hisses","purrs","hums","gushes")].</span>")
src.visible_message("<span class='notice'>[bicon(src)] [src] [pick("gloops","glugs","whirrs","whooshes","hisses","purrs","hums","gushes")].</span>")
//if we've finished growing...
if(time_spent_spawning >= time_per_spawn)
time_spent_spawning = 0
use_power = 1
src.visible_message("<span class='notice'>\icon[src] [src] pings!</span>")
src.visible_message("<span class='notice'>[bicon(src)] [src] pings!</span>")
icon_state = "cellold1"
desc = "It's full of a bubbling viscous liquid, and is lit by a mysterious glow."
if(spawn_type)
@@ -77,7 +77,7 @@
if(previous_power_state)
previous_power_state = 0
icon_state = "cellold0"
src.visible_message("<span class='notice'>\icon[src] [src] suddenly shuts down.</span>")
src.visible_message("<span class='notice'>[bicon(src)] [src] suddenly shuts down.</span>")
//cloned mob slowly breaks down
time_spent_spawning = max(time_spent_spawning + last_process - world.time, 0)
@@ -74,7 +74,7 @@
viables.Remove(type)
construction[button_desc] = type
fail_message = "<font color='blue'>\icon[src] a [pick("loud","soft","sinister","eery","triumphant","depressing","cheerful","angry")] \
fail_message = "<font color='blue'>[bicon(src)] a [pick("loud","soft","sinister","eery","triumphant","depressing","cheerful","angry")] \
[pick("horn","beep","bing","bleep","blat","honk","hrumph","ding")] sounds and a \
[pick("yellow","purple","green","blue","red","orange","white")] \
[pick("light","dial","meter","window","protrusion","knob","antenna","swirly thing")] \
@@ -86,7 +86,7 @@
if(spawning_types.len && powered())
spawn_progress_time += world.time - last_process_time
if(spawn_progress_time > max_spawn_time)
src.visible_message("<span class='notice'>\icon[src] [src] pings!</span>")
src.visible_message("<span class='notice'>[bicon(src)] [src] pings!</span>")
var/obj/source_material = pop(stored_materials)
var/spawn_type = pop(spawning_types)
@@ -109,7 +109,7 @@
icon_state = "borgcharger0(old)"
else if(prob(5))
src.visible_message("<span class='notice'>\icon[src] [src] [pick("clicks","whizzes","whirrs","whooshes","clanks","clongs","clonks","bangs")].</span>")
src.visible_message("<span class='notice'>[bicon(src)] [src] [pick("clicks","whizzes","whirrs","whooshes","clanks","clongs","clonks","bangs")].</span>")
last_process_time = world.time
@@ -140,9 +140,9 @@
if(index > 0 && index <= construction.len)
if(stored_materials.len > spawning_types.len)
if(spawning_types.len)
src.visible_message("<span class='notice'>\icon[src] a [pick("light","dial","display","meter","pad")] on [src]'s front [pick("blinks","flashes")] [pick("red","yellow","blue","orange","purple","green","white")].</span>")
src.visible_message("<span class='notice'>[bicon(src)] a [pick("light","dial","display","meter","pad")] on [src]'s front [pick("blinks","flashes")] [pick("red","yellow","blue","orange","purple","green","white")].</span>")
else
src.visible_message("<span class='notice'>\icon[src] [src]'s front compartment slides shut.</span>")
src.visible_message("<span class='notice'>[bicon(src)] [src]'s front compartment slides shut.</span>")
spawning_types.Add(construction[construction[index]])
spawn_progress_time = 0
+1 -1
View File
@@ -53,7 +53,7 @@
var/atom/toplevelholder = holder
while(!istype(toplevelholder.loc, /turf))
toplevelholder = toplevelholder.loc
toplevelholder.visible_message("<font color='red'>\icon[toplevelholder] [toplevelholder] [display_msg]</font>")
toplevelholder.visible_message("<font color='red'>[bicon(toplevelholder)] [toplevelholder] [display_msg]</font>")
/datum/artifact_effect/proc/DoEffectTouch(var/mob/user)
/datum/artifact_effect/proc/DoEffectAura(var/atom/holder)
@@ -77,7 +77,7 @@
..()
else if(istype(W,/obj/item/weapon/pen))
plaque_contents = sanitize(input("What would you like to write on the plaque:","Skeleton plaque",""))
user.visible_message("[user] writes something on the base of [src].","You relabel the plaque on the base of \icon[src] [src].")
user.visible_message("[user] writes something on the base of [src].","You relabel the plaque on the base of [bicon(src)] [src].")
if(src.contents.Find(/obj/item/weapon/fossil/skull/horned))
src.desc = "A creature made of [src.contents.len-1] assorted bones and a horned skull. The plaque reads \'[plaque_contents]\'."
else
@@ -99,7 +99,7 @@
if(charges >= 0.1)
if(prob(5))
src.visible_message("<font color='red'>\icon[src] [src]'s eyes glow ruby red for a moment!</font>")
src.visible_message("<font color='red'>[bicon(src)] [src]'s eyes glow ruby red for a moment!</font>")
charges -= 0.1
//check on our shadow wights
@@ -54,7 +54,7 @@
var/list/options = list("[holder_atom] seems to be listening intently to [source]...",\
"[holder_atom] seems to be focusing on [source]...",\
"[holder_atom] seems to turn it's attention to [source]...")
holder_atom.loc.visible_message("<font color='blue'>\icon[holder_atom] [pick(options)]</font>")
holder_atom.loc.visible_message("<font color='blue'>[bicon(holder_atom)] [pick(options)]</font>")
if(prob(20))
spawn(2)
@@ -118,5 +118,5 @@
listening|=M
for(var/mob/M in listening)
to_chat(M, "\icon[holder_atom] <b>[holder_atom]</b> reverberates, \"<font color='blue'>[msg]</font>\"")
to_chat(M, "[bicon(holder_atom)] <b>[holder_atom]</b> reverberates, \"<font color='blue'>[msg]</font>\"")
last_talk_time = world.time
@@ -102,9 +102,9 @@
if(interval > 0)
//apply the touch effect to the holder
if(holder)
to_chat(holder, "the \icon[src] [src] held by [holder] shudders in your grasp.")
to_chat(holder, "the [bicon(src)] [src] held by [holder] shudders in your grasp.")
else
src.loc.visible_message("the \icon[src] [src] shudders.")
src.loc.visible_message("the [bicon(src)] [src] shudders.")
inserted_battery.battery_effect.DoEffectTouch(holder)
//consume power
@@ -130,13 +130,13 @@
//work out if we need to shutdown
if(inserted_battery.stored_charge <= 0)
src.loc.visible_message("<font color='blue'>\icon[src] [src] buzzes.</font>", "<font color='blue'>\icon[src] You hear something buzz.</font>")
src.loc.visible_message("<font color='blue'>[bicon(src)] [src] buzzes.</font>", "<font color='blue'>[bicon(src)] You hear something buzz.</font>")
shutdown_emission()
else if(world.time > time_end)
src.loc.visible_message("<font color='blue'>\icon[src] [src] chimes.</font>", "<font color='blue'>\icon[src] You hear something chime.</font>")
src.loc.visible_message("<font color='blue'>[bicon(src)] [src] chimes.</font>", "<font color='blue'>[bicon(src)] You hear something chime.</font>")
shutdown_emission()
else
src.visible_message("<font color='blue'>\icon[src] [src] buzzes.</font>", "<font color='blue'>\icon[src] You hear something buzz.</font>")
src.visible_message("<font color='blue'>[bicon(src)] [src] buzzes.</font>", "<font color='blue'>[bicon(src)] You hear something buzz.</font>")
shutdown_emission()
last_process = world.time
@@ -163,7 +163,7 @@
if(href_list["startup"])
if(inserted_battery && inserted_battery.battery_effect && (inserted_battery.stored_charge > 0) )
activated = 1
src.visible_message("<font color='blue'>\icon[src] [src] whirrs.</font>", "\icon[src]<font color='blue'>You hear something whirr.</font>")
src.visible_message("<font color='blue'>[bicon(src)] [src] whirrs.</font>", "[bicon(src)]<font color='blue'>You hear something whirr.</font>")
if(!inserted_battery.battery_effect.activated)
inserted_battery.battery_effect.ToggleActivate(1)
time_end = world.time + duration
@@ -74,7 +74,7 @@
P.name = "[src] report #[++report_num]"
P.info = "<b>[src] analysis report #[report_num]</b><br>"
P.info += "<br>"
P.info += "\icon[scanned_object] [results]"
P.info += "[bicon(scanned_object)] [results]"
P.stamped = list(/obj/item/weapon/stamp)
P.overlays = list("paper_stamped")
@@ -234,16 +234,16 @@
//emergency stop if seal integrity reaches 0
if(scanner_seal_integrity <= 0 || (scanner_temperature >= 1273 && !rad_shield))
stop_scanning()
src.visible_message("<font color='blue'>\icon[src] buzzes unhappily. It has failed mid-scan!</font>", 2)
src.visible_message("<font color='blue'>[bicon(src)] buzzes unhappily. It has failed mid-scan!</font>", 2)
if(prob(5))
src.visible_message("<font color='blue'>\icon[src] [pick("whirrs","chuffs","clicks")][pick(" excitedly"," energetically"," busily")].</font>", 2)
src.visible_message("<font color='blue'>[bicon(src)] [pick("whirrs","chuffs","clicks")][pick(" excitedly"," energetically"," busily")].</font>", 2)
else
//gradually cool down over time
if(scanner_temperature > 0)
scanner_temperature = max(scanner_temperature - 5 - 10 * rand(), 0)
if(prob(0.75))
src.visible_message("<font color='blue'>\icon[src] [pick("plinks","hisses")][pick(" quietly"," softly"," sadly"," plaintively")].</font>", 2)
src.visible_message("<font color='blue'>[bicon(src)] [pick("plinks","hisses")][pick(" quietly"," softly"," sadly"," plaintively")].</font>", 2)
playsound(loc, 'sound/effects/ding.ogg', 25)
last_process_worldtime = world.time
@@ -262,7 +262,7 @@
used_coolant = 0
/obj/machinery/radiocarbon_spectrometer/proc/complete_scan()
src.visible_message("<font color='blue'>\icon[src] makes an insistent chime.</font>", 2)
src.visible_message("<font color='blue'>[bicon(src)] makes an insistent chime.</font>", 2)
if(scanned_item)
//create report
@@ -182,10 +182,10 @@
for(var/mob/living/M in T)
M.weakened += 5
M.visible_message("<font color='blue'>\icon[M] [M] begins to float in the air!</font>","You feel tingly and light, but it is difficult to move.")
M.visible_message("<font color='blue'>[bicon(M)] [M] begins to float in the air!</font>","You feel tingly and light, but it is difficult to move.")
suspension_field = new(T)
src.visible_message("<font color='blue'>\icon[src] [src] activates with a low hum.</font>")
src.visible_message("<font color='blue'>[bicon(src)] [src] activates with a low hum.</font>")
icon_state = "suspension3"
for(var/obj/item/I in T)
@@ -195,7 +195,7 @@
if(collected)
suspension_field.icon_state = "energynet"
suspension_field.overlays += "shield2"
src.visible_message("<font color='blue'>\icon[suspension_field] [suspension_field] gently absconds [collected > 1 ? "something" : "several things"].</font>")
src.visible_message("<font color='blue'>[bicon(suspension_field)] [suspension_field] gently absconds [collected > 1 ? "something" : "several things"].</font>")
else
if(istype(T,/turf/simulated/mineral) || istype(T,/turf/simulated/wall))
suspension_field.icon_state = "shieldsparkles"
@@ -210,7 +210,7 @@
to_chat(M, "<span class='info'>You no longer feel like floating.</span>")
M.weakened = min(M.weakened, 3)
src.visible_message("<font color='blue'>\icon[src] [src] deactivates with a gentle shudder.</font>")
src.visible_message("<font color='blue'>[bicon(src)] [src] deactivates with a gentle shudder.</font>")
qdel(suspension_field)
suspension_field = null
icon_state = "suspension2"
+4 -4
View File
@@ -133,7 +133,7 @@
positive_locations.Add(D)
to_chat(user, "<span class='notice'>\icon[src] [src] pings.</span>")
to_chat(user, "<span class='notice'>[bicon(src)] [src] pings.</span>")
else if(istype(A, /obj/structure/boulder))
var/obj/structure/boulder/B = A
@@ -151,7 +151,7 @@
positive_locations.Add(D)
to_chat(user, "<span class='notice'>\icon[src] [src] pings [pick("madly","wildly","excitedly","crazily")]!</span>")
to_chat(user, "<span class='notice'>[bicon(src)] [src] pings [pick("madly","wildly","excitedly","crazily")]!</span>")
/obj/item/device/depth_scanner/attack_self(var/mob/living/user)
interact(user)
@@ -267,9 +267,9 @@
scan_ticks = 0
var/turf/T = get_turf(src)
if(target_radio)
T.visible_message("\icon[src] [src] [pick("chirps","chirrups","cheeps")] happily.")
T.visible_message("[bicon(src)] [src] [pick("chirps","chirrups","cheeps")] happily.")
else
T.visible_message("\icon[src] [src] [pick("chirps","chirrups","cheeps")] sadly.")
T.visible_message("[bicon(src)] [src] [pick("chirps","chirrups","cheeps")] sadly.")
else
icon_state = "pinoff"
+1 -1
View File
@@ -53,7 +53,7 @@
var/obj/item/slime_extract/T = holder.my_atom
T.uses--
if(T.uses <= 0)
T.visible_message("\icon[T]<span class='notice'>\The [T] goes inert.</span>")
T.visible_message("[bicon(T)]<span class='notice'>\The [T] goes inert.</span>")
T.name = "inert [initial(T.name)]"
@@ -99,7 +99,7 @@
/obj/machinery/slime/extractor/proc/extract_cores()
if(!src.occupant)
src.visible_message("\icon[src] [src] pings unhappily.")
src.visible_message("[bicon(src)] [src] pings unhappily.")
else if(inuse)
return
@@ -102,15 +102,15 @@
in_use = 0
if(failed_task)
failed_task = 0
visible_message("\icon[src] [src] pings unhappily, flashing a red warning light.")
visible_message("[bicon(src)] [src] pings unhappily, flashing a red warning light.")
else
visible_message("\icon[src] [src] pings happily.")
visible_message("[bicon(src)] [src] pings happily.")
if(eject_disk)
eject_disk = 0
if(loaded_disk)
loaded_disk.forceMove(get_turf(src))
visible_message("\icon[src] [src] beeps and spits out [loaded_disk].")
visible_message("[bicon(src)] [src] beeps and spits out [loaded_disk].")
loaded_disk = null
/obj/machinery/xenobio/extractor
@@ -190,7 +190,7 @@
/obj/machinery/xenobio/proc/eject_disk()
if(!loaded_disk) return
loaded_disk.forceMove(loc)
visible_message("\icon[src] [src] beeps and spits out [loaded_disk].")
visible_message("[bicon(src)] [src] beeps and spits out [loaded_disk].")
loaded_disk = null
/obj/machinery/xenobio/extractor/Topic(href, href_list)
@@ -202,7 +202,7 @@
if(!product) return
product.forceMove(get_turf(src))
visible_message("\icon[src] [src] beeps and spits out [product].")
visible_message("[bicon(src)] [src] beeps and spits out [product].")
product = null
if(href_list["eject_disk"])
@@ -63,7 +63,7 @@
/obj/machinery/slime/replicator/proc/replicate_slime()
if(!src.core)
src.visible_message("\icon[src] [src] pings unhappily.")
src.visible_message("[bicon(src)] [src] pings unhappily.")
else if(inuse)
return