mirror of
https://github.com/KabKebab/GS13.git
synced 2026-02-08 22:57:36 +00:00
@@ -1,4 +1,4 @@
|
||||
FROM tgstation/byond:512.1488 as base
|
||||
FROM tgstation/byond:513.1503 as base
|
||||
|
||||
FROM base as build_base
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define TYPEID_NULL "0"
|
||||
#define TYPEID_NORMAL_LIST "f"
|
||||
//helper macros
|
||||
#define GET_TYPEID(ref) ( ( (length(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, length(ref)-6) ) )
|
||||
#define GET_TYPEID(ref) ( ( (length(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, -7) ) )
|
||||
#define IS_NORMAL_LIST(L) (GET_TYPEID("\ref[L]") == TYPEID_NORMAL_LIST)
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
continue
|
||||
path += choice
|
||||
|
||||
if(copytext(path,-1,0) != "/") //didn't choose a directory, no need to iterate again
|
||||
if(copytext_char(path, -1) != "/") //didn't choose a directory, no need to iterate again
|
||||
break
|
||||
var/extensions
|
||||
for(var/i in valid_extensions)
|
||||
|
||||
@@ -977,7 +977,7 @@ world
|
||||
var/icon/atom_icon = new(A.icon, A.icon_state)
|
||||
|
||||
if(!letter)
|
||||
letter = copytext(A.name, 1, 2)
|
||||
letter = A.name[1]
|
||||
if(uppercase == 1)
|
||||
letter = uppertext(letter)
|
||||
else if(uppercase == -1)
|
||||
@@ -1105,7 +1105,7 @@ GLOBAL_LIST_INIT(freon_color_matrix, list("#2E5E69", "#60A2A8", "#A1AFB1", rgb(0
|
||||
WRITE_FILE(GLOB.iconCache[iconKey], icon)
|
||||
var/iconData = GLOB.iconCache.ExportText(iconKey)
|
||||
var/list/partial = splittext(iconData, "{")
|
||||
return replacetext(copytext(partial[2], 3, -5), "\n", "")
|
||||
return replacetext(copytext_char(partial[2], 3, -5), "\n", "")
|
||||
|
||||
/proc/icon2html(thing, target, icon_state, dir, frame = 1, moving = FALSE)
|
||||
if (!thing)
|
||||
|
||||
@@ -28,10 +28,10 @@
|
||||
. = "does"
|
||||
|
||||
/datum/proc/p_theyve(capitalized, temp_gender)
|
||||
. = p_they(capitalized, temp_gender) + "'" + copytext(p_have(temp_gender), 3)
|
||||
. = p_they(capitalized, temp_gender) + "'" + copytext_char(p_have(temp_gender), 3)
|
||||
|
||||
/datum/proc/p_theyre(capitalized, temp_gender)
|
||||
. = p_they(capitalized, temp_gender) + "'" + copytext(p_are(temp_gender), 2)
|
||||
. = p_they(capitalized, temp_gender) + "'" + copytext_char(p_are(temp_gender), 2)
|
||||
|
||||
/datum/proc/p_s(temp_gender) //is this a descriptive proc name, or what?
|
||||
. = "s"
|
||||
|
||||
@@ -43,24 +43,24 @@
|
||||
if(!istext(color))
|
||||
color = ""
|
||||
|
||||
var/start = 1 + (text2ascii(color,1)==35)
|
||||
var/start = 1 + (text2ascii(color, 1) == 35)
|
||||
var/len = length(color)
|
||||
var/step_size = 1 + ((len+1)-start != desired_format)
|
||||
var/char = ""
|
||||
|
||||
. = ""
|
||||
for(var/i=start, i<=len, i+=step_size)
|
||||
var/ascii = text2ascii(color,i)
|
||||
switch(ascii)
|
||||
if(48 to 57)
|
||||
. += ascii2text(ascii) //numbers 0 to 9
|
||||
if(97 to 102)
|
||||
. += ascii2text(ascii) //letters a to f
|
||||
if(65 to 70)
|
||||
. += ascii2text(ascii+32) //letters A to F - translates to lowercase
|
||||
for(var/i = start, i <= len, i += length(char))
|
||||
char = color[i]
|
||||
switch(text2ascii(char))
|
||||
if(48 to 57) //numbers 0 to 9
|
||||
. += char
|
||||
if(97 to 102) //letters a to f
|
||||
. += char
|
||||
if(65 to 70) //letters A to F - translates to lowercase
|
||||
. += lowertext(char)
|
||||
else
|
||||
break
|
||||
|
||||
if(length(.) != desired_format)
|
||||
if(length_char(.) != desired_format)
|
||||
if(default)
|
||||
return default
|
||||
return crunch + repeat_string(desired_format, "0")
|
||||
@@ -68,7 +68,9 @@
|
||||
return crunch + .
|
||||
|
||||
/proc/sanitize_ooccolor(color)
|
||||
var/list/HSL = rgb2hsl(hex2num(copytext(color,2,4)),hex2num(copytext(color,4,6)),hex2num(copytext(color,6,8)))
|
||||
if(length(color) != length_char(color))
|
||||
CRASH("Invalid characters in color '[color]'")
|
||||
var/list/HSL = rgb2hsl(hex2num(copytext(color, 2, 4)), hex2num(copytext(color, 4, 6)), hex2num(copytext(color, 6, 8)))
|
||||
HSL[3] = min(HSL[3],0.4)
|
||||
var/list/RGB = hsl2rgb(arglist(HSL))
|
||||
return "#[num2hex(RGB[1],2)][num2hex(RGB[2],2)][num2hex(RGB[3],2)]"
|
||||
@@ -52,6 +52,6 @@
|
||||
if(bad_chars)
|
||||
bad_match = url_encode(bad_chars_regex.match)
|
||||
scrubbed_url += bad_match
|
||||
last_good = bad_chars + length(bad_match)
|
||||
last_good = bad_chars + length(bad_chars_regex.match)
|
||||
while(bad_chars)
|
||||
. = scrubbed_url
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,14 +8,15 @@
|
||||
index = findtext(t, char)
|
||||
return t
|
||||
|
||||
proc/TextPreview(var/string,var/len=40)
|
||||
if(length(string) <= len)
|
||||
if(!length(string))
|
||||
/proc/TextPreview(string, len = 40)
|
||||
var/char_len = length_char(string)
|
||||
if(char_len <= len)
|
||||
if(char_len)
|
||||
return "\[...\]"
|
||||
else
|
||||
return string
|
||||
else
|
||||
return "[copytext(string, 1, 37)]..."
|
||||
return "[copytext_char(string, 1, 37)]..."
|
||||
|
||||
GLOBAL_LIST_EMPTY(mentorlog)
|
||||
GLOBAL_PROTECT(mentorlog)
|
||||
|
||||
@@ -532,17 +532,17 @@
|
||||
|
||||
//assumes format #RRGGBB #rrggbb
|
||||
/proc/color_hex2num(A)
|
||||
if(!A)
|
||||
if(!A || length(A) != length_char(A))
|
||||
return 0
|
||||
var/R = hex2num(copytext(A,2,4))
|
||||
var/G = hex2num(copytext(A,4,6))
|
||||
var/B = hex2num(copytext(A,6,0))
|
||||
var/R = hex2num(copytext(A, 2, 4))
|
||||
var/G = hex2num(copytext(A, 4, 6))
|
||||
var/B = hex2num(copytext(A, 6, 0))
|
||||
return R+G+B
|
||||
|
||||
//word of warning: using a matrix like this as a color value will simplify it back to a string after being set
|
||||
/proc/color_hex2color_matrix(string)
|
||||
var/length = length(string)
|
||||
if(length != 7 && length != 9)
|
||||
if((length != 7 && length != 9) || length != length_char(string))
|
||||
return color_matrix_identity()
|
||||
var/r = hex2num(copytext(string, 2, 4))/255
|
||||
var/g = hex2num(copytext(string, 4, 6))/255
|
||||
|
||||
@@ -6,25 +6,18 @@
|
||||
|
||||
//Inverts the colour of an HTML string
|
||||
/proc/invertHTML(HTMLstring)
|
||||
|
||||
if (!( istext(HTMLstring) ))
|
||||
if(!istext(HTMLstring))
|
||||
CRASH("Given non-text argument!")
|
||||
return
|
||||
else
|
||||
if (length(HTMLstring) != 7)
|
||||
CRASH("Given non-HTML argument!")
|
||||
return
|
||||
else if(length(HTMLstring) != 7)
|
||||
CRASH("Given non-HTML argument!")
|
||||
return
|
||||
else if(length_char(HTMLstring) != 7)
|
||||
CRASH("Given non-hex symbols in argument!")
|
||||
var/textr = copytext(HTMLstring, 2, 4)
|
||||
var/textg = copytext(HTMLstring, 4, 6)
|
||||
var/textb = copytext(HTMLstring, 6, 8)
|
||||
var/r = hex2num(textr)
|
||||
var/g = hex2num(textg)
|
||||
var/b = hex2num(textb)
|
||||
textr = num2hex(255 - r, 2)
|
||||
textg = num2hex(255 - g, 2)
|
||||
textb = num2hex(255 - b, 2)
|
||||
return text("#[][][]", textr, textg, textb)
|
||||
return
|
||||
return rgb(255 - hex2num(textr), 255 - hex2num(textg), 255 - hex2num(textb))
|
||||
|
||||
/proc/Get_Angle(atom/movable/start,atom/movable/end)//For beams.
|
||||
if(!start || !end)
|
||||
@@ -184,15 +177,15 @@ Turf and target are separate in case you want to teleport some distance from a t
|
||||
//Returns whether or not a player is a guest using their ckey as an input
|
||||
/proc/IsGuestKey(key)
|
||||
if (findtext(key, "Guest-", 1, 7) != 1) //was findtextEx
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
var/i, ch, len = length(key)
|
||||
|
||||
for (i = 7, i <= len, ++i)
|
||||
for (i = 7, i <= len, ++i) //we know the first 6 chars are Guest-
|
||||
ch = text2ascii(key, i)
|
||||
if (ch < 48 || ch > 57)
|
||||
return 0
|
||||
return 1
|
||||
if (ch < 48 || ch > 57) //0-9
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
//Generalised helper proc for letting mobs rename themselves. Used to be clname() and ainame()
|
||||
/mob/proc/apply_pref_name(role, client/C)
|
||||
@@ -1421,7 +1414,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
|
||||
/proc/GUID()
|
||||
var/const/GUID_VERSION = "b"
|
||||
var/const/GUID_VARIANT = "d"
|
||||
var/node_id = copytext(md5("[rand()*rand(1,9999999)][world.name][world.hub][world.hub_password][world.internet_address][world.address][world.contents.len][world.status][world.port][rand()*rand(1,9999999)]"), 1, 13)
|
||||
var/node_id = copytext_char(md5("[rand()*rand(1,9999999)][world.name][world.hub][world.hub_password][world.internet_address][world.address][world.contents.len][world.status][world.port][rand()*rand(1,9999999)]"), 1, 13)
|
||||
|
||||
var/time_high = "[num2hex(text2num(time2text(world.realtime,"YYYY")), 2)][num2hex(world.realtime, 6)]"
|
||||
|
||||
|
||||
@@ -39,6 +39,26 @@
|
||||
#error You need version 512 or higher
|
||||
#endif
|
||||
|
||||
//Compatability -- These procs were added in 513.1493, not 513.1490
|
||||
//Which really shoulda bumped us up to 514 right then and there but instead Lummox is a dumb dumb
|
||||
#if DM_BUILD < 1493
|
||||
#define length_char(args...) length(args)
|
||||
#define text2ascii_char(args...) text2ascii(args)
|
||||
#define copytext_char(args...) copytext(args)
|
||||
#define splittext_char(args...) splittext(args)
|
||||
#define spantext_char(args...) spantext(args)
|
||||
#define nonspantext_char(args...) nonspantext(args)
|
||||
#define findtext_char(args...) findtext(args)
|
||||
#define findtextEx_char(args...) findtextEx(args)
|
||||
#define findlasttext_char(args...) findlasttext(args)
|
||||
#define findlasttextEx_char(args...) findlasttextEx(args)
|
||||
#define replacetext_char(args...) replacetext(args)
|
||||
#define replacetextEx_char(args...) replacetextEx(args)
|
||||
// /regex procs
|
||||
#define Find_char(args...) Find(args)
|
||||
#define Replace_char(args...) Replace(args)
|
||||
#endif
|
||||
|
||||
//Additional code for the above flags.
|
||||
#ifdef TESTING
|
||||
#warn compiling in TESTING mode. testing() debug messages will be visible.
|
||||
|
||||
@@ -166,7 +166,8 @@
|
||||
key_name = copytext(str_val, 1, key_pos)
|
||||
if(lowercase)
|
||||
key_name = lowertext(key_name)
|
||||
key_value = copytext(str_val, key_pos + 1)
|
||||
if(key_pos)
|
||||
key_value = copytext(str_val, key_pos + length(str_val[key_pos]))
|
||||
var/new_key
|
||||
var/new_value
|
||||
var/continue_check_value
|
||||
|
||||
@@ -106,13 +106,13 @@
|
||||
if(!L)
|
||||
continue
|
||||
|
||||
var/firstchar = copytext(L, 1, 2)
|
||||
var/firstchar = L[1]
|
||||
if(firstchar == "#")
|
||||
continue
|
||||
|
||||
var/lockthis = firstchar == "@"
|
||||
if(lockthis)
|
||||
L = copytext(L, 2)
|
||||
L = copytext(L, length(firstchar) + 1)
|
||||
|
||||
var/pos = findtext(L, " ")
|
||||
var/entry = null
|
||||
@@ -120,7 +120,7 @@
|
||||
|
||||
if(pos)
|
||||
entry = lowertext(copytext(L, 1, pos))
|
||||
value = copytext(L, pos + 1)
|
||||
value = copytext(L, pos + length(L[pos]))
|
||||
else
|
||||
entry = lowertext(L)
|
||||
|
||||
@@ -256,7 +256,7 @@
|
||||
t = trim(t)
|
||||
if(length(t) == 0)
|
||||
continue
|
||||
else if(copytext(t, 1, 2) == "#")
|
||||
else if(t[1] == "#")
|
||||
continue
|
||||
|
||||
var/pos = findtext(t, " ")
|
||||
@@ -265,7 +265,7 @@
|
||||
|
||||
if(pos)
|
||||
command = lowertext(copytext(t, 1, pos))
|
||||
data = copytext(t, pos + 1)
|
||||
data = copytext(t, pos + length(t[pos]))
|
||||
else
|
||||
command = lowertext(t)
|
||||
|
||||
|
||||
@@ -39,34 +39,34 @@ SUBSYSTEM_DEF(pai)
|
||||
|
||||
switch(option)
|
||||
if("name")
|
||||
t = input("Enter a name for your pAI", "pAI Name", candidate.name) as text
|
||||
t = reject_bad_name(stripped_input(usr, "Enter a name for your pAI", "pAI Name", candidate.name, MAX_NAME_LEN), TRUE)
|
||||
if(t)
|
||||
candidate.name = copytext(sanitize(t),1,MAX_NAME_LEN)
|
||||
candidate.name = t
|
||||
if("desc")
|
||||
t = input("Enter a description for your pAI", "pAI Description", candidate.description) as message
|
||||
t = stripped_multiline_input(usr, "Enter a description for your pAI", "pAI Description", candidate.description, MAX_MESSAGE_LEN)
|
||||
if(t)
|
||||
candidate.description = copytext(sanitize(t),1,MAX_MESSAGE_LEN)
|
||||
candidate.description = t
|
||||
if("role")
|
||||
t = input("Enter a role for your pAI", "pAI Role", candidate.role) as text
|
||||
t = stripped_input(usr, "Enter a role for your pAI", "pAI Role", candidate.role, MAX_MESSAGE_LEN)
|
||||
if(t)
|
||||
candidate.role = copytext(sanitize(t),1,MAX_MESSAGE_LEN)
|
||||
candidate.role = t
|
||||
if("ooc")
|
||||
t = input("Enter any OOC comments", "pAI OOC Comments", candidate.comments) as message
|
||||
t = stripped_multiline_input(usr, "Enter any OOC comments", "pAI OOC Comments", candidate.comments, MAX_MESSAGE_LEN)
|
||||
if(t)
|
||||
candidate.comments = copytext(sanitize(t),1,MAX_MESSAGE_LEN)
|
||||
candidate.comments = t
|
||||
if("save")
|
||||
candidate.savefile_save(usr)
|
||||
if("load")
|
||||
candidate.savefile_load(usr)
|
||||
//In case people have saved unsanitized stuff.
|
||||
if(candidate.name)
|
||||
candidate.name = copytext(sanitize(candidate.name),1,MAX_NAME_LEN)
|
||||
candidate.name = copytext_char(sanitize(candidate.name),1,MAX_NAME_LEN)
|
||||
if(candidate.description)
|
||||
candidate.description = copytext(sanitize(candidate.description),1,MAX_MESSAGE_LEN)
|
||||
candidate.description = copytext_char(sanitize(candidate.description),1,MAX_MESSAGE_LEN)
|
||||
if(candidate.role)
|
||||
candidate.role = copytext(sanitize(candidate.role),1,MAX_MESSAGE_LEN)
|
||||
candidate.role = copytext_char(sanitize(candidate.role),1,MAX_MESSAGE_LEN)
|
||||
if(candidate.comments)
|
||||
candidate.comments = copytext(sanitize(candidate.comments),1,MAX_MESSAGE_LEN)
|
||||
candidate.comments = copytext_char(sanitize(candidate.comments),1,MAX_MESSAGE_LEN)
|
||||
|
||||
if("submit")
|
||||
if(candidate)
|
||||
|
||||
@@ -46,6 +46,6 @@ PROCESSING_SUBSYSTEM_DEF(networks)
|
||||
var/hex = md5(string)
|
||||
if(!hex)
|
||||
return //errored
|
||||
. = "[copytext(hex, 1, 9)]" //16 ^ 8 possibilities I think.
|
||||
. = "[copytext_char(hex, 1, 9)]" //16 ^ 8 possibilities I think.
|
||||
if(interfaces_by_id[.])
|
||||
return resolve_collisions? make_address("[num2text(rand(HID_RESTRICTED_END, 999999999), 12)]"):null
|
||||
|
||||
@@ -155,7 +155,7 @@
|
||||
to_chat(src, compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source))
|
||||
|
||||
/mob/camera/imaginary_friend/proc/friend_talk(message)
|
||||
message = capitalize(trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)))
|
||||
message = capitalize(trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN)))
|
||||
|
||||
if(!message)
|
||||
return
|
||||
|
||||
@@ -199,13 +199,16 @@
|
||||
var/list/new_message = list()
|
||||
|
||||
for(var/word in message_split)
|
||||
var/suffix = copytext(word,-1)
|
||||
var/suffix = ""
|
||||
var/suffix_foundon = 0
|
||||
for(var/potential_suffix in list("." , "," , ";" , "!" , ":" , "?"))
|
||||
suffix_foundon = findtext(word, potential_suffix, -length(potential_suffix))
|
||||
if(suffix_foundon)
|
||||
suffix = potential_suffix
|
||||
break
|
||||
|
||||
// Check if we have a suffix and break it out of the word
|
||||
if(suffix in list("." , "," , ";" , "!" , ":" , "?"))
|
||||
word = copytext(word,1,-1)
|
||||
else
|
||||
suffix = ""
|
||||
if(suffix_foundon)
|
||||
word = copytext(word, 1, suffix_foundon)
|
||||
|
||||
word = html_decode(word)
|
||||
|
||||
@@ -216,10 +219,9 @@
|
||||
new_message += pick("uh","erm")
|
||||
break
|
||||
else
|
||||
var/list/charlist = string2charlist(word) // Stupid shit code
|
||||
var/list/charlist = text2charlist(word)
|
||||
shuffle_inplace(charlist)
|
||||
charlist.len = round(charlist.len * 0.5,1)
|
||||
new_message += html_encode(jointext(charlist,"")) + suffix
|
||||
new_message += jointext(charlist, "") + suffix
|
||||
|
||||
message = jointext(new_message, " ")
|
||||
|
||||
|
||||
@@ -476,14 +476,14 @@
|
||||
|
||||
/proc/getleftblocks(input,blocknumber,blocksize)
|
||||
if(blocknumber > 1)
|
||||
return copytext(input,1,((blocksize*blocknumber)-(blocksize-1)))
|
||||
return copytext_char(input,1,((blocksize*blocknumber)-(blocksize-1)))
|
||||
|
||||
/proc/getrightblocks(input,blocknumber,blocksize)
|
||||
if(blocknumber < (length(input)/blocksize))
|
||||
return copytext(input,blocksize*blocknumber+1,length(input)+1)
|
||||
return copytext_char(input,blocksize*blocknumber+1,length(input)+1)
|
||||
|
||||
/proc/getblock(input, blocknumber, blocksize=DNA_BLOCK_SIZE)
|
||||
return copytext(input, blocksize*(blocknumber-1)+1, (blocksize*blocknumber)+1)
|
||||
return copytext_char(input, blocksize*(blocknumber-1)+1, (blocksize*blocknumber)+1)
|
||||
|
||||
/proc/setblock(istring, blocknumber, replacement, blocksize=DNA_BLOCK_SIZE)
|
||||
if(!istring || !blocknumber || !replacement || !blocksize)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
var/list/mob_type_ignore_stat_typecache
|
||||
var/stat_allowed = CONSCIOUS
|
||||
var/static/list/emote_list = list()
|
||||
var/static/regex/stop_bad_mime = regex(@"says|exclaims|yells|asks")
|
||||
|
||||
/datum/emote/New()
|
||||
if(key_third_person)
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
for(var/line in testmerge)
|
||||
var/datum/tgs_revision_information/test_merge/tm = line
|
||||
var/cm = tm.pull_request_commit
|
||||
var/details = ": '" + html_encode(tm.title) + "' by " + html_encode(tm.author) + " at commit " + html_encode(copytext(cm, 1, min(length(cm), 11)))
|
||||
var/details = ": '" + html_encode(tm.title) + "' by " + html_encode(tm.author) + " at commit " + html_encode(copytext_char(cm, 1, 11))
|
||||
if(details && findtext(details, "\[s\]") && (!usr || !usr.client.holder))
|
||||
continue
|
||||
. += "<a href=\"[CONFIG_GET(string/githuburl)]/pull/[tm.number]\">#[tm.number][details]</a><br>"
|
||||
@@ -57,11 +57,11 @@
|
||||
// Round ID
|
||||
if(GLOB.round_id)
|
||||
msg += "<b>Round ID:</b> [GLOB.round_id]"
|
||||
|
||||
|
||||
msg += "<b>BYOND Version:</b> [world.byond_version].[world.byond_build]"
|
||||
if(DM_VERSION != world.byond_version || DM_BUILD != world.byond_build)
|
||||
msg += "<b>Compiled with BYOND Version:</b> [DM_VERSION].[DM_BUILD]"
|
||||
|
||||
|
||||
// Revision information
|
||||
var/datum/getrev/revdata = GLOB.revdata
|
||||
msg += "<b>Server revision compiled on:</b> [revdata.date]"
|
||||
|
||||
@@ -257,8 +257,8 @@
|
||||
var/splitpoint = findtext(prepared_line," ")
|
||||
if(!splitpoint)
|
||||
continue
|
||||
var/command = copytext(prepared_line,1,splitpoint)
|
||||
var/value = copytext(prepared_line,splitpoint+1)
|
||||
var/command = copytext(prepared_line, 1, splitpoint)
|
||||
var/value = copytext(prepared_line, splitpoint + length(prepared_line[splitpoint]))
|
||||
switch(command)
|
||||
if("DELAY")
|
||||
var/delay_value = text2num(value)
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
restraining = 0
|
||||
streak = streak+element
|
||||
if(length(streak) > max_streak_length)
|
||||
streak = copytext(streak,2)
|
||||
streak = copytext(streak, 1 + length(streak[1]))
|
||||
return
|
||||
|
||||
/datum/martial_art/proc/basic_hit(mob/living/carbon/human/A,mob/living/carbon/human/D)
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
L.update_arousal_hud() //Removes the old icon
|
||||
|
||||
/datum/mind/proc/store_memory(new_text)
|
||||
if((length(memory) + length(new_text)) <= MAX_MESSAGE_LEN)
|
||||
if((length_char(memory) + length_char(new_text)) <= MAX_MESSAGE_LEN)
|
||||
memory += "[new_text]<BR>"
|
||||
|
||||
/datum/mind/proc/wipe_memory()
|
||||
@@ -411,7 +411,7 @@
|
||||
assigned_role = new_role
|
||||
|
||||
else if (href_list["memory_edit"])
|
||||
var/new_memo = copytext(sanitize(input("Write new memory", "Memory", memory) as null|message),1,MAX_MESSAGE_LEN)
|
||||
var/new_memo = stripped_multiline_input(usr, "Write new memory", "Memory", memory, MAX_MESSAGE_LEN)
|
||||
if (isnull(new_memo))
|
||||
return
|
||||
memory = new_memo
|
||||
|
||||
@@ -88,8 +88,8 @@
|
||||
var/list/entry = list()
|
||||
entry["parent"] = "[type]"
|
||||
entry["name"] = verbpath.desc
|
||||
if (copytext(verbpath.name,1,2) == "@")
|
||||
entry["command"] = copytext(verbpath.name,2)
|
||||
if (verbpath.name[1] == "@")
|
||||
entry["command"] = copytext(verbpath.name, length(verbpath.name[1]) + 1)
|
||||
else
|
||||
entry["command"] = replacetext(verbpath.name, " ", "-")
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
return TRUE
|
||||
|
||||
/datum/wires/proc/is_dud(wire)
|
||||
return dd_hasprefix(wire, WIRE_DUD_PREFIX)
|
||||
return findtext(wire, WIRE_DUD_PREFIX)
|
||||
|
||||
/datum/wires/proc/is_dud_color(color)
|
||||
return is_dud(get_wire(color))
|
||||
|
||||
@@ -487,7 +487,7 @@
|
||||
|
||||
R.fields["ckey"] = mob_occupant.ckey
|
||||
R.fields["name"] = mob_occupant.real_name
|
||||
R.fields["id"] = copytext(md5(mob_occupant.real_name), 2, 6)
|
||||
R.fields["id"] = copytext_char(md5(mob_occupant.real_name), 2, 6)
|
||||
R.fields["UE"] = dna.unique_enzymes
|
||||
R.fields["UI"] = dna.uni_identity
|
||||
R.fields["SE"] = dna.mutation_index
|
||||
|
||||
@@ -449,7 +449,7 @@
|
||||
var/dat = ""
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_CALL)
|
||||
var/timeleft = SSshuttle.emergency.timeLeft()
|
||||
dat += "<B>Emergency shuttle</B>\n<BR>\nETA: [timeleft / 60 % 60]:[add_zero(num2text(timeleft % 60), 2)]"
|
||||
dat += "<B>Emergency shuttle</B>\n<BR>\nETA: [timeleft / 60 % 60]:[add_leading(num2text(timeleft % 60), 2, "0")]"
|
||||
|
||||
|
||||
var/datum/browser/popup = new(user, "communications", "Communications Console", 400, 500)
|
||||
|
||||
@@ -650,7 +650,7 @@
|
||||
viable_occupant.radiation += (RADIATION_IRRADIATION_MULTIPLIER*radduration*radstrength)/(connected.damage_coeff ** 2) //Read comment in "transferbuffer" section above for explanation
|
||||
switch(href_list["task"]) //Same thing as there but values are even lower, on best part they are about 0.0*, effectively no damage
|
||||
if("pulseui")
|
||||
var/len = length(viable_occupant.dna.uni_identity)
|
||||
var/len = length_char(viable_occupant.dna.uni_identity)
|
||||
num = WRAP(num, 1, len+1)
|
||||
num = randomize_radiation_accuracy(num, radduration + (connected.precision_coeff ** 2), len) //Each manipulator level above 1 makes randomization as accurate as selected time + manipulator lvl^2
|
||||
//Value is this high for the same reason as with laser - not worth the hassle of upgrading if the bonus is low
|
||||
@@ -658,12 +658,12 @@
|
||||
var/subblock = num - block*DNA_BLOCK_SIZE
|
||||
last_change = "UI #[block]-[subblock]; "
|
||||
|
||||
var/hex = copytext(viable_occupant.dna.uni_identity, num, num+1)
|
||||
var/hex = copytext_char(viable_occupant.dna.uni_identity, num, num+1)
|
||||
last_change += "[hex]"
|
||||
hex = scramble(hex, radstrength, radduration)
|
||||
last_change += "->[hex]"
|
||||
|
||||
viable_occupant.dna.uni_identity = copytext(viable_occupant.dna.uni_identity, 1, num) + hex + copytext(viable_occupant.dna.uni_identity, num+1, 0)
|
||||
viable_occupant.dna.uni_identity = copytext_char(viable_occupant.dna.uni_identity, 1, num) + hex + copytext_char(viable_occupant.dna.uni_identity, num + 1)
|
||||
viable_occupant.updateappearance(mutations_overlay_update=1)
|
||||
else
|
||||
current_screen = "mainmenu"
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
to_chat(usr, "<span class='danger'>Unauthorized access.</span>")
|
||||
|
||||
else if(href_list["warn"])
|
||||
var/warning = copytext(sanitize(input(usr,"Message:","Enter your message here!","")),1,MAX_MESSAGE_LEN)
|
||||
var/warning = stripped_input(usr, "Message:", "Enter your message here!", "", MAX_MESSAGE_LEN)
|
||||
if(!warning)
|
||||
return
|
||||
var/obj/item/implant/I = locate(href_list["warn"]) in GLOB.tracked_implants
|
||||
|
||||
@@ -543,7 +543,7 @@ What a mess.*/
|
||||
switch(href_list["field"])
|
||||
if("name")
|
||||
if(istype(active1, /datum/data/record) || istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(sanitize(input("Please input name:", "Secure. records", active1.fields["name"], null) as text),1,MAX_MESSAGE_LEN)
|
||||
var/t1 = stripped_input(usr, "Please input name:", "Secure. records", active1.fields["name"], MAX_MESSAGE_LEN)
|
||||
if(!canUseSecurityRecordsConsole(usr, t1, a1))
|
||||
return
|
||||
if(istype(active1, /datum/data/record))
|
||||
|
||||
@@ -168,7 +168,7 @@
|
||||
if(timing)
|
||||
var/disp1 = id
|
||||
var/time_left = time_left(seconds = TRUE)
|
||||
var/disp2 = "[add_zero(num2text((time_left / 60) % 60),2)]~[add_zero(num2text(time_left % 60), 2)]"
|
||||
var/disp2 = "[add_leading(num2text((time_left / 60) % 60), 2, "0")]:[add_leading(num2text(time_left % 60), 2, "0")]"
|
||||
if(length(disp2) > CHARS_PER_LINE)
|
||||
disp2 = "Error"
|
||||
update_display(disp1, disp2)
|
||||
|
||||
@@ -306,7 +306,7 @@
|
||||
if(speed <= 0)
|
||||
speed = 1
|
||||
if("setpath")
|
||||
var/newpath = copytext(sanitize(input(usr, "Please define a new path!",,path) as text|null),1,MAX_MESSAGE_LEN)
|
||||
var/newpath = stripped_input(usr, "Please define a new path!", "New Path", path, MAX_MESSAGE_LEN)
|
||||
if(newpath && newpath != "")
|
||||
moving = 0 // stop moving
|
||||
path = newpath
|
||||
@@ -368,13 +368,19 @@
|
||||
// Generates the rpath variable using the path string, think of this as "string2list"
|
||||
// Doesn't use params2list() because of the akward way it stacks entities
|
||||
rpath = list() // clear rpath
|
||||
var/maximum_character = min( 50, length(path) ) // chooses the maximum length of the iterator. 50 max length
|
||||
var/maximum_characters = 50
|
||||
|
||||
for(var/i=1, i<=maximum_character, i++) // iterates through all characters in path
|
||||
var/lentext = length(path)
|
||||
var/nextchar = ""
|
||||
var/charcount = 0
|
||||
|
||||
var/nextchar = copytext(path, i, i+1) // find next character
|
||||
|
||||
if(!(nextchar in list(";", "&", "*", " "))) // if char is a separator, ignore
|
||||
rpath += copytext(path, i, i+1) // else, add to list
|
||||
for(var/i = 1, i <= lentext, i += length(nextchar)) // iterates through all characters in path
|
||||
nextchar = path[i] // find next character
|
||||
|
||||
if(nextchar in list(";", "&", "*", " ")) // if char is a separator, ignore
|
||||
continue
|
||||
rpath += nextchar // else, add to list
|
||||
// there doesn't HAVE to be separators but it makes paths syntatically visible
|
||||
charcount++
|
||||
if(charcount >= maximum_characters)
|
||||
break
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
var/index = findtext(e, "=") // format is "key=value"
|
||||
if(index)
|
||||
var/key = copytext(e, 1, index)
|
||||
var/val = copytext(e, index+1)
|
||||
var/val = copytext(e, index + length(e[index]))
|
||||
codes[key] = val
|
||||
else
|
||||
codes[e] = "1"
|
||||
@@ -167,7 +167,7 @@ Transponder Codes:<UL>"}
|
||||
usr.set_machine(src)
|
||||
|
||||
if(href_list["locedit"])
|
||||
var/newloc = copytext(sanitize(input("Enter New Location", "Navigation Beacon", location) as text|null),1,MAX_MESSAGE_LEN)
|
||||
var/newloc = stripped_input(usr, "Enter New Location", "Navigation Beacon", location, MAX_MESSAGE_LEN)
|
||||
if(newloc)
|
||||
location = newloc
|
||||
updateDialog()
|
||||
|
||||
@@ -162,7 +162,7 @@ GLOBAL_LIST_EMPTY(allCasters)
|
||||
NEWSCASTER.update_icon()
|
||||
|
||||
/datum/newscaster/feed_network/proc/save_photo(icon/photo)
|
||||
var/photo_file = copytext(md5("\icon[photo]"), 1, 6)
|
||||
var/photo_file = copytext_char(md5("\icon[photo]"), 1, 6)
|
||||
if(!fexists("[GLOB.log_directory]/photos/[photo_file].png"))
|
||||
//Clean up repeated frames
|
||||
var/icon/clean = new /icon()
|
||||
@@ -514,8 +514,6 @@ GLOBAL_LIST_EMPTY(allCasters)
|
||||
scan_user(usr)
|
||||
if(href_list["set_channel_name"])
|
||||
channel_name = stripped_input(usr, "Provide a Feed Channel Name", "Network Channel Handler", "", MAX_NAME_LEN)
|
||||
while (findtext(channel_name," ") == 1)
|
||||
channel_name = copytext(channel_name,2,length(channel_name)+1)
|
||||
updateUsrDialog()
|
||||
else if(href_list["set_channel_lock"])
|
||||
c_locked = !c_locked
|
||||
@@ -690,7 +688,7 @@ GLOBAL_LIST_EMPTY(allCasters)
|
||||
updateUsrDialog()
|
||||
else if(href_list["new_comment"])
|
||||
var/datum/newscaster/feed_message/FM = locate(href_list["new_comment"])
|
||||
var/cominput = copytext(stripped_input(usr, "Write your message:", "New comment", null),1,141)
|
||||
var/cominput = copytext_char(stripped_input(usr, "Write your message:", "New comment", null), 140)
|
||||
if(cominput)
|
||||
scan_user(usr)
|
||||
var/datum/newscaster/feed_comment/FC = new/datum/newscaster/feed_comment
|
||||
|
||||
@@ -263,10 +263,9 @@ GLOBAL_LIST_EMPTY(allConsoles)
|
||||
usr.set_machine(src)
|
||||
add_fingerprint(usr)
|
||||
|
||||
if(reject_bad_text(href_list["write"]))
|
||||
dpt = ckey(href_list["write"]) //write contains the string of the receiving department's name
|
||||
|
||||
var/new_message = copytext(reject_bad_text(input(usr, "Write your message:", "Awaiting Input", "")),1,MAX_MESSAGE_LEN)
|
||||
if(href_list["write"])
|
||||
dpt = ckey(reject_bad_text(href_list["write"])) //write contains the string of the receiving department's name
|
||||
var/new_message = stripped_input(usr, "Write your message:", "Awaiting Input", "", MAX_MESSAGE_LEN)
|
||||
if(new_message)
|
||||
message = new_message
|
||||
screen = 9
|
||||
@@ -282,7 +281,7 @@ GLOBAL_LIST_EMPTY(allConsoles)
|
||||
priority = -1
|
||||
|
||||
if(href_list["writeAnnouncement"])
|
||||
var/new_message = copytext(reject_bad_text(input(usr, "Write your message:", "Awaiting Input", "")),1,MAX_MESSAGE_LEN)
|
||||
var/new_message = reject_bad_text(stripped_input(usr, "Write your message:", "Awaiting Input", "", MAX_MESSAGE_LEN))
|
||||
if(new_message)
|
||||
message = new_message
|
||||
if (text2num(href_list["priority"]) < 2)
|
||||
@@ -438,9 +437,8 @@ GLOBAL_LIST_EMPTY(allConsoles)
|
||||
return
|
||||
|
||||
/obj/machinery/requests_console/say_mod(input, message_mode)
|
||||
var/ending = copytext(input, length(input) - 2)
|
||||
if (ending == "!!!")
|
||||
. = "blares"
|
||||
if(spantext_char(input, "!", -3))
|
||||
return "blares"
|
||||
else
|
||||
. = ..()
|
||||
|
||||
|
||||
@@ -1,368 +1,368 @@
|
||||
// Status display
|
||||
// (formerly Countdown timer display)
|
||||
|
||||
#define CHARS_PER_LINE 5
|
||||
#define FONT_SIZE "5pt"
|
||||
#define FONT_COLOR "#09f"
|
||||
#define FONT_STYLE "Arial Black"
|
||||
#define SCROLL_SPEED 2
|
||||
|
||||
#define SD_BLANK 0 // 0 = Blank
|
||||
#define SD_EMERGENCY 1 // 1 = Emergency Shuttle timer
|
||||
#define SD_MESSAGE 2 // 2 = Arbitrary message(s)
|
||||
#define SD_PICTURE 3 // 3 = alert picture
|
||||
|
||||
#define SD_AI_EMOTE 1 // 1 = AI emoticon
|
||||
#define SD_AI_BSOD 2 // 2 = Blue screen of death
|
||||
|
||||
/// Status display which can show images and scrolling text.
|
||||
/obj/machinery/status_display
|
||||
name = "status display"
|
||||
desc = null
|
||||
icon = 'icons/obj/status_display.dmi'
|
||||
icon_state = "frame"
|
||||
density = FALSE
|
||||
use_power = IDLE_POWER_USE
|
||||
idle_power_usage = 10
|
||||
|
||||
maptext_height = 26
|
||||
maptext_width = 32
|
||||
|
||||
var/message1 = "" // message line 1
|
||||
var/message2 = "" // message line 2
|
||||
var/index1 // display index for scrolling messages or 0 if non-scrolling
|
||||
var/index2
|
||||
|
||||
/// Immediately blank the display.
|
||||
/obj/machinery/status_display/proc/remove_display()
|
||||
cut_overlays()
|
||||
if(maptext)
|
||||
maptext = ""
|
||||
|
||||
/// Immediately change the display to the given picture.
|
||||
/obj/machinery/status_display/proc/set_picture(state)
|
||||
remove_display()
|
||||
add_overlay(state)
|
||||
|
||||
/// Immediately change the display to the given two lines.
|
||||
/obj/machinery/status_display/proc/update_display(line1, line2)
|
||||
var/new_text = {"<div style="font-size:[FONT_SIZE];color:[FONT_COLOR];font:'[FONT_STYLE]';text-align:center;" valign="top">[line1]<br>[line2]</div>"}
|
||||
if(maptext != new_text)
|
||||
maptext = new_text
|
||||
|
||||
/// Prepare the display to marquee the given two lines.
|
||||
///
|
||||
/// Call with no arguments to disable.
|
||||
/obj/machinery/status_display/proc/set_message(m1, m2)
|
||||
if(m1)
|
||||
index1 = (length(m1) > CHARS_PER_LINE)
|
||||
message1 = m1
|
||||
else
|
||||
message1 = ""
|
||||
index1 = 0
|
||||
|
||||
if(m2)
|
||||
index2 = (length(m2) > CHARS_PER_LINE)
|
||||
message2 = m2
|
||||
else
|
||||
message2 = ""
|
||||
index2 = 0
|
||||
|
||||
// Timed process - performs default marquee action if so needed.
|
||||
/obj/machinery/status_display/process()
|
||||
if(stat & NOPOWER)
|
||||
// No power, no processing.
|
||||
remove_display()
|
||||
return PROCESS_KILL
|
||||
|
||||
var/line1 = message1
|
||||
if(index1)
|
||||
line1 = copytext("[message1]|[message1]", index1, index1+CHARS_PER_LINE)
|
||||
var/message1_len = length(message1)
|
||||
index1 += SCROLL_SPEED
|
||||
if(index1 > message1_len)
|
||||
index1 -= message1_len
|
||||
|
||||
var/line2 = message2
|
||||
if(index2)
|
||||
line2 = copytext("[message2]|[message2]", index2, index2+CHARS_PER_LINE)
|
||||
var/message2_len = length(message2)
|
||||
index2 += SCROLL_SPEED
|
||||
if(index2 > message2_len)
|
||||
index2 -= message2_len
|
||||
|
||||
update_display(line1, line2)
|
||||
if (!index1 && !index2)
|
||||
// No marquee, no processing.
|
||||
return PROCESS_KILL
|
||||
|
||||
/// Update the display and, if necessary, re-enable processing.
|
||||
/obj/machinery/status_display/proc/update()
|
||||
if (process() != PROCESS_KILL)
|
||||
START_PROCESSING(SSmachines, src)
|
||||
|
||||
/obj/machinery/status_display/power_change()
|
||||
. = ..()
|
||||
update()
|
||||
|
||||
/obj/machinery/status_display/emp_act(severity)
|
||||
. = ..()
|
||||
if(stat & (NOPOWER|BROKEN) || . & EMP_PROTECT_SELF)
|
||||
return
|
||||
set_picture("ai_bsod")
|
||||
|
||||
/obj/machinery/status_display/examine(mob/user)
|
||||
. = ..()
|
||||
if (message1 || message2)
|
||||
. += "The display says:"
|
||||
if (message1)
|
||||
. += "\t<tt>[html_encode(message1)]</tt>"
|
||||
if (message2)
|
||||
. += "\t<tt>[html_encode(message2)]</tt>"
|
||||
|
||||
// Helper procs for child display types.
|
||||
/obj/machinery/status_display/proc/display_shuttle_status(obj/docking_port/mobile/shuttle)
|
||||
if(!shuttle)
|
||||
// the shuttle is missing - no processing
|
||||
update_display("shutl?","")
|
||||
return PROCESS_KILL
|
||||
else if(shuttle.timer)
|
||||
var/line1 = "-[shuttle.getModeStr()]-"
|
||||
var/line2 = shuttle.getTimerStr()
|
||||
|
||||
if(length(line2) > CHARS_PER_LINE)
|
||||
line2 = "error"
|
||||
update_display(line1, line2)
|
||||
else
|
||||
// don't kill processing, the timer might turn back on
|
||||
remove_display()
|
||||
|
||||
/obj/machinery/status_display/proc/examine_shuttle(mob/user, obj/docking_port/mobile/shuttle)
|
||||
if (shuttle)
|
||||
var/modestr = shuttle.getModeStr()
|
||||
if (modestr)
|
||||
if (shuttle.timer)
|
||||
modestr = "<br>\t<tt>[modestr]: [shuttle.getTimerStr()]</tt>"
|
||||
else
|
||||
modestr = "<br>\t<tt>[modestr]</tt>"
|
||||
return "The display says:<br>\t<tt>[shuttle.name]</tt>[modestr]"
|
||||
else
|
||||
return "The display says:<br>\t<tt>Shuttle missing!</tt>"
|
||||
|
||||
|
||||
/// Evac display which shows shuttle timer or message set by Command.
|
||||
/obj/machinery/status_display/evac
|
||||
var/frequency = FREQ_STATUS_DISPLAYS
|
||||
var/mode = SD_EMERGENCY
|
||||
var/friendc = FALSE // track if Friend Computer mode
|
||||
var/last_picture // For when Friend Computer mode is undone
|
||||
|
||||
/obj/machinery/status_display/evac/Initialize()
|
||||
. = ..()
|
||||
// register for radio system
|
||||
SSradio.add_object(src, frequency)
|
||||
|
||||
/obj/machinery/status_display/evac/Destroy()
|
||||
SSradio.remove_object(src,frequency)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/status_display/evac/process()
|
||||
if(stat & NOPOWER)
|
||||
// No power, no processing.
|
||||
remove_display()
|
||||
return PROCESS_KILL
|
||||
|
||||
if(friendc) //Makes all status displays except supply shuttle timer display the eye -- Urist
|
||||
set_picture("ai_friend")
|
||||
return PROCESS_KILL
|
||||
|
||||
switch(mode)
|
||||
if(SD_BLANK)
|
||||
remove_display()
|
||||
return PROCESS_KILL
|
||||
|
||||
if(SD_EMERGENCY)
|
||||
return display_shuttle_status(SSshuttle.emergency)
|
||||
|
||||
if(SD_MESSAGE)
|
||||
return ..()
|
||||
|
||||
if(SD_PICTURE)
|
||||
set_picture(last_picture)
|
||||
return PROCESS_KILL
|
||||
|
||||
/obj/machinery/status_display/evac/examine(mob/user)
|
||||
. = ..()
|
||||
if(mode == SD_EMERGENCY)
|
||||
. += examine_shuttle(user, SSshuttle.emergency)
|
||||
else if(!message1 && !message2)
|
||||
. += "The display is blank."
|
||||
|
||||
/obj/machinery/status_display/evac/receive_signal(datum/signal/signal)
|
||||
switch(signal.data["command"])
|
||||
if("blank")
|
||||
mode = SD_BLANK
|
||||
set_message(null, null)
|
||||
if("shuttle")
|
||||
mode = SD_EMERGENCY
|
||||
set_message(null, null)
|
||||
if("message")
|
||||
mode = SD_MESSAGE
|
||||
set_message(signal.data["msg1"], signal.data["msg2"])
|
||||
if("alert")
|
||||
mode = SD_PICTURE
|
||||
last_picture = signal.data["picture_state"]
|
||||
set_picture(last_picture)
|
||||
if("friendcomputer")
|
||||
friendc = !friendc
|
||||
update()
|
||||
|
||||
|
||||
/// Supply display which shows the status of the supply shuttle.
|
||||
/obj/machinery/status_display/supply
|
||||
name = "supply display"
|
||||
|
||||
/obj/machinery/status_display/supply/process()
|
||||
if(stat & NOPOWER)
|
||||
// No power, no processing.
|
||||
remove_display()
|
||||
return PROCESS_KILL
|
||||
|
||||
var/line1
|
||||
var/line2
|
||||
if(!SSshuttle.supply)
|
||||
// Might be missing in our first update on initialize before shuttles
|
||||
// have loaded. Cross our fingers that it will soon return.
|
||||
line1 = "CARGO"
|
||||
line2 = "shutl?"
|
||||
else if(SSshuttle.supply.mode == SHUTTLE_IDLE)
|
||||
if(is_station_level(SSshuttle.supply.z))
|
||||
line1 = "CARGO"
|
||||
line2 = "Docked"
|
||||
else
|
||||
line1 = "CARGO"
|
||||
line2 = SSshuttle.supply.getTimerStr()
|
||||
if(length(line2) > CHARS_PER_LINE)
|
||||
line2 = "Error"
|
||||
update_display(line1, line2)
|
||||
|
||||
/obj/machinery/status_display/supply/examine(mob/user)
|
||||
. = ..()
|
||||
var/obj/docking_port/mobile/shuttle = SSshuttle.supply
|
||||
var/shuttleMsg = null
|
||||
if (shuttle.mode == SHUTTLE_IDLE)
|
||||
if (is_station_level(shuttle.z))
|
||||
shuttleMsg = "Docked"
|
||||
else
|
||||
shuttleMsg = "[shuttle.getModeStr()]: [shuttle.getTimerStr()]"
|
||||
if (shuttleMsg)
|
||||
. += "The display says:<br>\t<tt>[shuttleMsg]</tt>"
|
||||
else
|
||||
. += "The display is blank."
|
||||
|
||||
|
||||
/// General-purpose shuttle status display.
|
||||
/obj/machinery/status_display/shuttle
|
||||
name = "shuttle display"
|
||||
var/shuttle_id
|
||||
|
||||
/obj/machinery/status_display/shuttle/process()
|
||||
if(!shuttle_id || (stat & NOPOWER))
|
||||
// No power, no processing.
|
||||
remove_display()
|
||||
return PROCESS_KILL
|
||||
|
||||
return display_shuttle_status(SSshuttle.getShuttle(shuttle_id))
|
||||
|
||||
/obj/machinery/status_display/shuttle/examine(mob/user)
|
||||
. = ..()
|
||||
if(shuttle_id)
|
||||
. += examine_shuttle(user, SSshuttle.getShuttle(shuttle_id))
|
||||
else
|
||||
. += "The display is blank."
|
||||
|
||||
/obj/machinery/status_display/shuttle/vv_edit_var(var_name, var_value)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
switch(var_name)
|
||||
if("shuttle_id")
|
||||
update()
|
||||
|
||||
/obj/machinery/status_display/shuttle/proc/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override)
|
||||
if (port && (shuttle_id == initial(shuttle_id) || override))
|
||||
shuttle_id = port.id
|
||||
update()
|
||||
|
||||
|
||||
/// Pictograph display which the AI can use to emote.
|
||||
/obj/machinery/status_display/ai
|
||||
name = "\improper AI display"
|
||||
desc = "A small screen which the AI can use to present itself."
|
||||
|
||||
var/mode = SD_BLANK
|
||||
var/emotion = "Neutral"
|
||||
|
||||
/obj/machinery/status_display/ai/Initialize()
|
||||
. = ..()
|
||||
GLOB.ai_status_displays.Add(src)
|
||||
|
||||
/obj/machinery/status_display/ai/Destroy()
|
||||
GLOB.ai_status_displays.Remove(src)
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/status_display/ai/attack_ai(mob/living/silicon/ai/user)
|
||||
if(isAI(user))
|
||||
user.ai_statuschange()
|
||||
|
||||
/obj/machinery/status_display/ai/process()
|
||||
if(mode == SD_BLANK || (stat & NOPOWER))
|
||||
remove_display()
|
||||
return PROCESS_KILL
|
||||
|
||||
if(mode == SD_AI_EMOTE)
|
||||
switch(emotion)
|
||||
if("Very Happy")
|
||||
set_picture("ai_veryhappy")
|
||||
if("Happy")
|
||||
set_picture("ai_happy")
|
||||
if("Neutral")
|
||||
set_picture("ai_neutral")
|
||||
if("Unsure")
|
||||
set_picture("ai_unsure")
|
||||
if("Confused")
|
||||
set_picture("ai_confused")
|
||||
if("Sad")
|
||||
set_picture("ai_sad")
|
||||
if("BSOD")
|
||||
set_picture("ai_bsod")
|
||||
if("Blank")
|
||||
set_picture("ai_off")
|
||||
if("Problems?")
|
||||
set_picture("ai_trollface")
|
||||
if("Awesome")
|
||||
set_picture("ai_awesome")
|
||||
if("Dorfy")
|
||||
set_picture("ai_urist")
|
||||
if("Thinking")
|
||||
set_picture("ai_thinking")
|
||||
if("Facepalm")
|
||||
set_picture("ai_facepalm")
|
||||
if("Friend Computer")
|
||||
set_picture("ai_friend")
|
||||
if("Blue Glow")
|
||||
set_picture("ai_sal")
|
||||
if("Red Glow")
|
||||
set_picture("ai_hal")
|
||||
return PROCESS_KILL
|
||||
|
||||
if(mode == SD_AI_BSOD)
|
||||
set_picture("ai_bsod")
|
||||
return PROCESS_KILL
|
||||
|
||||
|
||||
#undef CHARS_PER_LINE
|
||||
#undef FONT_SIZE
|
||||
#undef FONT_COLOR
|
||||
#undef FONT_STYLE
|
||||
#undef SCROLL_SPEED
|
||||
// Status display
|
||||
// (formerly Countdown timer display)
|
||||
|
||||
#define CHARS_PER_LINE 5
|
||||
#define FONT_SIZE "5pt"
|
||||
#define FONT_COLOR "#09f"
|
||||
#define FONT_STYLE "Arial Black"
|
||||
#define SCROLL_SPEED 2
|
||||
|
||||
#define SD_BLANK 0 // 0 = Blank
|
||||
#define SD_EMERGENCY 1 // 1 = Emergency Shuttle timer
|
||||
#define SD_MESSAGE 2 // 2 = Arbitrary message(s)
|
||||
#define SD_PICTURE 3 // 3 = alert picture
|
||||
|
||||
#define SD_AI_EMOTE 1 // 1 = AI emoticon
|
||||
#define SD_AI_BSOD 2 // 2 = Blue screen of death
|
||||
|
||||
/// Status display which can show images and scrolling text.
|
||||
/obj/machinery/status_display
|
||||
name = "status display"
|
||||
desc = null
|
||||
icon = 'icons/obj/status_display.dmi'
|
||||
icon_state = "frame"
|
||||
density = FALSE
|
||||
use_power = IDLE_POWER_USE
|
||||
idle_power_usage = 10
|
||||
|
||||
maptext_height = 26
|
||||
maptext_width = 32
|
||||
|
||||
var/message1 = "" // message line 1
|
||||
var/message2 = "" // message line 2
|
||||
var/index1 // display index for scrolling messages or 0 if non-scrolling
|
||||
var/index2
|
||||
|
||||
/// Immediately blank the display.
|
||||
/obj/machinery/status_display/proc/remove_display()
|
||||
cut_overlays()
|
||||
if(maptext)
|
||||
maptext = ""
|
||||
|
||||
/// Immediately change the display to the given picture.
|
||||
/obj/machinery/status_display/proc/set_picture(state)
|
||||
remove_display()
|
||||
add_overlay(state)
|
||||
|
||||
/// Immediately change the display to the given two lines.
|
||||
/obj/machinery/status_display/proc/update_display(line1, line2)
|
||||
var/new_text = {"<div style="font-size:[FONT_SIZE];color:[FONT_COLOR];font:'[FONT_STYLE]';text-align:center;" valign="top">[line1]<br>[line2]</div>"}
|
||||
if(maptext != new_text)
|
||||
maptext = new_text
|
||||
|
||||
/// Prepare the display to marquee the given two lines.
|
||||
///
|
||||
/// Call with no arguments to disable.
|
||||
/obj/machinery/status_display/proc/set_message(m1, m2)
|
||||
if(m1)
|
||||
index1 = (length_char(m1) > CHARS_PER_LINE)
|
||||
message1 = m1
|
||||
else
|
||||
message1 = ""
|
||||
index1 = 0
|
||||
|
||||
if(m2)
|
||||
index2 = (length_char(m2) > CHARS_PER_LINE)
|
||||
message2 = m2
|
||||
else
|
||||
message2 = ""
|
||||
index2 = 0
|
||||
|
||||
// Timed process - performs default marquee action if so needed.
|
||||
/obj/machinery/status_display/process()
|
||||
if(stat & NOPOWER)
|
||||
// No power, no processing.
|
||||
remove_display()
|
||||
return PROCESS_KILL
|
||||
|
||||
var/line1 = message1
|
||||
if(index1)
|
||||
line1 = copytext_char("[message1]|[message1]", index1, index1+CHARS_PER_LINE)
|
||||
var/message1_len = length_char(message1)
|
||||
index1 += SCROLL_SPEED
|
||||
if(index1 > message1_len + 1)
|
||||
index1 -= (message1_len + 1)
|
||||
|
||||
var/line2 = message2
|
||||
if(index2)
|
||||
line2 = copytext_char("[message2]|[message2]", index2, index2+CHARS_PER_LINE)
|
||||
var/message2_len = length(message2)
|
||||
index2 += SCROLL_SPEED
|
||||
if(index2 > message2_len + 1)
|
||||
index2 -= (message2_len + 1)
|
||||
|
||||
update_display(line1, line2)
|
||||
if (!index1 && !index2)
|
||||
// No marquee, no processing.
|
||||
return PROCESS_KILL
|
||||
|
||||
/// Update the display and, if necessary, re-enable processing.
|
||||
/obj/machinery/status_display/proc/update()
|
||||
if (process() != PROCESS_KILL)
|
||||
START_PROCESSING(SSmachines, src)
|
||||
|
||||
/obj/machinery/status_display/power_change()
|
||||
. = ..()
|
||||
update()
|
||||
|
||||
/obj/machinery/status_display/emp_act(severity)
|
||||
. = ..()
|
||||
if(stat & (NOPOWER|BROKEN) || . & EMP_PROTECT_SELF)
|
||||
return
|
||||
set_picture("ai_bsod")
|
||||
|
||||
/obj/machinery/status_display/examine(mob/user)
|
||||
. = ..()
|
||||
if (message1 || message2)
|
||||
. += "The display says:"
|
||||
if (message1)
|
||||
. += "\t<tt>[html_encode(message1)]</tt>"
|
||||
if (message2)
|
||||
. += "\t<tt>[html_encode(message2)]</tt>"
|
||||
|
||||
// Helper procs for child display types.
|
||||
/obj/machinery/status_display/proc/display_shuttle_status(obj/docking_port/mobile/shuttle)
|
||||
if(!shuttle)
|
||||
// the shuttle is missing - no processing
|
||||
update_display("shutl?","")
|
||||
return PROCESS_KILL
|
||||
else if(shuttle.timer)
|
||||
var/line1 = "-[shuttle.getModeStr()]-"
|
||||
var/line2 = shuttle.getTimerStr()
|
||||
|
||||
if(length_char(line2) > CHARS_PER_LINE)
|
||||
line2 = "error"
|
||||
update_display(line1, line2)
|
||||
else
|
||||
// don't kill processing, the timer might turn back on
|
||||
remove_display()
|
||||
|
||||
/obj/machinery/status_display/proc/examine_shuttle(mob/user, obj/docking_port/mobile/shuttle)
|
||||
if (shuttle)
|
||||
var/modestr = shuttle.getModeStr()
|
||||
if (modestr)
|
||||
if (shuttle.timer)
|
||||
modestr = "<br>\t<tt>[modestr]: [shuttle.getTimerStr()]</tt>"
|
||||
else
|
||||
modestr = "<br>\t<tt>[modestr]</tt>"
|
||||
return "The display says:<br>\t<tt>[shuttle.name]</tt>[modestr]"
|
||||
else
|
||||
return "The display says:<br>\t<tt>Shuttle missing!</tt>"
|
||||
|
||||
|
||||
/// Evac display which shows shuttle timer or message set by Command.
|
||||
/obj/machinery/status_display/evac
|
||||
var/frequency = FREQ_STATUS_DISPLAYS
|
||||
var/mode = SD_EMERGENCY
|
||||
var/friendc = FALSE // track if Friend Computer mode
|
||||
var/last_picture // For when Friend Computer mode is undone
|
||||
|
||||
/obj/machinery/status_display/evac/Initialize()
|
||||
. = ..()
|
||||
// register for radio system
|
||||
SSradio.add_object(src, frequency)
|
||||
|
||||
/obj/machinery/status_display/evac/Destroy()
|
||||
SSradio.remove_object(src,frequency)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/status_display/evac/process()
|
||||
if(stat & NOPOWER)
|
||||
// No power, no processing.
|
||||
remove_display()
|
||||
return PROCESS_KILL
|
||||
|
||||
if(friendc) //Makes all status displays except supply shuttle timer display the eye -- Urist
|
||||
set_picture("ai_friend")
|
||||
return PROCESS_KILL
|
||||
|
||||
switch(mode)
|
||||
if(SD_BLANK)
|
||||
remove_display()
|
||||
return PROCESS_KILL
|
||||
|
||||
if(SD_EMERGENCY)
|
||||
return display_shuttle_status(SSshuttle.emergency)
|
||||
|
||||
if(SD_MESSAGE)
|
||||
return ..()
|
||||
|
||||
if(SD_PICTURE)
|
||||
set_picture(last_picture)
|
||||
return PROCESS_KILL
|
||||
|
||||
/obj/machinery/status_display/evac/examine(mob/user)
|
||||
. = ..()
|
||||
if(mode == SD_EMERGENCY)
|
||||
. += examine_shuttle(user, SSshuttle.emergency)
|
||||
else if(!message1 && !message2)
|
||||
. += "The display is blank."
|
||||
|
||||
/obj/machinery/status_display/evac/receive_signal(datum/signal/signal)
|
||||
switch(signal.data["command"])
|
||||
if("blank")
|
||||
mode = SD_BLANK
|
||||
set_message(null, null)
|
||||
if("shuttle")
|
||||
mode = SD_EMERGENCY
|
||||
set_message(null, null)
|
||||
if("message")
|
||||
mode = SD_MESSAGE
|
||||
set_message(signal.data["msg1"], signal.data["msg2"])
|
||||
if("alert")
|
||||
mode = SD_PICTURE
|
||||
last_picture = signal.data["picture_state"]
|
||||
set_picture(last_picture)
|
||||
if("friendcomputer")
|
||||
friendc = !friendc
|
||||
update()
|
||||
|
||||
|
||||
/// Supply display which shows the status of the supply shuttle.
|
||||
/obj/machinery/status_display/supply
|
||||
name = "supply display"
|
||||
|
||||
/obj/machinery/status_display/supply/process()
|
||||
if(stat & NOPOWER)
|
||||
// No power, no processing.
|
||||
remove_display()
|
||||
return PROCESS_KILL
|
||||
|
||||
var/line1
|
||||
var/line2
|
||||
if(!SSshuttle.supply)
|
||||
// Might be missing in our first update on initialize before shuttles
|
||||
// have loaded. Cross our fingers that it will soon return.
|
||||
line1 = "CARGO"
|
||||
line2 = "shutl?"
|
||||
else if(SSshuttle.supply.mode == SHUTTLE_IDLE)
|
||||
if(is_station_level(SSshuttle.supply.z))
|
||||
line1 = "CARGO"
|
||||
line2 = "Docked"
|
||||
else
|
||||
line1 = "CARGO"
|
||||
line2 = SSshuttle.supply.getTimerStr()
|
||||
if(length_char(line2) > CHARS_PER_LINE)
|
||||
line2 = "Error"
|
||||
update_display(line1, line2)
|
||||
|
||||
/obj/machinery/status_display/supply/examine(mob/user)
|
||||
. = ..()
|
||||
var/obj/docking_port/mobile/shuttle = SSshuttle.supply
|
||||
var/shuttleMsg = null
|
||||
if (shuttle.mode == SHUTTLE_IDLE)
|
||||
if (is_station_level(shuttle.z))
|
||||
shuttleMsg = "Docked"
|
||||
else
|
||||
shuttleMsg = "[shuttle.getModeStr()]: [shuttle.getTimerStr()]"
|
||||
if (shuttleMsg)
|
||||
. += "The display says:<br>\t<tt>[shuttleMsg]</tt>"
|
||||
else
|
||||
. += "The display is blank."
|
||||
|
||||
|
||||
/// General-purpose shuttle status display.
|
||||
/obj/machinery/status_display/shuttle
|
||||
name = "shuttle display"
|
||||
var/shuttle_id
|
||||
|
||||
/obj/machinery/status_display/shuttle/process()
|
||||
if(!shuttle_id || (stat & NOPOWER))
|
||||
// No power, no processing.
|
||||
remove_display()
|
||||
return PROCESS_KILL
|
||||
|
||||
return display_shuttle_status(SSshuttle.getShuttle(shuttle_id))
|
||||
|
||||
/obj/machinery/status_display/shuttle/examine(mob/user)
|
||||
. = ..()
|
||||
if(shuttle_id)
|
||||
. += examine_shuttle(user, SSshuttle.getShuttle(shuttle_id))
|
||||
else
|
||||
. += "The display is blank."
|
||||
|
||||
/obj/machinery/status_display/shuttle/vv_edit_var(var_name, var_value)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
switch(var_name)
|
||||
if("shuttle_id")
|
||||
update()
|
||||
|
||||
/obj/machinery/status_display/shuttle/proc/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override)
|
||||
if (port && (shuttle_id == initial(shuttle_id) || override))
|
||||
shuttle_id = port.id
|
||||
update()
|
||||
|
||||
|
||||
/// Pictograph display which the AI can use to emote.
|
||||
/obj/machinery/status_display/ai
|
||||
name = "\improper AI display"
|
||||
desc = "A small screen which the AI can use to present itself."
|
||||
|
||||
var/mode = SD_BLANK
|
||||
var/emotion = "Neutral"
|
||||
|
||||
/obj/machinery/status_display/ai/Initialize()
|
||||
. = ..()
|
||||
GLOB.ai_status_displays.Add(src)
|
||||
|
||||
/obj/machinery/status_display/ai/Destroy()
|
||||
GLOB.ai_status_displays.Remove(src)
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/status_display/ai/attack_ai(mob/living/silicon/ai/user)
|
||||
if(isAI(user))
|
||||
user.ai_statuschange()
|
||||
|
||||
/obj/machinery/status_display/ai/process()
|
||||
if(mode == SD_BLANK || (stat & NOPOWER))
|
||||
remove_display()
|
||||
return PROCESS_KILL
|
||||
|
||||
if(mode == SD_AI_EMOTE)
|
||||
switch(emotion)
|
||||
if("Very Happy")
|
||||
set_picture("ai_veryhappy")
|
||||
if("Happy")
|
||||
set_picture("ai_happy")
|
||||
if("Neutral")
|
||||
set_picture("ai_neutral")
|
||||
if("Unsure")
|
||||
set_picture("ai_unsure")
|
||||
if("Confused")
|
||||
set_picture("ai_confused")
|
||||
if("Sad")
|
||||
set_picture("ai_sad")
|
||||
if("BSOD")
|
||||
set_picture("ai_bsod")
|
||||
if("Blank")
|
||||
set_picture("ai_off")
|
||||
if("Problems?")
|
||||
set_picture("ai_trollface")
|
||||
if("Awesome")
|
||||
set_picture("ai_awesome")
|
||||
if("Dorfy")
|
||||
set_picture("ai_urist")
|
||||
if("Thinking")
|
||||
set_picture("ai_thinking")
|
||||
if("Facepalm")
|
||||
set_picture("ai_facepalm")
|
||||
if("Friend Computer")
|
||||
set_picture("ai_friend")
|
||||
if("Blue Glow")
|
||||
set_picture("ai_sal")
|
||||
if("Red Glow")
|
||||
set_picture("ai_hal")
|
||||
return PROCESS_KILL
|
||||
|
||||
if(mode == SD_AI_BSOD)
|
||||
set_picture("ai_bsod")
|
||||
return PROCESS_KILL
|
||||
|
||||
|
||||
#undef CHARS_PER_LINE
|
||||
#undef FONT_SIZE
|
||||
#undef FONT_COLOR
|
||||
#undef FONT_STYLE
|
||||
#undef SCROLL_SPEED
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
set waitfor = FALSE
|
||||
|
||||
// Perform final composition steps on the message.
|
||||
var/message = copytext(data["message"], 1, MAX_BROADCAST_LEN)
|
||||
var/message = copytext_char(data["message"], 1, MAX_BROADCAST_LEN)
|
||||
if(!message)
|
||||
return
|
||||
var/compression = data["compression"]
|
||||
|
||||
@@ -179,7 +179,7 @@
|
||||
|
||||
|
||||
if("id")
|
||||
var/newid = copytext(reject_bad_text(input(usr, "Specify the new ID for this machine", src, id) as null|text),1,MAX_MESSAGE_LEN)
|
||||
var/newid = reject_bad_text(stripped_input(usr, "Specify the new ID for this machine", src, id, MAX_MESSAGE_LEN))
|
||||
if(newid && canAccess(usr))
|
||||
id = newid
|
||||
temp = "<font color = #666633>-% New ID assigned: \"[id]\" %-</font color>"
|
||||
|
||||
@@ -441,7 +441,7 @@
|
||||
return ..()
|
||||
|
||||
/obj/machinery/mecha_part_fabricator/proc/material2name(ID)
|
||||
return copytext(ID,2)
|
||||
return copytext_char(ID,2)
|
||||
|
||||
/obj/machinery/mecha_part_fabricator/proc/is_insertion_ready(mob/user)
|
||||
if(panel_open)
|
||||
|
||||
@@ -299,11 +299,11 @@
|
||||
onclose(occupant, "exosuit_log")
|
||||
|
||||
if (href_list["change_name"])
|
||||
var/newname = stripped_input(occupant,"Choose new exosuit name","Rename exosuit","", MAX_NAME_LEN)
|
||||
if(newname && trim(newname))
|
||||
name = newname
|
||||
else
|
||||
alert(occupant, "nope.avi")
|
||||
var/userinput = stripped_input(occupant,"Choose new exosuit name","Rename exosuit","", MAX_NAME_LEN)
|
||||
if(!userinput || usr != occupant || usr.incapacitated())
|
||||
return
|
||||
name = userinput
|
||||
return
|
||||
|
||||
if (href_list["toggle_id_upload"])
|
||||
add_req_access = !add_req_access
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
if (smooth & SMOOTH_DIAGONAL)
|
||||
for (var/O in overlays)
|
||||
var/image/I = O
|
||||
if (copytext(I.icon_state, 1, 3) == "d-")
|
||||
if(copytext(I.icon_state, 1, 3) == "d-") //3 == length("d-") + 1
|
||||
return
|
||||
|
||||
var/stuff_on_wall = 0
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -407,7 +407,7 @@
|
||||
to_chat(user, "<span class='notice'>You spray a [temp] on \the [target.name]</span>")
|
||||
|
||||
if(length(text_buffer) > 1)
|
||||
text_buffer = copytext(text_buffer,2)
|
||||
text_buffer = copytext(text_buffer, length(text_buffer[1]) + 1)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
if(post_noise)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -308,9 +308,14 @@ Code:
|
||||
var/list/S = list(" Off","AOff"," On", " AOn")
|
||||
var/list/chg = list("N","C","F")
|
||||
|
||||
//Neither copytext nor copytext_char is appropriate here; neither 30 UTF-8 code units nor 30 code points equates to 30 columns of output.
|
||||
//Some glyphs are very tall or very wide while others are small or even take up no space at all.
|
||||
//Emojis can take modifiers which are many characters but render as only one glyph.
|
||||
//A proper solution here (as far as Unicode goes, maybe not ideal as far as markup goes, a table would be better)
|
||||
//would be to use <span style="width: NNNpx; overflow: none;">[A.area.name]</span>
|
||||
for(var/obj/machinery/power/apc/A in L)
|
||||
menu += copytext(add_tspace(A.area.name, 30), 1, 30)
|
||||
menu += " [S[A.equipment+1]] [S[A.lighting+1]] [S[A.environ+1]] [add_lspace(DisplayPower(A.lastused_total), 6)] [A.cell ? "[add_lspace(round(A.cell.percent()), 3)]% [chg[A.charging+1]]" : " N/C"]<BR>"
|
||||
menu += copytext_char(add_trailing(A.area.name, 30, " "), 1, 30)
|
||||
menu += " [S[A.equipment+1]] [S[A.lighting+1]] [S[A.environ+1]] [add_leading(DisplayPower(A.lastused_total), 6, " ")] [A.cell ? "[add_leading(round(A.cell.percent()), 3, " ")]% [chg[A.charging+1]]" : " N/C"]<BR>"
|
||||
|
||||
menu += "</FONT></PRE>"
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
if(pai.radio)
|
||||
pai.radio.wires.cut(wire)
|
||||
if(href_list["setlaws"])
|
||||
var/newlaws = copytext(sanitize(input("Enter any additional directives you would like your pAI personality to follow. Note that these directives will not override the personality's allegiance to its imprinted master. Conflicting directives will be ignored.", "pAI Directive Configuration", pai.laws.supplied[1]) as message),1,MAX_MESSAGE_LEN)
|
||||
var/newlaws = stripped_multiline_input("Enter any additional directives you would like your pAI personality to follow. Note that these directives will not override the personality's allegiance to its imprinted master. Conflicting directives will be ignored.", "pAI Directive Configuration", MAX_MESSAGE_LEN)
|
||||
if(newlaws && pai)
|
||||
pai.add_supplied_law(0,newlaws)
|
||||
if(href_list["toggle_holo"])
|
||||
|
||||
@@ -1,146 +1,146 @@
|
||||
/obj/item/electropack
|
||||
name = "electropack"
|
||||
desc = "Dance my monkeys! DANCE!!!"
|
||||
icon = 'icons/obj/radio.dmi'
|
||||
icon_state = "electropack0"
|
||||
item_state = "electropack"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
flags_1 = CONDUCT_1
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
materials = list(MAT_METAL=10000, MAT_GLASS=2500)
|
||||
|
||||
var/code = 2
|
||||
var/frequency = FREQ_ELECTROPACK
|
||||
var/on = TRUE
|
||||
var/shock_cooldown = FALSE
|
||||
|
||||
/obj/item/electropack/suicide_act(mob/living/carbon/user)
|
||||
user.visible_message("<span class='suicide'>[user] hooks [user.p_them()]self to the electropack and spams the trigger! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
return (FIRELOSS)
|
||||
|
||||
/obj/item/electropack/Initialize()
|
||||
. = ..()
|
||||
set_frequency(frequency)
|
||||
|
||||
/obj/item/electropack/Destroy()
|
||||
SSradio.remove_object(src, frequency)
|
||||
. = ..()
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/electropack/attack_hand(mob/user)
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
if(src == C.back)
|
||||
to_chat(user, "<span class='warning'>You need help taking this off!</span>")
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/item/electropack/attackby(obj/item/W, mob/living/user, params)
|
||||
if(istype(W, /obj/item/clothing/head/helmet))
|
||||
var/obj/item/assembly/shock_kit/A = new /obj/item/assembly/shock_kit(user)
|
||||
A.icon = 'icons/obj/assemblies.dmi'
|
||||
|
||||
if(!user.transferItemToLoc(W, A))
|
||||
to_chat(user, "<span class='warning'>[W] is stuck to your hand, you cannot attach it to [src]!</span>")
|
||||
return
|
||||
W.master = A
|
||||
A.part1 = W
|
||||
|
||||
user.transferItemToLoc(src, A, TRUE)
|
||||
master = A
|
||||
A.part2 = src
|
||||
|
||||
user.put_in_hands(A)
|
||||
A.add_fingerprint(user)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/electropack/Topic(href, href_list)
|
||||
var/mob/living/carbon/C = usr
|
||||
if(usr.stat || usr.restrained() || C.back == src)
|
||||
return
|
||||
|
||||
if(!usr.canUseTopic(src, BE_CLOSE))
|
||||
usr << browse(null, "window=radio")
|
||||
onclose(usr, "radio")
|
||||
return
|
||||
|
||||
if(href_list["set"])
|
||||
if(href_list["set"] == "freq")
|
||||
var/new_freq = input(usr, "Input a new receiving frequency", "Electropack Frequency", format_frequency(frequency)) as num|null
|
||||
if(!usr.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
new_freq = unformat_frequency(new_freq)
|
||||
new_freq = sanitize_frequency(new_freq, TRUE)
|
||||
set_frequency(new_freq)
|
||||
|
||||
if(href_list["set"] == "code")
|
||||
var/new_code = input(usr, "Input a new receiving code", "Electropack Code", code) as num|null
|
||||
if(!usr.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
new_code = round(new_code)
|
||||
new_code = CLAMP(new_code, 1, 100)
|
||||
code = new_code
|
||||
|
||||
if(href_list["set"] == "power")
|
||||
if(!usr.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
on = !(on)
|
||||
icon_state = "electropack[on]"
|
||||
|
||||
if(usr)
|
||||
attack_self(usr)
|
||||
|
||||
return
|
||||
|
||||
/obj/item/electropack/proc/set_frequency(new_frequency)
|
||||
SSradio.remove_object(src, frequency)
|
||||
frequency = new_frequency
|
||||
SSradio.add_object(src, frequency, RADIO_SIGNALER)
|
||||
return
|
||||
|
||||
/obj/item/electropack/receive_signal(datum/signal/signal)
|
||||
if(!signal || signal.data["code"] != code)
|
||||
return
|
||||
|
||||
if(isliving(loc) && on)
|
||||
if(shock_cooldown == TRUE)
|
||||
return
|
||||
shock_cooldown = TRUE
|
||||
addtimer(VARSET_CALLBACK(src, shock_cooldown, FALSE), 100)
|
||||
var/mob/living/L = loc
|
||||
step(L, pick(GLOB.cardinals))
|
||||
|
||||
to_chat(L, "<span class='danger'>You feel a sharp shock!</span>")
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(3, 1, L)
|
||||
s.start()
|
||||
|
||||
L.Knockdown(100)
|
||||
|
||||
if(master)
|
||||
master.receive_signal()
|
||||
return
|
||||
|
||||
/obj/item/electropack/ui_interact(mob/user)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
|
||||
user.set_machine(src)
|
||||
var/dat = {"
|
||||
<TT>
|
||||
Turned [on ? "On" : "Off"] - <A href='?src=[REF(src)];set=power'>Toggle</A><BR>
|
||||
<B>Frequency/Code</B> for electropack:<BR>
|
||||
Frequency:
|
||||
[format_frequency(src.frequency)]
|
||||
<A href='byond://?src=[REF(src)];set=freq'>Set</A><BR>
|
||||
|
||||
Code:
|
||||
[src.code]
|
||||
<A href='byond://?src=[REF(src)];set=code'>Set</A><BR>
|
||||
</TT>"}
|
||||
user << browse(dat, "window=radio")
|
||||
onclose(user, "radio")
|
||||
return
|
||||
/obj/item/electropack
|
||||
name = "electropack"
|
||||
desc = "Dance my monkeys! DANCE!!!"
|
||||
icon = 'icons/obj/radio.dmi'
|
||||
icon_state = "electropack0"
|
||||
item_state = "electropack"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
flags_1 = CONDUCT_1
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
materials = list(MAT_METAL=10000, MAT_GLASS=2500)
|
||||
|
||||
var/code = 2
|
||||
var/frequency = FREQ_ELECTROPACK
|
||||
var/on = TRUE
|
||||
var/shock_cooldown = FALSE
|
||||
|
||||
/obj/item/electropack/suicide_act(mob/living/carbon/user)
|
||||
user.visible_message("<span class='suicide'>[user] hooks [user.p_them()]self to the electropack and spams the trigger! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
return (FIRELOSS)
|
||||
|
||||
/obj/item/electropack/Initialize()
|
||||
. = ..()
|
||||
set_frequency(frequency)
|
||||
|
||||
/obj/item/electropack/Destroy()
|
||||
SSradio.remove_object(src, frequency)
|
||||
. = ..()
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/electropack/attack_hand(mob/user)
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
if(src == C.back)
|
||||
to_chat(user, "<span class='warning'>You need help taking this off!</span>")
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/item/electropack/attackby(obj/item/W, mob/living/user, params)
|
||||
if(istype(W, /obj/item/clothing/head/helmet))
|
||||
var/obj/item/assembly/shock_kit/A = new /obj/item/assembly/shock_kit(user)
|
||||
A.icon = 'icons/obj/assemblies.dmi'
|
||||
|
||||
if(!user.transferItemToLoc(W, A))
|
||||
to_chat(user, "<span class='warning'>[W] is stuck to your hand, you cannot attach it to [src]!</span>")
|
||||
return
|
||||
W.master = A
|
||||
A.part1 = W
|
||||
|
||||
user.transferItemToLoc(src, A, TRUE)
|
||||
master = A
|
||||
A.part2 = src
|
||||
|
||||
user.put_in_hands(A)
|
||||
A.add_fingerprint(user)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/electropack/Topic(href, href_list)
|
||||
var/mob/living/carbon/C = usr
|
||||
if(usr.stat || usr.restrained() || C.back == src)
|
||||
return
|
||||
|
||||
if(!usr.canUseTopic(src, BE_CLOSE))
|
||||
usr << browse(null, "window=radio")
|
||||
onclose(usr, "radio")
|
||||
return
|
||||
|
||||
if(href_list["set"])
|
||||
if(href_list["set"] == "freq")
|
||||
var/new_freq = input(usr, "Input a new receiving frequency", "Electropack Frequency", format_frequency(frequency)) as num|null
|
||||
if(!usr.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
new_freq = unformat_frequency(new_freq)
|
||||
new_freq = sanitize_frequency(new_freq, TRUE)
|
||||
set_frequency(new_freq)
|
||||
|
||||
if(href_list["set"] == "code")
|
||||
var/new_code = input(usr, "Input a new receiving code", "Electropack Code", code) as num|null
|
||||
if(!usr.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
new_code = round(new_code)
|
||||
new_code = CLAMP(new_code, 1, 100)
|
||||
code = new_code
|
||||
|
||||
if(href_list["set"] == "power")
|
||||
if(!usr.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
on = !(on)
|
||||
icon_state = "electropack[on]"
|
||||
|
||||
if(usr)
|
||||
attack_self(usr)
|
||||
|
||||
return
|
||||
|
||||
/obj/item/electropack/proc/set_frequency(new_frequency)
|
||||
SSradio.remove_object(src, frequency)
|
||||
frequency = new_frequency
|
||||
SSradio.add_object(src, frequency, RADIO_SIGNALER)
|
||||
return
|
||||
|
||||
/obj/item/electropack/receive_signal(datum/signal/signal)
|
||||
if(!signal || signal.data["code"] != code)
|
||||
return
|
||||
|
||||
if(isliving(loc) && on)
|
||||
if(shock_cooldown == TRUE)
|
||||
return
|
||||
shock_cooldown = TRUE
|
||||
addtimer(VARSET_CALLBACK(src, shock_cooldown, FALSE), 100)
|
||||
var/mob/living/L = loc
|
||||
step(L, pick(GLOB.cardinals))
|
||||
|
||||
to_chat(L, "<span class='danger'>You feel a sharp shock!</span>")
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(3, 1, L)
|
||||
s.start()
|
||||
|
||||
L.Knockdown(100)
|
||||
|
||||
if(master)
|
||||
master.receive_signal()
|
||||
return
|
||||
|
||||
/obj/item/electropack/ui_interact(mob/user)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
|
||||
user.set_machine(src)
|
||||
var/dat = {"
|
||||
<TT>
|
||||
Turned [on ? "On" : "Off"] - <A href='?src=[REF(src)];set=power'>Toggle</A><BR>
|
||||
<B>Frequency/Code</B> for electropack:<BR>
|
||||
Frequency:
|
||||
[format_frequency(src.frequency)]
|
||||
<A href='byond://?src=[REF(src)];set=freq'>Set</A><BR>
|
||||
|
||||
Code:
|
||||
[src.code]
|
||||
<A href='byond://?src=[REF(src)];set=code'>Set</A><BR>
|
||||
</TT>"}
|
||||
user << browse(dat, "window=radio")
|
||||
onclose(user, "radio")
|
||||
return
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -37,9 +37,9 @@
|
||||
wielded = 0
|
||||
if(force_unwielded)
|
||||
force = force_unwielded
|
||||
var/sf = findtext(name," (Wielded)")
|
||||
var/sf = findtext(name, " (Wielded)", -10)//10 == length(" (Wielded)")
|
||||
if(sf)
|
||||
name = copytext(name,1,sf)
|
||||
name = copytext(name, 1, sf)
|
||||
else //something wrong
|
||||
name = "[initial(name)]"
|
||||
update_icon()
|
||||
|
||||
@@ -1,253 +1,253 @@
|
||||
|
||||
/obj
|
||||
var/crit_fail = FALSE
|
||||
animate_movement = 2
|
||||
speech_span = SPAN_ROBOT
|
||||
var/obj_flags = CAN_BE_HIT
|
||||
var/set_obj_flags // ONLY FOR MAPPING: Sets flags from a string list, handled in Initialize. Usage: set_obj_flags = "EMAGGED;!CAN_BE_HIT" to set EMAGGED and clear CAN_BE_HIT.
|
||||
|
||||
var/damtype = BRUTE
|
||||
var/force = 0
|
||||
|
||||
var/datum/armor/armor
|
||||
var/obj_integrity //defaults to max_integrity
|
||||
var/max_integrity = 500
|
||||
var/integrity_failure = 0 //0 if we have no special broken behavior
|
||||
|
||||
var/resistance_flags = NONE // INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ON_FIRE | UNACIDABLE | ACID_PROOF
|
||||
|
||||
var/acid_level = 0 //how much acid is on that obj
|
||||
|
||||
var/persistence_replacement //have something WAY too amazing to live to the next round? Set a new path here. Overuse of this var will make me upset.
|
||||
var/current_skin //the item reskin
|
||||
var/list/unique_reskin //List of options to reskin.
|
||||
var/always_reskinnable = FALSE
|
||||
|
||||
// Access levels, used in modules\jobs\access.dm
|
||||
var/list/req_access
|
||||
var/req_access_txt = "0"
|
||||
var/list/req_one_access
|
||||
var/req_one_access_txt = "0"
|
||||
|
||||
var/renamedByPlayer = FALSE //set when a player uses a pen on a renamable object
|
||||
|
||||
/obj/vv_edit_var(vname, vval)
|
||||
switch(vname)
|
||||
if("anchored")
|
||||
setAnchored(vval)
|
||||
return TRUE
|
||||
if("obj_flags")
|
||||
if ((obj_flags & DANGEROUS_POSSESSION) && !(vval & DANGEROUS_POSSESSION))
|
||||
return FALSE
|
||||
if("control_object")
|
||||
var/obj/O = vval
|
||||
if(istype(O) && (O.obj_flags & DANGEROUS_POSSESSION))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/Initialize()
|
||||
. = ..()
|
||||
if (islist(armor))
|
||||
armor = getArmor(arglist(armor))
|
||||
else if (!armor)
|
||||
armor = getArmor()
|
||||
else if (!istype(armor, /datum/armor))
|
||||
stack_trace("Invalid type [armor.type] found in .armor during /obj Initialize()")
|
||||
|
||||
if(obj_integrity == null)
|
||||
obj_integrity = max_integrity
|
||||
if (set_obj_flags)
|
||||
var/flagslist = splittext(set_obj_flags,";")
|
||||
var/list/string_to_objflag = GLOB.bitfields["obj_flags"]
|
||||
for (var/flag in flagslist)
|
||||
if (findtext(flag,"!",1,2))
|
||||
flag = copytext(flag,1-(length(flag))) // Get all but the initial !
|
||||
obj_flags &= ~string_to_objflag[flag]
|
||||
else
|
||||
obj_flags |= string_to_objflag[flag]
|
||||
if((obj_flags & ON_BLUEPRINTS) && isturf(loc))
|
||||
var/turf/T = loc
|
||||
T.add_blueprints_preround(src)
|
||||
|
||||
|
||||
/obj/Destroy(force=FALSE)
|
||||
if(!ismachinery(src))
|
||||
STOP_PROCESSING(SSobj, src) // TODO: Have a processing bitflag to reduce on unnecessary loops through the processing lists
|
||||
SStgui.close_uis(src)
|
||||
. = ..()
|
||||
|
||||
/obj/proc/setAnchored(anchorvalue)
|
||||
SEND_SIGNAL(src, COMSIG_OBJ_SETANCHORED, anchorvalue)
|
||||
anchored = anchorvalue
|
||||
|
||||
/obj/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, messy_throw = TRUE)
|
||||
. = ..()
|
||||
if(obj_flags & FROZEN)
|
||||
visible_message("<span class='danger'>[src] shatters into a million pieces!</span>")
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/assume_air(datum/gas_mixture/giver)
|
||||
if(loc)
|
||||
return loc.assume_air(giver)
|
||||
else
|
||||
return null
|
||||
|
||||
/obj/remove_air(amount)
|
||||
if(loc)
|
||||
return loc.remove_air(amount)
|
||||
else
|
||||
return null
|
||||
|
||||
/obj/return_air()
|
||||
if(loc)
|
||||
return loc.return_air()
|
||||
else
|
||||
return null
|
||||
|
||||
/obj/proc/handle_internal_lifeform(mob/lifeform_inside_me, breath_request)
|
||||
//Return: (NONSTANDARD)
|
||||
// null if object handles breathing logic for lifeform
|
||||
// datum/air_group to tell lifeform to process using that breath return
|
||||
//DEFAULT: Take air from turf to give to have mob process
|
||||
|
||||
if(breath_request>0)
|
||||
var/datum/gas_mixture/environment = return_air()
|
||||
var/breath_percentage = BREATH_VOLUME / environment.return_volume()
|
||||
return remove_air(environment.total_moles() * breath_percentage)
|
||||
else
|
||||
return null
|
||||
|
||||
/obj/proc/updateUsrDialog()
|
||||
if((obj_flags & IN_USE) && !(obj_flags & USES_TGUI))
|
||||
var/is_in_use = FALSE
|
||||
var/list/nearby = viewers(1, src)
|
||||
for(var/mob/M in nearby)
|
||||
if ((M.client && M.machine == src))
|
||||
is_in_use = TRUE
|
||||
ui_interact(M)
|
||||
if(isAI(usr) || iscyborg(usr) || IsAdminGhost(usr))
|
||||
if (!(usr in nearby))
|
||||
if (usr.client && usr.machine==src) // && M.machine == src is omitted because if we triggered this by using the dialog, it doesn't matter if our machine changed in between triggering it and this - the dialog is probably still supposed to refresh.
|
||||
is_in_use = TRUE
|
||||
ui_interact(usr)
|
||||
|
||||
// check for TK users
|
||||
|
||||
if(ishuman(usr))
|
||||
var/mob/living/carbon/human/H = usr
|
||||
if(!(usr in nearby))
|
||||
if(usr.client && usr.machine==src)
|
||||
if(H.dna.check_mutation(TK))
|
||||
is_in_use = TRUE
|
||||
ui_interact(usr)
|
||||
if (is_in_use)
|
||||
obj_flags |= IN_USE
|
||||
else
|
||||
obj_flags &= ~IN_USE
|
||||
|
||||
/obj/proc/updateDialog(update_viewers = TRUE,update_ais = TRUE)
|
||||
// Check that people are actually using the machine. If not, don't update anymore.
|
||||
if(obj_flags & IN_USE)
|
||||
var/is_in_use = FALSE
|
||||
if(update_viewers)
|
||||
for(var/mob/M in viewers(1, src))
|
||||
if ((M.client && M.machine == src))
|
||||
is_in_use = TRUE
|
||||
src.interact(M)
|
||||
var/ai_in_use = FALSE
|
||||
if(update_ais)
|
||||
ai_in_use = AutoUpdateAI(src)
|
||||
|
||||
if(update_viewers && update_ais) //State change is sure only if we check both
|
||||
if(!ai_in_use && !is_in_use)
|
||||
obj_flags &= ~IN_USE
|
||||
|
||||
|
||||
/obj/attack_ghost(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
ui_interact(user)
|
||||
|
||||
/obj/proc/container_resist(mob/living/user)
|
||||
return
|
||||
|
||||
/obj/proc/update_icon()
|
||||
return
|
||||
|
||||
/mob/proc/unset_machine()
|
||||
if(machine)
|
||||
machine.on_unset_machine(src)
|
||||
machine = null
|
||||
|
||||
//called when the user unsets the machine.
|
||||
/atom/movable/proc/on_unset_machine(mob/user)
|
||||
return
|
||||
|
||||
/mob/proc/set_machine(obj/O)
|
||||
if(src.machine)
|
||||
unset_machine()
|
||||
src.machine = O
|
||||
if(istype(O))
|
||||
O.obj_flags |= IN_USE
|
||||
|
||||
/obj/item/proc/updateSelfDialog()
|
||||
var/mob/M = src.loc
|
||||
if(istype(M) && M.client && M.machine == src)
|
||||
src.attack_self(M)
|
||||
|
||||
/obj/proc/hide(h)
|
||||
return
|
||||
|
||||
/obj/singularity_pull(S, current_size)
|
||||
..()
|
||||
if(!anchored || current_size >= STAGE_FIVE)
|
||||
step_towards(src,S)
|
||||
|
||||
/obj/get_dumping_location(datum/component/storage/source,mob/user)
|
||||
return get_turf(src)
|
||||
|
||||
/obj/proc/CanAStarPass()
|
||||
. = !density
|
||||
|
||||
/obj/proc/check_uplink_validity()
|
||||
return 1
|
||||
|
||||
/obj/proc/intercept_user_move(dir, mob, newLoc, oldLoc)
|
||||
return
|
||||
|
||||
/obj/vv_get_dropdown()
|
||||
. = ..()
|
||||
.["Delete all of type"] = "?_src_=vars;[HrefToken()];delall=[REF(src)]"
|
||||
.["Osay"] = "?_src_=vars;[HrefToken()];osay[REF(src)]"
|
||||
.["Modify armor values"] = "?_src_=vars;[HrefToken()];modarmor=[REF(src)]"
|
||||
|
||||
/obj/examine(mob/user)
|
||||
. = ..()
|
||||
if(obj_flags & UNIQUE_RENAME)
|
||||
. += "<span class='notice'>Use a pen on it to rename it or change its description.</span>"
|
||||
if(unique_reskin && (!current_skin || always_reskinnable))
|
||||
. += "<span class='notice'>Alt-click it to reskin it.</span>"
|
||||
|
||||
/obj/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(unique_reskin && (!current_skin || always_reskinnable) && user.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
|
||||
reskin_obj(user)
|
||||
return TRUE
|
||||
|
||||
/obj/proc/reskin_obj(mob/M)
|
||||
if(!LAZYLEN(unique_reskin))
|
||||
return
|
||||
var/dat = "<b>Reskin options for [name]:</b>\n"
|
||||
for(var/V in unique_reskin)
|
||||
var/output = icon2html(src, M, unique_reskin[V])
|
||||
dat += "[V]: <span class='reallybig'>[output]</span>\n"
|
||||
to_chat(M, dat)
|
||||
|
||||
var/choice = input(M, always_reskinnable ? "Choose the a reskin for [src]" : "Warning, you can only reskin [src] once!","Reskin Object") as null|anything in unique_reskin
|
||||
if(QDELETED(src) || !choice || (current_skin && !always_reskinnable) || M.incapacitated() || !in_range(M,src) || !unique_reskin[choice] || unique_reskin[choice] == current_skin)
|
||||
return
|
||||
current_skin = choice
|
||||
icon_state = unique_reskin[choice]
|
||||
to_chat(M, "[src] is now skinned as '[choice]'.")
|
||||
|
||||
/obj
|
||||
var/crit_fail = FALSE
|
||||
animate_movement = 2
|
||||
speech_span = SPAN_ROBOT
|
||||
var/obj_flags = CAN_BE_HIT
|
||||
var/set_obj_flags // ONLY FOR MAPPING: Sets flags from a string list, handled in Initialize. Usage: set_obj_flags = "EMAGGED;!CAN_BE_HIT" to set EMAGGED and clear CAN_BE_HIT.
|
||||
|
||||
var/damtype = BRUTE
|
||||
var/force = 0
|
||||
|
||||
var/datum/armor/armor
|
||||
var/obj_integrity //defaults to max_integrity
|
||||
var/max_integrity = 500
|
||||
var/integrity_failure = 0 //0 if we have no special broken behavior
|
||||
|
||||
var/resistance_flags = NONE // INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ON_FIRE | UNACIDABLE | ACID_PROOF
|
||||
|
||||
var/acid_level = 0 //how much acid is on that obj
|
||||
|
||||
var/persistence_replacement //have something WAY too amazing to live to the next round? Set a new path here. Overuse of this var will make me upset.
|
||||
var/current_skin //the item reskin
|
||||
var/list/unique_reskin //List of options to reskin.
|
||||
var/always_reskinnable = FALSE
|
||||
|
||||
// Access levels, used in modules\jobs\access.dm
|
||||
var/list/req_access
|
||||
var/req_access_txt = "0"
|
||||
var/list/req_one_access
|
||||
var/req_one_access_txt = "0"
|
||||
|
||||
var/renamedByPlayer = FALSE //set when a player uses a pen on a renamable object
|
||||
|
||||
/obj/vv_edit_var(vname, vval)
|
||||
switch(vname)
|
||||
if("anchored")
|
||||
setAnchored(vval)
|
||||
return TRUE
|
||||
if("obj_flags")
|
||||
if ((obj_flags & DANGEROUS_POSSESSION) && !(vval & DANGEROUS_POSSESSION))
|
||||
return FALSE
|
||||
if("control_object")
|
||||
var/obj/O = vval
|
||||
if(istype(O) && (O.obj_flags & DANGEROUS_POSSESSION))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/Initialize()
|
||||
. = ..()
|
||||
if (islist(armor))
|
||||
armor = getArmor(arglist(armor))
|
||||
else if (!armor)
|
||||
armor = getArmor()
|
||||
else if (!istype(armor, /datum/armor))
|
||||
stack_trace("Invalid type [armor.type] found in .armor during /obj Initialize()")
|
||||
|
||||
if(obj_integrity == null)
|
||||
obj_integrity = max_integrity
|
||||
if (set_obj_flags)
|
||||
var/flagslist = splittext(set_obj_flags,";")
|
||||
var/list/string_to_objflag = GLOB.bitfields["obj_flags"]
|
||||
for (var/flag in flagslist)
|
||||
if(flag[1] == "!")
|
||||
flag = copytext(flag, length(flag[1]) + 1) // Get all but the initial !
|
||||
obj_flags &= ~string_to_objflag[flag]
|
||||
else
|
||||
obj_flags |= string_to_objflag[flag]
|
||||
if((obj_flags & ON_BLUEPRINTS) && isturf(loc))
|
||||
var/turf/T = loc
|
||||
T.add_blueprints_preround(src)
|
||||
|
||||
|
||||
/obj/Destroy(force=FALSE)
|
||||
if(!ismachinery(src))
|
||||
STOP_PROCESSING(SSobj, src) // TODO: Have a processing bitflag to reduce on unnecessary loops through the processing lists
|
||||
SStgui.close_uis(src)
|
||||
. = ..()
|
||||
|
||||
/obj/proc/setAnchored(anchorvalue)
|
||||
SEND_SIGNAL(src, COMSIG_OBJ_SETANCHORED, anchorvalue)
|
||||
anchored = anchorvalue
|
||||
|
||||
/obj/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, messy_throw = TRUE)
|
||||
. = ..()
|
||||
if(obj_flags & FROZEN)
|
||||
visible_message("<span class='danger'>[src] shatters into a million pieces!</span>")
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/assume_air(datum/gas_mixture/giver)
|
||||
if(loc)
|
||||
return loc.assume_air(giver)
|
||||
else
|
||||
return null
|
||||
|
||||
/obj/remove_air(amount)
|
||||
if(loc)
|
||||
return loc.remove_air(amount)
|
||||
else
|
||||
return null
|
||||
|
||||
/obj/return_air()
|
||||
if(loc)
|
||||
return loc.return_air()
|
||||
else
|
||||
return null
|
||||
|
||||
/obj/proc/handle_internal_lifeform(mob/lifeform_inside_me, breath_request)
|
||||
//Return: (NONSTANDARD)
|
||||
// null if object handles breathing logic for lifeform
|
||||
// datum/air_group to tell lifeform to process using that breath return
|
||||
//DEFAULT: Take air from turf to give to have mob process
|
||||
|
||||
if(breath_request>0)
|
||||
var/datum/gas_mixture/environment = return_air()
|
||||
var/breath_percentage = BREATH_VOLUME / environment.return_volume()
|
||||
return remove_air(environment.total_moles() * breath_percentage)
|
||||
else
|
||||
return null
|
||||
|
||||
/obj/proc/updateUsrDialog()
|
||||
if((obj_flags & IN_USE) && !(obj_flags & USES_TGUI))
|
||||
var/is_in_use = FALSE
|
||||
var/list/nearby = viewers(1, src)
|
||||
for(var/mob/M in nearby)
|
||||
if ((M.client && M.machine == src))
|
||||
is_in_use = TRUE
|
||||
ui_interact(M)
|
||||
if(isAI(usr) || iscyborg(usr) || IsAdminGhost(usr))
|
||||
if (!(usr in nearby))
|
||||
if (usr.client && usr.machine==src) // && M.machine == src is omitted because if we triggered this by using the dialog, it doesn't matter if our machine changed in between triggering it and this - the dialog is probably still supposed to refresh.
|
||||
is_in_use = TRUE
|
||||
ui_interact(usr)
|
||||
|
||||
// check for TK users
|
||||
|
||||
if(ishuman(usr))
|
||||
var/mob/living/carbon/human/H = usr
|
||||
if(!(usr in nearby))
|
||||
if(usr.client && usr.machine==src)
|
||||
if(H.dna.check_mutation(TK))
|
||||
is_in_use = TRUE
|
||||
ui_interact(usr)
|
||||
if (is_in_use)
|
||||
obj_flags |= IN_USE
|
||||
else
|
||||
obj_flags &= ~IN_USE
|
||||
|
||||
/obj/proc/updateDialog(update_viewers = TRUE,update_ais = TRUE)
|
||||
// Check that people are actually using the machine. If not, don't update anymore.
|
||||
if(obj_flags & IN_USE)
|
||||
var/is_in_use = FALSE
|
||||
if(update_viewers)
|
||||
for(var/mob/M in viewers(1, src))
|
||||
if ((M.client && M.machine == src))
|
||||
is_in_use = TRUE
|
||||
src.interact(M)
|
||||
var/ai_in_use = FALSE
|
||||
if(update_ais)
|
||||
ai_in_use = AutoUpdateAI(src)
|
||||
|
||||
if(update_viewers && update_ais) //State change is sure only if we check both
|
||||
if(!ai_in_use && !is_in_use)
|
||||
obj_flags &= ~IN_USE
|
||||
|
||||
|
||||
/obj/attack_ghost(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
ui_interact(user)
|
||||
|
||||
/obj/proc/container_resist(mob/living/user)
|
||||
return
|
||||
|
||||
/obj/proc/update_icon()
|
||||
return
|
||||
|
||||
/mob/proc/unset_machine()
|
||||
if(machine)
|
||||
machine.on_unset_machine(src)
|
||||
machine = null
|
||||
|
||||
//called when the user unsets the machine.
|
||||
/atom/movable/proc/on_unset_machine(mob/user)
|
||||
return
|
||||
|
||||
/mob/proc/set_machine(obj/O)
|
||||
if(src.machine)
|
||||
unset_machine()
|
||||
src.machine = O
|
||||
if(istype(O))
|
||||
O.obj_flags |= IN_USE
|
||||
|
||||
/obj/item/proc/updateSelfDialog()
|
||||
var/mob/M = src.loc
|
||||
if(istype(M) && M.client && M.machine == src)
|
||||
src.attack_self(M)
|
||||
|
||||
/obj/proc/hide(h)
|
||||
return
|
||||
|
||||
/obj/singularity_pull(S, current_size)
|
||||
..()
|
||||
if(!anchored || current_size >= STAGE_FIVE)
|
||||
step_towards(src,S)
|
||||
|
||||
/obj/get_dumping_location(datum/component/storage/source,mob/user)
|
||||
return get_turf(src)
|
||||
|
||||
/obj/proc/CanAStarPass()
|
||||
. = !density
|
||||
|
||||
/obj/proc/check_uplink_validity()
|
||||
return 1
|
||||
|
||||
/obj/proc/intercept_user_move(dir, mob, newLoc, oldLoc)
|
||||
return
|
||||
|
||||
/obj/vv_get_dropdown()
|
||||
. = ..()
|
||||
.["Delete all of type"] = "?_src_=vars;[HrefToken()];delall=[REF(src)]"
|
||||
.["Osay"] = "?_src_=vars;[HrefToken()];osay[REF(src)]"
|
||||
.["Modify armor values"] = "?_src_=vars;[HrefToken()];modarmor=[REF(src)]"
|
||||
|
||||
/obj/examine(mob/user)
|
||||
. = ..()
|
||||
if(obj_flags & UNIQUE_RENAME)
|
||||
. += "<span class='notice'>Use a pen on it to rename it or change its description.</span>"
|
||||
if(unique_reskin && (!current_skin || always_reskinnable))
|
||||
. += "<span class='notice'>Alt-click it to reskin it.</span>"
|
||||
|
||||
/obj/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(unique_reskin && (!current_skin || always_reskinnable) && user.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
|
||||
reskin_obj(user)
|
||||
return TRUE
|
||||
|
||||
/obj/proc/reskin_obj(mob/M)
|
||||
if(!LAZYLEN(unique_reskin))
|
||||
return
|
||||
var/dat = "<b>Reskin options for [name]:</b>\n"
|
||||
for(var/V in unique_reskin)
|
||||
var/output = icon2html(src, M, unique_reskin[V])
|
||||
dat += "[V]: <span class='reallybig'>[output]</span>\n"
|
||||
to_chat(M, dat)
|
||||
|
||||
var/choice = input(M, always_reskinnable ? "Choose the a reskin for [src]" : "Warning, you can only reskin [src] once!","Reskin Object") as null|anything in unique_reskin
|
||||
if(QDELETED(src) || !choice || (current_skin && !always_reskinnable) || M.incapacitated() || !in_range(M,src) || !unique_reskin[choice] || unique_reskin[choice] == current_skin)
|
||||
return
|
||||
current_skin = choice
|
||||
icon_state = unique_reskin[choice]
|
||||
to_chat(M, "[src] is now skinned as '[choice]'.")
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
|
||||
switch(choice)
|
||||
if("name")
|
||||
var/newname = copytext(sanitize(input(H, "Who are we again?", "Name change", H.name) as null|text),1,MAX_NAME_LEN)
|
||||
var/newname = reject_bad_name(stripped_input(H, "Who are we again?", "Name change", H.name, MAX_NAME_LEN))
|
||||
|
||||
if(!newname)
|
||||
return
|
||||
|
||||
@@ -1,381 +1,382 @@
|
||||
|
||||
#define MUSICIAN_HEARCHECK_MINDELAY 4
|
||||
#define MUSIC_MAXLINES 600
|
||||
#define MUSIC_MAXLINECHARS 50
|
||||
|
||||
/datum/song
|
||||
var/name = "Untitled"
|
||||
var/list/lines = new()
|
||||
var/tempo = 5 // delay between notes
|
||||
|
||||
var/playing = 0 // if we're playing
|
||||
var/help = 0 // if help is open
|
||||
var/edit = 1 // if we're in editing mode
|
||||
var/repeat = 0 // number of times remaining to repeat
|
||||
var/max_repeats = 10 // maximum times we can repeat
|
||||
|
||||
var/instrumentDir = "piano" // the folder with the sounds
|
||||
var/instrumentExt = "ogg" // the file extension
|
||||
var/obj/instrumentObj = null // the associated obj playing the sound
|
||||
var/last_hearcheck = 0
|
||||
var/list/hearing_mobs
|
||||
|
||||
/datum/song/New(dir, obj, ext = "ogg")
|
||||
tempo = sanitize_tempo(tempo)
|
||||
instrumentDir = dir
|
||||
instrumentObj = obj
|
||||
instrumentExt = ext
|
||||
|
||||
/datum/song/Destroy()
|
||||
instrumentObj = null
|
||||
return ..()
|
||||
|
||||
// note is a number from 1-7 for A-G
|
||||
// acc is either "b", "n", or "#"
|
||||
// oct is 1-8 (or 9 for C)
|
||||
/datum/song/proc/playnote(note, acc as text, oct)
|
||||
// handle accidental -> B<>C of E<>F
|
||||
if(acc == "b" && (note == 3 || note == 6)) // C or F
|
||||
if(note == 3)
|
||||
oct--
|
||||
note--
|
||||
acc = "n"
|
||||
else if(acc == "#" && (note == 2 || note == 5)) // B or E
|
||||
if(note == 2)
|
||||
oct++
|
||||
note++
|
||||
acc = "n"
|
||||
else if(acc == "#" && (note == 7)) //G#
|
||||
note = 1
|
||||
acc = "b"
|
||||
else if(acc == "#") // mass convert all sharps to flats, octave jump already handled
|
||||
acc = "b"
|
||||
note++
|
||||
|
||||
// check octave, C is allowed to go to 9
|
||||
if(oct < 1 || (note == 3 ? oct > 9 : oct > 8))
|
||||
return
|
||||
|
||||
// now generate name
|
||||
var/soundfile = "sound/instruments/[instrumentDir]/[ascii2text(note+64)][acc][oct].[instrumentExt]"
|
||||
soundfile = file(soundfile)
|
||||
// make sure the note exists
|
||||
if(!fexists(soundfile))
|
||||
return
|
||||
// and play
|
||||
var/turf/source = get_turf(instrumentObj)
|
||||
if((world.time - MUSICIAN_HEARCHECK_MINDELAY) > last_hearcheck)
|
||||
LAZYCLEARLIST(hearing_mobs)
|
||||
for(var/mob/M in get_hearers_in_view(15, source))
|
||||
if(!M.client || !(M.client.prefs.toggles & SOUND_INSTRUMENTS))
|
||||
continue
|
||||
LAZYADD(hearing_mobs, M)
|
||||
last_hearcheck = world.time
|
||||
|
||||
var/sound/music_played = sound(soundfile)
|
||||
for(var/i in hearing_mobs)
|
||||
var/mob/M = i
|
||||
M.playsound_local(source, null, 100, falloff = 5, S = music_played)
|
||||
|
||||
/datum/song/proc/updateDialog(mob/user)
|
||||
instrumentObj.updateDialog() // assumes it's an object in world, override if otherwise
|
||||
|
||||
/datum/song/proc/shouldStopPlaying(mob/user)
|
||||
if(instrumentObj)
|
||||
if(!user.canUseTopic(instrumentObj))
|
||||
return TRUE
|
||||
return !instrumentObj.anchored // add special cases to stop in subclasses
|
||||
else
|
||||
return TRUE
|
||||
|
||||
/datum/song/proc/playsong(mob/user)
|
||||
while(repeat >= 0)
|
||||
var/cur_oct[7]
|
||||
var/cur_acc[7]
|
||||
for(var/i = 1 to 7)
|
||||
cur_oct[i] = 3
|
||||
cur_acc[i] = "n"
|
||||
|
||||
for(var/line in lines)
|
||||
for(var/beat in splittext(lowertext(line), ","))
|
||||
var/list/notes = splittext(beat, "/")
|
||||
for(var/note in splittext(notes[1], "-"))
|
||||
if(!playing || shouldStopPlaying(user))//If the instrument is playing, or special case
|
||||
playing = FALSE
|
||||
hearing_mobs = null
|
||||
return
|
||||
if(!length(note))
|
||||
continue
|
||||
var/cur_note = text2ascii(note) - 96
|
||||
if(cur_note < 1 || cur_note > 7)
|
||||
continue
|
||||
for(var/i=2 to length(note))
|
||||
var/ni = copytext(note,i,i+1)
|
||||
if(!text2num(ni))
|
||||
if(ni == "#" || ni == "b" || ni == "n")
|
||||
cur_acc[cur_note] = ni
|
||||
else if(ni == "s")
|
||||
cur_acc[cur_note] = "#" // so shift is never required
|
||||
else
|
||||
cur_oct[cur_note] = text2num(ni)
|
||||
if(user.dizziness > 0 && prob(user.dizziness / 2))
|
||||
cur_note = CLAMP(cur_note + rand(round(-user.dizziness / 10), round(user.dizziness / 10)), 1, 7)
|
||||
if(user.dizziness > 0 && prob(user.dizziness / 5))
|
||||
if(prob(30))
|
||||
cur_acc[cur_note] = "#"
|
||||
else if(prob(42))
|
||||
cur_acc[cur_note] = "b"
|
||||
else if(prob(75))
|
||||
cur_acc[cur_note] = "n"
|
||||
playnote(cur_note, cur_acc[cur_note], cur_oct[cur_note])
|
||||
if(notes.len >= 2 && text2num(notes[2]))
|
||||
sleep(sanitize_tempo(tempo / text2num(notes[2])))
|
||||
else
|
||||
sleep(tempo)
|
||||
repeat--
|
||||
hearing_mobs = null
|
||||
playing = FALSE
|
||||
repeat = 0
|
||||
updateDialog(user)
|
||||
|
||||
/datum/song/proc/interact(mob/user)
|
||||
var/dat = ""
|
||||
|
||||
if(lines.len > 0)
|
||||
dat += "<H3>Playback</H3>"
|
||||
if(!playing)
|
||||
dat += "<A href='?src=[REF(src)];play=1'>Play</A> <SPAN CLASS='linkOn'>Stop</SPAN><BR><BR>"
|
||||
dat += "Repeat Song: "
|
||||
dat += repeat > 0 ? "<A href='?src=[REF(src)];repeat=-10'>-</A><A href='?src=[REF(src)];repeat=-1'>-</A>" : "<SPAN CLASS='linkOff'>-</SPAN><SPAN CLASS='linkOff'>-</SPAN>"
|
||||
dat += " [repeat] times "
|
||||
dat += repeat < max_repeats ? "<A href='?src=[REF(src)];repeat=1'>+</A><A href='?src=[REF(src)];repeat=10'>+</A>" : "<SPAN CLASS='linkOff'>+</SPAN><SPAN CLASS='linkOff'>+</SPAN>"
|
||||
dat += "<BR>"
|
||||
else
|
||||
dat += "<SPAN CLASS='linkOn'>Play</SPAN> <A href='?src=[REF(src)];stop=1'>Stop</A><BR>"
|
||||
dat += "Repeats left: <B>[repeat]</B><BR>"
|
||||
if(!edit)
|
||||
dat += "<BR><B><A href='?src=[REF(src)];edit=2'>Show Editor</A></B><BR>"
|
||||
else
|
||||
dat += "<H3>Editing</H3>"
|
||||
dat += "<B><A href='?src=[REF(src)];edit=1'>Hide Editor</A></B>"
|
||||
dat += " <A href='?src=[REF(src)];newsong=1'>Start a New Song</A>"
|
||||
dat += " <A href='?src=[REF(src)];import=1'>Import a Song</A><BR><BR>"
|
||||
var/bpm = round(600 / tempo)
|
||||
dat += "Tempo: <A href='?src=[REF(src)];tempo=[world.tick_lag]'>-</A> [bpm] BPM <A href='?src=[REF(src)];tempo=-[world.tick_lag]'>+</A><BR><BR>"
|
||||
var/linecount = 0
|
||||
for(var/line in lines)
|
||||
linecount += 1
|
||||
dat += "Line [linecount]: <A href='?src=[REF(src)];modifyline=[linecount]'>Edit</A> <A href='?src=[REF(src)];deleteline=[linecount]'>X</A> [line]<BR>"
|
||||
dat += "<A href='?src=[REF(src)];newline=1'>Add Line</A><BR><BR>"
|
||||
if(help)
|
||||
dat += "<B><A href='?src=[REF(src)];help=1'>Hide Help</A></B><BR>"
|
||||
dat += {"
|
||||
Lines are a series of chords, separated by commas (,), each with notes separated by hyphens (-).<br>
|
||||
Every note in a chord will play together, with chord timed by the tempo.<br>
|
||||
<br>
|
||||
Notes are played by the names of the note, and optionally, the accidental, and/or the octave number.<br>
|
||||
By default, every note is natural and in octave 3. Defining otherwise is remembered for each note.<br>
|
||||
Example: <i>C,D,E,F,G,A,B</i> will play a C major scale.<br>
|
||||
After a note has an accidental placed, it will be remembered: <i>C,C4,C,C3</i> is <i>C3,C4,C4,C3</i><br>
|
||||
Chords can be played simply by seperating each note with a hyphon: <i>A-C#,Cn-E,E-G#,Gn-B</i><br>
|
||||
A pause may be denoted by an empty chord: <i>C,E,,C,G</i><br>
|
||||
To make a chord be a different time, end it with /x, where the chord length will be length<br>
|
||||
defined by tempo / x: <i>C,G/2,E/4</i><br>
|
||||
Combined, an example is: <i>E-E4/4,F#/2,G#/8,B/8,E3-E4/4</i>
|
||||
<br>
|
||||
Lines may be up to [MUSIC_MAXLINECHARS] characters.<br>
|
||||
A song may only contain up to [MUSIC_MAXLINES] lines.<br>
|
||||
"}
|
||||
else
|
||||
dat += "<B><A href='?src=[REF(src)];help=2'>Show Help</A></B><BR>"
|
||||
|
||||
var/datum/browser/popup = new(user, "instrument", instrumentObj.name, 700, 500)
|
||||
popup.set_content(dat)
|
||||
popup.set_title_image(user.browse_rsc_icon(instrumentObj.icon, instrumentObj.icon_state))
|
||||
popup.open()
|
||||
|
||||
/datum/song/proc/ParseSong(text)
|
||||
set waitfor = FALSE
|
||||
//split into lines
|
||||
lines = splittext(text, "\n")
|
||||
if(lines.len)
|
||||
if(copytext(lines[1],1,6) == "BPM: ")
|
||||
tempo = sanitize_tempo(600 / text2num(copytext(lines[1],6)))
|
||||
lines.Cut(1,2)
|
||||
else
|
||||
tempo = sanitize_tempo(5) // default 120 BPM
|
||||
if(lines.len > MUSIC_MAXLINES)
|
||||
to_chat(usr, "Too many lines!")
|
||||
lines.Cut(MUSIC_MAXLINES + 1)
|
||||
var/linenum = 1
|
||||
for(var/l in lines)
|
||||
if(length(l) > MUSIC_MAXLINECHARS)
|
||||
to_chat(usr, "Line [linenum] too long!")
|
||||
lines.Remove(l)
|
||||
else
|
||||
linenum++
|
||||
updateDialog(usr) // make sure updates when complete
|
||||
|
||||
/datum/song/Topic(href, href_list)
|
||||
if(!usr.canUseTopic(instrumentObj))
|
||||
usr << browse(null, "window=instrument")
|
||||
usr.unset_machine()
|
||||
return
|
||||
|
||||
instrumentObj.add_fingerprint(usr)
|
||||
|
||||
if(href_list["newsong"])
|
||||
lines = new()
|
||||
tempo = sanitize_tempo(5) // default 120 BPM
|
||||
name = ""
|
||||
|
||||
else if(href_list["import"])
|
||||
var/t = ""
|
||||
do
|
||||
t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", name), t) as message)
|
||||
if(!in_range(instrumentObj, usr))
|
||||
return
|
||||
|
||||
if(length(t) >= MUSIC_MAXLINES * MUSIC_MAXLINECHARS)
|
||||
var/cont = input(usr, "Your message is too long! Would you like to continue editing it?", "", "yes") in list("yes", "no")
|
||||
if(cont == "no")
|
||||
break
|
||||
while(length(t) > MUSIC_MAXLINES * MUSIC_MAXLINECHARS)
|
||||
ParseSong(t)
|
||||
|
||||
else if(href_list["help"])
|
||||
help = text2num(href_list["help"]) - 1
|
||||
|
||||
else if(href_list["edit"])
|
||||
edit = text2num(href_list["edit"]) - 1
|
||||
|
||||
if(href_list["repeat"]) //Changing this from a toggle to a number of repeats to avoid infinite loops.
|
||||
if(playing)
|
||||
return //So that people cant keep adding to repeat. If the do it intentionally, it could result in the server crashing.
|
||||
repeat += round(text2num(href_list["repeat"]))
|
||||
if(repeat < 0)
|
||||
repeat = 0
|
||||
if(repeat > max_repeats)
|
||||
repeat = max_repeats
|
||||
|
||||
else if(href_list["tempo"])
|
||||
tempo = sanitize_tempo(tempo + text2num(href_list["tempo"]))
|
||||
|
||||
else if(href_list["play"])
|
||||
playing = TRUE
|
||||
spawn()
|
||||
playsong(usr)
|
||||
|
||||
else if(href_list["newline"])
|
||||
var/newline = html_encode(input("Enter your line: ", instrumentObj.name) as text|null)
|
||||
if(!newline || !in_range(instrumentObj, usr))
|
||||
return
|
||||
if(lines.len > MUSIC_MAXLINES)
|
||||
return
|
||||
if(length(newline) > MUSIC_MAXLINECHARS)
|
||||
newline = copytext(newline, 1, MUSIC_MAXLINECHARS)
|
||||
lines.Add(newline)
|
||||
|
||||
else if(href_list["deleteline"])
|
||||
var/num = round(text2num(href_list["deleteline"]))
|
||||
if(num > lines.len || num < 1)
|
||||
return
|
||||
lines.Cut(num, num+1)
|
||||
|
||||
else if(href_list["modifyline"])
|
||||
var/num = round(text2num(href_list["modifyline"]),1)
|
||||
var/content = html_encode(input("Enter your line: ", instrumentObj.name, lines[num]) as text|null)
|
||||
if(!content || !in_range(instrumentObj, usr))
|
||||
return
|
||||
if(length(content) > MUSIC_MAXLINECHARS)
|
||||
content = copytext(content, 1, MUSIC_MAXLINECHARS)
|
||||
if(num > lines.len || num < 1)
|
||||
return
|
||||
lines[num] = content
|
||||
|
||||
else if(href_list["stop"])
|
||||
playing = FALSE
|
||||
hearing_mobs = null
|
||||
|
||||
updateDialog(usr)
|
||||
return
|
||||
|
||||
/datum/song/proc/sanitize_tempo(new_tempo)
|
||||
new_tempo = abs(new_tempo)
|
||||
return max(round(new_tempo, world.tick_lag), world.tick_lag)
|
||||
|
||||
// subclass for handheld instruments, like violin
|
||||
/datum/song/handheld
|
||||
|
||||
/datum/song/handheld/updateDialog(mob/user)
|
||||
instrumentObj.interact(user)
|
||||
|
||||
/datum/song/handheld/shouldStopPlaying()
|
||||
if(instrumentObj)
|
||||
return !isliving(instrumentObj.loc)
|
||||
else
|
||||
return TRUE
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/obj/structure/piano
|
||||
name = "space minimoog"
|
||||
icon = 'icons/obj/musician.dmi'
|
||||
icon_state = "minimoog"
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
var/datum/song/song
|
||||
|
||||
/obj/structure/piano/unanchored
|
||||
anchored = FALSE
|
||||
|
||||
/obj/structure/piano/New()
|
||||
..()
|
||||
song = new("piano", src)
|
||||
|
||||
if(prob(50) && icon_state == initial(icon_state))
|
||||
name = "space minimoog"
|
||||
desc = "This is a minimoog, like a space piano, but more spacey!"
|
||||
icon_state = "minimoog"
|
||||
else
|
||||
name = "space piano"
|
||||
desc = "This is a space piano, like a regular piano, but always in tune! Even if the musician isn't."
|
||||
icon_state = "piano"
|
||||
|
||||
/obj/structure/piano/Destroy()
|
||||
qdel(song)
|
||||
song = null
|
||||
return ..()
|
||||
|
||||
/obj/structure/piano/Initialize(mapload)
|
||||
. = ..()
|
||||
if(mapload)
|
||||
song.tempo = song.sanitize_tempo(song.tempo) // tick_lag isn't set when the map is loaded
|
||||
|
||||
/obj/structure/piano/attack_hand(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
interact(user)
|
||||
|
||||
/obj/structure/piano/attack_paw(mob/user)
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/structure/piano/interact(mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/structure/piano/ui_interact(mob/user)
|
||||
if(!user || !anchored)
|
||||
return
|
||||
|
||||
if(!user.IsAdvancedToolUser())
|
||||
to_chat(user, "<span class='warning'>You don't have the dexterity to do this!</span>")
|
||||
return 1
|
||||
user.set_machine(src)
|
||||
song.interact(user)
|
||||
|
||||
/obj/structure/piano/wrench_act(mob/living/user, obj/item/I)
|
||||
default_unfasten_wrench(user, I, 40)
|
||||
return TRUE
|
||||
|
||||
#define MUSICIAN_HEARCHECK_MINDELAY 4
|
||||
#define MUSIC_MAXLINES 600
|
||||
#define MUSIC_MAXLINECHARS 50
|
||||
|
||||
/datum/song
|
||||
var/name = "Untitled"
|
||||
var/list/lines = new()
|
||||
var/tempo = 5 // delay between notes
|
||||
|
||||
var/playing = 0 // if we're playing
|
||||
var/help = 0 // if help is open
|
||||
var/edit = 1 // if we're in editing mode
|
||||
var/repeat = 0 // number of times remaining to repeat
|
||||
var/max_repeats = 10 // maximum times we can repeat
|
||||
|
||||
var/instrumentDir = "piano" // the folder with the sounds
|
||||
var/instrumentExt = "ogg" // the file extension
|
||||
var/obj/instrumentObj = null // the associated obj playing the sound
|
||||
var/last_hearcheck = 0
|
||||
var/list/hearing_mobs
|
||||
|
||||
/datum/song/New(dir, obj, ext = "ogg")
|
||||
tempo = sanitize_tempo(tempo)
|
||||
instrumentDir = dir
|
||||
instrumentObj = obj
|
||||
instrumentExt = ext
|
||||
|
||||
/datum/song/Destroy()
|
||||
instrumentObj = null
|
||||
return ..()
|
||||
|
||||
// note is a number from 1-7 for A-G
|
||||
// acc is either "b", "n", or "#"
|
||||
// oct is 1-8 (or 9 for C)
|
||||
/datum/song/proc/playnote(note, acc as text, oct)
|
||||
// handle accidental -> B<>C of E<>F
|
||||
if(acc == "b" && (note == 3 || note == 6)) // C or F
|
||||
if(note == 3)
|
||||
oct--
|
||||
note--
|
||||
acc = "n"
|
||||
else if(acc == "#" && (note == 2 || note == 5)) // B or E
|
||||
if(note == 2)
|
||||
oct++
|
||||
note++
|
||||
acc = "n"
|
||||
else if(acc == "#" && (note == 7)) //G#
|
||||
note = 1
|
||||
acc = "b"
|
||||
else if(acc == "#") // mass convert all sharps to flats, octave jump already handled
|
||||
acc = "b"
|
||||
note++
|
||||
|
||||
// check octave, C is allowed to go to 9
|
||||
if(oct < 1 || (note == 3 ? oct > 9 : oct > 8))
|
||||
return
|
||||
|
||||
// now generate name
|
||||
var/soundfile = "sound/instruments/[instrumentDir]/[ascii2text(note+64)][acc][oct].[instrumentExt]"
|
||||
soundfile = file(soundfile)
|
||||
// make sure the note exists
|
||||
if(!fexists(soundfile))
|
||||
return
|
||||
// and play
|
||||
var/turf/source = get_turf(instrumentObj)
|
||||
if((world.time - MUSICIAN_HEARCHECK_MINDELAY) > last_hearcheck)
|
||||
LAZYCLEARLIST(hearing_mobs)
|
||||
for(var/mob/M in get_hearers_in_view(15, source))
|
||||
if(!M.client || !(M.client.prefs.toggles & SOUND_INSTRUMENTS))
|
||||
continue
|
||||
LAZYADD(hearing_mobs, M)
|
||||
last_hearcheck = world.time
|
||||
|
||||
var/sound/music_played = sound(soundfile)
|
||||
for(var/i in hearing_mobs)
|
||||
var/mob/M = i
|
||||
M.playsound_local(source, null, 100, falloff = 5, S = music_played)
|
||||
|
||||
/datum/song/proc/updateDialog(mob/user)
|
||||
instrumentObj.updateDialog() // assumes it's an object in world, override if otherwise
|
||||
|
||||
/datum/song/proc/shouldStopPlaying(mob/user)
|
||||
if(instrumentObj)
|
||||
if(!user.canUseTopic(instrumentObj))
|
||||
return TRUE
|
||||
return !instrumentObj.anchored // add special cases to stop in subclasses
|
||||
else
|
||||
return TRUE
|
||||
|
||||
/datum/song/proc/playsong(mob/user)
|
||||
while(repeat >= 0)
|
||||
var/cur_oct[7]
|
||||
var/cur_acc[7]
|
||||
for(var/i = 1 to 7)
|
||||
cur_oct[i] = 3
|
||||
cur_acc[i] = "n"
|
||||
|
||||
for(var/line in lines)
|
||||
for(var/beat in splittext(lowertext(line), ","))
|
||||
var/list/notes = splittext(beat, "/")
|
||||
for(var/note in splittext(notes[1], "-"))
|
||||
if(!playing || shouldStopPlaying(user))//If the instrument is playing, or special case
|
||||
playing = FALSE
|
||||
hearing_mobs = null
|
||||
return
|
||||
if(!length(note))
|
||||
continue
|
||||
var/cur_note = text2ascii(note) - 96
|
||||
if(cur_note < 1 || cur_note > 7)
|
||||
continue
|
||||
var/notelen = length(note)
|
||||
var/ni = ""
|
||||
for(var/i = length(note[1]) + 1, i <= notelen, i += length(ni))
|
||||
ni = note[i]
|
||||
if(!text2num(ni))
|
||||
if(ni == "#" || ni == "b" || ni == "n")
|
||||
cur_acc[cur_note] = ni
|
||||
else if(ni == "s")
|
||||
cur_acc[cur_note] = "#" // so shift is never required
|
||||
else
|
||||
cur_oct[cur_note] = text2num(ni)
|
||||
if(user.dizziness > 0 && prob(user.dizziness / 2))
|
||||
cur_note = CLAMP(cur_note + rand(round(-user.dizziness / 10), round(user.dizziness / 10)), 1, 7)
|
||||
if(user.dizziness > 0 && prob(user.dizziness / 5))
|
||||
if(prob(30))
|
||||
cur_acc[cur_note] = "#"
|
||||
else if(prob(42))
|
||||
cur_acc[cur_note] = "b"
|
||||
else if(prob(75))
|
||||
cur_acc[cur_note] = "n"
|
||||
playnote(cur_note, cur_acc[cur_note], cur_oct[cur_note])
|
||||
if(notes.len >= 2 && text2num(notes[2]))
|
||||
sleep(sanitize_tempo(tempo / text2num(notes[2])))
|
||||
else
|
||||
sleep(tempo)
|
||||
repeat--
|
||||
hearing_mobs = null
|
||||
playing = FALSE
|
||||
repeat = 0
|
||||
updateDialog(user)
|
||||
|
||||
/datum/song/proc/interact(mob/user)
|
||||
var/dat = ""
|
||||
|
||||
if(lines.len > 0)
|
||||
dat += "<H3>Playback</H3>"
|
||||
if(!playing)
|
||||
dat += "<A href='?src=[REF(src)];play=1'>Play</A> <SPAN CLASS='linkOn'>Stop</SPAN><BR><BR>"
|
||||
dat += "Repeat Song: "
|
||||
dat += repeat > 0 ? "<A href='?src=[REF(src)];repeat=-10'>-</A><A href='?src=[REF(src)];repeat=-1'>-</A>" : "<SPAN CLASS='linkOff'>-</SPAN><SPAN CLASS='linkOff'>-</SPAN>"
|
||||
dat += " [repeat] times "
|
||||
dat += repeat < max_repeats ? "<A href='?src=[REF(src)];repeat=1'>+</A><A href='?src=[REF(src)];repeat=10'>+</A>" : "<SPAN CLASS='linkOff'>+</SPAN><SPAN CLASS='linkOff'>+</SPAN>"
|
||||
dat += "<BR>"
|
||||
else
|
||||
dat += "<SPAN CLASS='linkOn'>Play</SPAN> <A href='?src=[REF(src)];stop=1'>Stop</A><BR>"
|
||||
dat += "Repeats left: <B>[repeat]</B><BR>"
|
||||
if(!edit)
|
||||
dat += "<BR><B><A href='?src=[REF(src)];edit=2'>Show Editor</A></B><BR>"
|
||||
else
|
||||
dat += "<H3>Editing</H3>"
|
||||
dat += "<B><A href='?src=[REF(src)];edit=1'>Hide Editor</A></B>"
|
||||
dat += " <A href='?src=[REF(src)];newsong=1'>Start a New Song</A>"
|
||||
dat += " <A href='?src=[REF(src)];import=1'>Import a Song</A><BR><BR>"
|
||||
var/bpm = round(600 / tempo)
|
||||
dat += "Tempo: <A href='?src=[REF(src)];tempo=[world.tick_lag]'>-</A> [bpm] BPM <A href='?src=[REF(src)];tempo=-[world.tick_lag]'>+</A><BR><BR>"
|
||||
var/linecount = 0
|
||||
for(var/line in lines)
|
||||
linecount += 1
|
||||
dat += "Line [linecount]: <A href='?src=[REF(src)];modifyline=[linecount]'>Edit</A> <A href='?src=[REF(src)];deleteline=[linecount]'>X</A> [line]<BR>"
|
||||
dat += "<A href='?src=[REF(src)];newline=1'>Add Line</A><BR><BR>"
|
||||
if(help)
|
||||
dat += "<B><A href='?src=[REF(src)];help=1'>Hide Help</A></B><BR>"
|
||||
dat += {"
|
||||
Lines are a series of chords, separated by commas (,), each with notes separated by hyphens (-).<br>
|
||||
Every note in a chord will play together, with chord timed by the tempo.<br>
|
||||
<br>
|
||||
Notes are played by the names of the note, and optionally, the accidental, and/or the octave number.<br>
|
||||
By default, every note is natural and in octave 3. Defining otherwise is remembered for each note.<br>
|
||||
Example: <i>C,D,E,F,G,A,B</i> will play a C major scale.<br>
|
||||
After a note has an accidental placed, it will be remembered: <i>C,C4,C,C3</i> is <i>C3,C4,C4,C3</i><br>
|
||||
Chords can be played simply by seperating each note with a hyphon: <i>A-C#,Cn-E,E-G#,Gn-B</i><br>
|
||||
A pause may be denoted by an empty chord: <i>C,E,,C,G</i><br>
|
||||
To make a chord be a different time, end it with /x, where the chord length will be length<br>
|
||||
defined by tempo / x: <i>C,G/2,E/4</i><br>
|
||||
Combined, an example is: <i>E-E4/4,F#/2,G#/8,B/8,E3-E4/4</i>
|
||||
<br>
|
||||
Lines may be up to [MUSIC_MAXLINECHARS] characters.<br>
|
||||
A song may only contain up to [MUSIC_MAXLINES] lines.<br>
|
||||
"}
|
||||
else
|
||||
dat += "<B><A href='?src=[REF(src)];help=2'>Show Help</A></B><BR>"
|
||||
|
||||
var/datum/browser/popup = new(user, "instrument", instrumentObj.name, 700, 500)
|
||||
popup.set_content(dat)
|
||||
popup.set_title_image(user.browse_rsc_icon(instrumentObj.icon, instrumentObj.icon_state))
|
||||
popup.open()
|
||||
|
||||
/datum/song/proc/ParseSong(text)
|
||||
set waitfor = FALSE
|
||||
//split into lines
|
||||
lines = splittext(text, "\n")
|
||||
if(lines.len)
|
||||
var/bpm_string = "BPM: "
|
||||
if(findtext(lines[1], bpm_string, 1, length(bpm_string) + 1))
|
||||
tempo = sanitize_tempo(600 / text2num(copytext(lines[1], length(bpm_string) + 1)))
|
||||
lines.Cut(1, 2)
|
||||
else
|
||||
tempo = sanitize_tempo(5) // default 120 BPM
|
||||
if(lines.len > MUSIC_MAXLINES)
|
||||
to_chat(usr, "Too many lines!")
|
||||
lines.Cut(MUSIC_MAXLINES + 1)
|
||||
var/linenum = 1
|
||||
for(var/l in lines)
|
||||
if(length_char(l) > MUSIC_MAXLINECHARS)
|
||||
to_chat(usr, "Line [linenum] too long!")
|
||||
lines.Remove(l)
|
||||
else
|
||||
linenum++
|
||||
updateDialog(usr) // make sure updates when complete
|
||||
|
||||
/datum/song/Topic(href, href_list)
|
||||
if(!usr.canUseTopic(instrumentObj))
|
||||
usr << browse(null, "window=instrument")
|
||||
usr.unset_machine()
|
||||
return
|
||||
|
||||
instrumentObj.add_fingerprint(usr)
|
||||
|
||||
if(href_list["newsong"])
|
||||
lines = new()
|
||||
tempo = sanitize_tempo(5) // default 120 BPM
|
||||
name = ""
|
||||
|
||||
else if(href_list["import"])
|
||||
var/t = ""
|
||||
do
|
||||
t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", name), t) as message)
|
||||
if(!in_range(instrumentObj, usr))
|
||||
return
|
||||
|
||||
if(length_char(t) >= MUSIC_MAXLINES * MUSIC_MAXLINECHARS)
|
||||
var/cont = input(usr, "Your message is too long! Would you like to continue editing it?", "", "yes") in list("yes", "no")
|
||||
if(cont == "no")
|
||||
break
|
||||
while(length_char(t) > MUSIC_MAXLINES * MUSIC_MAXLINECHARS)
|
||||
ParseSong(t)
|
||||
|
||||
else if(href_list["help"])
|
||||
help = text2num(href_list["help"]) - 1
|
||||
|
||||
else if(href_list["edit"])
|
||||
edit = text2num(href_list["edit"]) - 1
|
||||
|
||||
if(href_list["repeat"]) //Changing this from a toggle to a number of repeats to avoid infinite loops.
|
||||
if(playing)
|
||||
return //So that people cant keep adding to repeat. If the do it intentionally, it could result in the server crashing.
|
||||
repeat += round(text2num(href_list["repeat"]))
|
||||
if(repeat < 0)
|
||||
repeat = 0
|
||||
if(repeat > max_repeats)
|
||||
repeat = max_repeats
|
||||
|
||||
else if(href_list["tempo"])
|
||||
tempo = sanitize_tempo(tempo + text2num(href_list["tempo"]))
|
||||
|
||||
else if(href_list["play"])
|
||||
playing = TRUE
|
||||
spawn()
|
||||
playsong(usr)
|
||||
|
||||
else if(href_list["newline"])
|
||||
var/newline = html_encode(input("Enter your line: ", instrumentObj.name) as text|null)
|
||||
if(!newline || !in_range(instrumentObj, usr))
|
||||
return
|
||||
if(lines.len > MUSIC_MAXLINES)
|
||||
return
|
||||
if(length(newline) > MUSIC_MAXLINECHARS)
|
||||
newline = copytext(newline, 1, MUSIC_MAXLINECHARS)
|
||||
lines.Add(newline)
|
||||
|
||||
else if(href_list["deleteline"])
|
||||
var/num = round(text2num(href_list["deleteline"]))
|
||||
if(num > lines.len || num < 1)
|
||||
return
|
||||
lines.Cut(num, num+1)
|
||||
|
||||
else if(href_list["modifyline"])
|
||||
var/num = round(text2num(href_list["modifyline"]),1)
|
||||
var/content = stripped_input(usr, "Enter your line: ", instrumentObj.name, lines[num], MUSIC_MAXLINECHARS)
|
||||
if(!content || !in_range(instrumentObj, usr))
|
||||
return
|
||||
if(num > lines.len || num < 1)
|
||||
return
|
||||
lines[num] = content
|
||||
|
||||
else if(href_list["stop"])
|
||||
playing = FALSE
|
||||
hearing_mobs = null
|
||||
|
||||
updateDialog(usr)
|
||||
return
|
||||
|
||||
/datum/song/proc/sanitize_tempo(new_tempo)
|
||||
new_tempo = abs(new_tempo)
|
||||
return max(round(new_tempo, world.tick_lag), world.tick_lag)
|
||||
|
||||
// subclass for handheld instruments, like violin
|
||||
/datum/song/handheld
|
||||
|
||||
/datum/song/handheld/updateDialog(mob/user)
|
||||
instrumentObj.interact(user)
|
||||
|
||||
/datum/song/handheld/shouldStopPlaying()
|
||||
if(instrumentObj)
|
||||
return !isliving(instrumentObj.loc)
|
||||
else
|
||||
return TRUE
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/obj/structure/piano
|
||||
name = "space minimoog"
|
||||
icon = 'icons/obj/musician.dmi'
|
||||
icon_state = "minimoog"
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
var/datum/song/song
|
||||
|
||||
/obj/structure/piano/unanchored
|
||||
anchored = FALSE
|
||||
|
||||
/obj/structure/piano/New()
|
||||
..()
|
||||
song = new("piano", src)
|
||||
|
||||
if(prob(50) && icon_state == initial(icon_state))
|
||||
name = "space minimoog"
|
||||
desc = "This is a minimoog, like a space piano, but more spacey!"
|
||||
icon_state = "minimoog"
|
||||
else
|
||||
name = "space piano"
|
||||
desc = "This is a space piano, like a regular piano, but always in tune! Even if the musician isn't."
|
||||
icon_state = "piano"
|
||||
|
||||
/obj/structure/piano/Destroy()
|
||||
qdel(song)
|
||||
song = null
|
||||
return ..()
|
||||
|
||||
/obj/structure/piano/Initialize(mapload)
|
||||
. = ..()
|
||||
if(mapload)
|
||||
song.tempo = song.sanitize_tempo(song.tempo) // tick_lag isn't set when the map is loaded
|
||||
|
||||
/obj/structure/piano/attack_hand(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
interact(user)
|
||||
|
||||
/obj/structure/piano/attack_paw(mob/user)
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/structure/piano/interact(mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/structure/piano/ui_interact(mob/user)
|
||||
if(!user || !anchored)
|
||||
return
|
||||
|
||||
if(!user.IsAdvancedToolUser())
|
||||
to_chat(user, "<span class='warning'>You don't have the dexterity to do this!</span>")
|
||||
return 1
|
||||
user.set_machine(src)
|
||||
song.interact(user)
|
||||
|
||||
/obj/structure/piano/wrench_act(mob/living/user, obj/item/I)
|
||||
default_unfasten_wrench(user, I, 40)
|
||||
return TRUE
|
||||
|
||||
@@ -75,8 +75,8 @@ GLOBAL_LIST_INIT(freqtospan, list(
|
||||
return ""
|
||||
|
||||
/atom/movable/proc/say_mod(input, message_mode)
|
||||
var/ending = copytext(input, length(input))
|
||||
if(copytext(input, length(input) - 1) == "!!")
|
||||
var/ending = copytext_char(input, -1)
|
||||
if(copytext_char(input, -2) == "!!")
|
||||
return verb_yell
|
||||
else if(ending == "?")
|
||||
return verb_ask
|
||||
@@ -89,7 +89,7 @@ GLOBAL_LIST_INIT(freqtospan, list(
|
||||
if(!input)
|
||||
input = "..."
|
||||
|
||||
if(copytext(input, length(input) - 1) == "!!")
|
||||
if(copytext_char(input, -2) == "!!")
|
||||
spans |= SPAN_YELL
|
||||
|
||||
var/spanned = attach_spans(input, spans)
|
||||
@@ -136,12 +136,12 @@ GLOBAL_LIST_INIT(freqtospan, list(
|
||||
var/returntext = GLOB.reverseradiochannels["[freq]"]
|
||||
if(returntext)
|
||||
return returntext
|
||||
return "[copytext("[freq]", 1, 4)].[copytext("[freq]", 4, 5)]"
|
||||
return "[copytext_char("[freq]", 1, 4)].[copytext_char("[freq]", 4, 5)]"
|
||||
|
||||
/atom/movable/proc/attach_spans(input, list/spans)
|
||||
var/customsayverb = findtext(input, "*")
|
||||
if(customsayverb)
|
||||
input = capitalize(copytext(input, customsayverb+1))
|
||||
input = capitalize(copytext(input, length(input[customsayverb]) + 1))
|
||||
if(input)
|
||||
return "[message_spans_start(spans)][input]</span>"
|
||||
else
|
||||
@@ -155,7 +155,7 @@ GLOBAL_LIST_INIT(freqtospan, list(
|
||||
return output
|
||||
|
||||
/proc/say_test(text)
|
||||
var/ending = copytext(text, length(text))
|
||||
var/ending = copytext_char(text, -1)
|
||||
if (ending == "?")
|
||||
return "1"
|
||||
else if (ending == "!")
|
||||
|
||||
@@ -135,10 +135,10 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
var/previous_rights = 0
|
||||
//load text from file and process each line separately
|
||||
for(var/line in world.file2list("[global.config.directory]/admin_ranks.txt"))
|
||||
if(!line || findtextEx(line,"#",1,2))
|
||||
if(!line || findtextEx_char(line,"#",1,2))
|
||||
continue
|
||||
var/next = findtext(line, "=")
|
||||
var/datum/admin_rank/R = new(ckeyEx(copytext(line, 1, next)))
|
||||
var/datum/admin_rank/R = new(ckeyEx(copytext(line, 1, line[next])))
|
||||
if(!R)
|
||||
continue
|
||||
GLOB.admin_ranks += R
|
||||
@@ -146,7 +146,7 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
var/prev = findchar(line, "+-*", next, 0)
|
||||
while(prev)
|
||||
next = findchar(line, "+-*", prev + 1, 0)
|
||||
R.process_keyword(copytext(line, prev, next), previous_rights)
|
||||
R.process_keyword(copytext_char(line, prev, next), previous_rights)
|
||||
prev = next
|
||||
previous_rights = R.rights
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) || dbfail)
|
||||
|
||||
@@ -447,11 +447,9 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
|
||||
mob.name = initial(mob.name)
|
||||
mob.mouse_opacity = initial(mob.mouse_opacity)
|
||||
else
|
||||
var/new_key = ckeyEx(input("Enter your desired display name.", "Fake Key", key) as text|null)
|
||||
var/new_key = ckeyEx(stripped_input(usr, "Enter your desired display name.", "Fake Key", key, 26))
|
||||
if(!new_key)
|
||||
return
|
||||
if(length(new_key) >= 26)
|
||||
new_key = copytext(new_key, 1, 26)
|
||||
holder.fakekey = new_key
|
||||
createStealthKey()
|
||||
if(isobserver(mob))
|
||||
@@ -558,9 +556,9 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
|
||||
set desc = "Gives a spell to a mob."
|
||||
|
||||
var/list/spell_list = list()
|
||||
var/type_length = length("/obj/effect/proc_holder/spell") + 2
|
||||
var/type_length = length_char("/obj/effect/proc_holder/spell") + 2
|
||||
for(var/A in GLOB.spells)
|
||||
spell_list[copytext("[A]", type_length)] = A
|
||||
spell_list[copytext_char("[A]", type_length)] = A
|
||||
var/obj/effect/proc_holder/spell/S = input("Choose the spell to give to that guy", "ABRAKADABRA") as null|anything in spell_list
|
||||
if(!S)
|
||||
return
|
||||
|
||||
@@ -149,10 +149,10 @@
|
||||
else
|
||||
var/timeleft = SSshuttle.emergency.timeLeft()
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_CALL)
|
||||
dat += "ETA: <a href='?_src_=holder;[HrefToken()];edit_shuttle_time=1'>[(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]</a><BR>"
|
||||
dat += "ETA: <a href='?_src_=holder;[HrefToken()];edit_shuttle_time=1'>[(timeleft / 60) % 60]:[add_leading(num2text(timeleft % 60), 2, "0")]</a><BR>"
|
||||
dat += "<a href='?_src_=holder;[HrefToken()];call_shuttle=2'>Send Back</a><br>"
|
||||
else
|
||||
dat += "ETA: <a href='?_src_=holder;[HrefToken()];edit_shuttle_time=1'>[(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]</a><BR>"
|
||||
dat += "ETA: <a href='?_src_=holder;[HrefToken()];edit_shuttle_time=1'>[(timeleft / 60) % 60]:[add_leading(num2text(timeleft % 60), 2, "0")]</a><BR>"
|
||||
dat += "<B>Continuous Round Status</B><BR>"
|
||||
dat += "<a href='?_src_=holder;[HrefToken()];toggle_continuous=1'>[CONFIG_GET(keyed_list/continuous)[SSticker.mode.config_tag] ? "Continue if antagonists die" : "End on antagonist death"]</a>"
|
||||
if(CONFIG_GET(keyed_list/continuous)[SSticker.mode.config_tag])
|
||||
|
||||
@@ -345,7 +345,7 @@
|
||||
if(!SSticker.HasRoundStarted())
|
||||
alert("The game hasn't started yet!")
|
||||
return
|
||||
var/objective = copytext(sanitize(input("Enter an objective")),1,MAX_MESSAGE_LEN)
|
||||
var/objective = stripped_input(usr, "Enter an objective")
|
||||
if(!objective)
|
||||
return
|
||||
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Traitor All", "[objective]"))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -862,8 +862,8 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
|
||||
else if(ispath(expression[i]))
|
||||
val = expression[i]
|
||||
|
||||
else if(copytext(expression[i], 1, 2) in list("'", "\""))
|
||||
val = copytext(expression[i], 2, length(expression[i]))
|
||||
else if(expression[i][1] in list("'", "\""))
|
||||
val = copytext_char(expression[i], 2, -1)
|
||||
|
||||
else if(expression[i] == "\[")
|
||||
var/list/expressions_list = expression[++i]
|
||||
@@ -954,11 +954,11 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
|
||||
if(is_proper_datum(object))
|
||||
D = object
|
||||
|
||||
if (object == world && (!long || expression[start + 1] == ".") && !(expression[start] in exclude))
|
||||
if (object == world && (!long || expression[start + 1] == ".") && !(expression[start] in exclude)) //3 == length("SS") + 1
|
||||
to_chat(usr, "<span class='danger'>World variables are not allowed to be accessed. Use global.</span>")
|
||||
return null
|
||||
|
||||
else if(expression [start] == "{" && long)
|
||||
else if(expression [start] == "{" && long) //3 == length("0x") + 1
|
||||
if(lowertext(copytext(expression[start + 1], 1, 3)) != "0x")
|
||||
to_chat(usr, "<span class='danger'>Invalid pointer syntax: [expression[start + 1]]</span>")
|
||||
return null
|
||||
@@ -1063,9 +1063,10 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
|
||||
var/word = ""
|
||||
var/list/query_list = list()
|
||||
var/len = length(query_text)
|
||||
var/char = ""
|
||||
|
||||
for(var/i = 1, i <= len, i++)
|
||||
var/char = copytext(query_text, i, i + 1)
|
||||
for(var/i = 1, i <= len, i += length(char))
|
||||
char = query_text[i]
|
||||
|
||||
if(char in whitespace)
|
||||
if(word != "")
|
||||
@@ -1084,7 +1085,7 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
|
||||
query_list += word
|
||||
word = ""
|
||||
|
||||
var/char2 = copytext(query_text, i + 1, i + 2)
|
||||
var/char2 = query_text[i + length(char)]
|
||||
|
||||
if(char2 in multi[char])
|
||||
query_list += "[char][char2]"
|
||||
@@ -1100,13 +1101,13 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
|
||||
|
||||
word = "'"
|
||||
|
||||
for(i++, i <= len, i++)
|
||||
char = copytext(query_text, i, i + 1)
|
||||
for(i += length(char), i <= len, i += length(char))
|
||||
char = query_text[i]
|
||||
|
||||
if(char == "'")
|
||||
if(copytext(query_text, i + 1, i + 2) == "'")
|
||||
if(query_text[i + length(char)] == "'")
|
||||
word += "'"
|
||||
i++
|
||||
i += length(query_text[i + length(char)])
|
||||
|
||||
else
|
||||
break
|
||||
@@ -1128,13 +1129,13 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
|
||||
|
||||
word = "\""
|
||||
|
||||
for(i++, i <= len, i++)
|
||||
char = copytext(query_text, i, i + 1)
|
||||
for(i += length(char), i <= len, i += length(char))
|
||||
char = query_text[i]
|
||||
|
||||
if(char == "\"")
|
||||
if(copytext(query_text, i + 1, i + 2) == "'")
|
||||
if(query_text[i + length(char)] == "'")
|
||||
word += "\""
|
||||
i++
|
||||
i += length(query_text[i + length(char)])
|
||||
|
||||
else
|
||||
break
|
||||
|
||||
@@ -256,7 +256,7 @@
|
||||
node += "*"
|
||||
i++
|
||||
|
||||
else if (copytext(token(i), 1, 2) == "/")
|
||||
else if(token(i)[1] == "/")
|
||||
i = object_type(i, node)
|
||||
|
||||
else
|
||||
@@ -377,7 +377,7 @@
|
||||
//object_type: <type path>
|
||||
/datum/SDQL_parser/proc/object_type(i, list/node)
|
||||
|
||||
if (copytext(token(i), 1, 2) != "/")
|
||||
if(token(i)[1] != "/")
|
||||
return parse_error("Expected type, but it didn't begin with /")
|
||||
|
||||
var/path = text2path(token(i))
|
||||
@@ -416,7 +416,7 @@
|
||||
//string: ''' <some text> ''' | '"' <some text > '"'
|
||||
/datum/SDQL_parser/proc/string(i, list/node)
|
||||
|
||||
if(copytext(token(i), 1, 2) in list("'", "\""))
|
||||
if(token(i)[1] in list("'", "\""))
|
||||
node += token(i)
|
||||
|
||||
else
|
||||
@@ -427,7 +427,7 @@
|
||||
//array: '[' expression, expression, ... ']'
|
||||
/datum/SDQL_parser/proc/array(var/i, var/list/node)
|
||||
// Arrays get turned into this: list("[", list(exp_1a = exp_1b, ...), ...), "[" is to mark the next node as an array.
|
||||
if(copytext(token(i), 1, 2) != "\[")
|
||||
if(token(i)[1] != "\[")
|
||||
parse_error("Expected an array but found '[token(i)]'")
|
||||
return i + 1
|
||||
|
||||
@@ -613,7 +613,7 @@
|
||||
node += "null"
|
||||
i++
|
||||
|
||||
else if(lowertext(copytext(token(i), 1, 3)) == "0x" && isnum(hex2num(copytext(token(i), 3))))
|
||||
else if(lowertext(copytext(token(i), 1, 3)) == "0x" && isnum(hex2num(copytext(token(i), 3))))//3 == length("0x") + 1
|
||||
node += hex2num(copytext(token(i), 3))
|
||||
i++
|
||||
|
||||
@@ -621,12 +621,12 @@
|
||||
node += text2num(token(i))
|
||||
i++
|
||||
|
||||
else if(copytext(token(i), 1, 2) in list("'", "\""))
|
||||
else if(token(i)[1] in list("'", "\""))
|
||||
i = string(i, node)
|
||||
|
||||
else if(copytext(token(i), 1, 2) == "\[") // Start a list.
|
||||
else if(token(i)[1] == "\[") // Start a list.
|
||||
i = array(i, node)
|
||||
else if(copytext(token(i), 1, 2) == "/")
|
||||
else if(token(i)[1] == "/")
|
||||
i = object_type(i, node)
|
||||
else
|
||||
i = variable(i, node)
|
||||
|
||||
@@ -165,7 +165,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
//is_bwoink is TRUE if this ticket was started by an admin PM
|
||||
/datum/admin_help/New(msg, client/C, is_bwoink)
|
||||
//clean the input msg
|
||||
msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN))
|
||||
msg = sanitize(copytext_char(msg,1,MAX_MESSAGE_LEN))
|
||||
if(!msg || !C || !C.mob)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
return
|
||||
var/client/C
|
||||
if(istext(whom))
|
||||
if(cmptext(copytext(whom,1,2),"@"))
|
||||
if(whom[1] == "@")
|
||||
whom = findStealthKey(whom)
|
||||
C = GLOB.directory[whom]
|
||||
else if(istype(whom, /client))
|
||||
@@ -76,7 +76,7 @@
|
||||
var/client/recipient
|
||||
var/irc = 0
|
||||
if(istext(whom))
|
||||
if(cmptext(copytext(whom,1,2),"@"))
|
||||
if(whom[1] == "@")
|
||||
whom = findStealthKey(whom)
|
||||
if(whom == "IRCKEY")
|
||||
irc = 1
|
||||
@@ -133,7 +133,7 @@
|
||||
|
||||
//clean the message if it's not sent by a high-rank admin
|
||||
if(!check_rights(R_SERVER|R_DEBUG,0)||irc)//no sending html to the poor bots
|
||||
msg = trim(sanitize(copytext(msg,1,MAX_MESSAGE_LEN)))
|
||||
msg = trim(sanitize(msg), MAX_MESSAGE_LEN)
|
||||
if(!msg)
|
||||
return
|
||||
|
||||
@@ -287,7 +287,7 @@
|
||||
if(!stealthkey)
|
||||
stealthkey = GenIrcStealthKey()
|
||||
|
||||
msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN))
|
||||
msg = sanitize(copytext_char(msg, 1, MAX_MESSAGE_LEN))
|
||||
if(!msg)
|
||||
return "Error: No message"
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
if(!check_rights(0))
|
||||
return
|
||||
|
||||
msg = copytext(sanitize(msg), 1, MAX_MESSAGE_LEN)
|
||||
msg = copytext_char(sanitize(msg), 1, MAX_MESSAGE_LEN)
|
||||
if(!msg)
|
||||
return
|
||||
msg = emoji_parse(msg)
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
if (src.handle_spam_prevention(msg,MUTE_DEADCHAT))
|
||||
return
|
||||
|
||||
msg = copytext(sanitize(msg), 1, MAX_MESSAGE_LEN)
|
||||
msg = copytext_char(sanitize(msg), 1, MAX_MESSAGE_LEN)
|
||||
mob.log_talk(msg, LOG_DSAY)
|
||||
|
||||
if (!msg)
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
var/map = input(src, "Choose a Map Template to upload to template storage","Upload Map Template") as null|file
|
||||
if(!map)
|
||||
return
|
||||
if(copytext("[map]",-4) != ".dmm")
|
||||
if(copytext("[map]", -4) != ".dmm")//4 == length(".dmm")
|
||||
to_chat(src, "<span class='warning'>Filename must end in '.dmm': [map]</span>")
|
||||
return
|
||||
var/datum/map_template/M
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
||||
to_chat(usr, "<span class='danger'>Speech is currently admin-disabled.</span>")
|
||||
return
|
||||
|
||||
msg = copytext(sanitize(msg), 1, MAX_MESSAGE_LEN)
|
||||
msg = copytext_char(sanitize(msg), 1, MAX_MESSAGE_LEN)
|
||||
if(!msg)
|
||||
return
|
||||
log_prayer("[src.key]/([src.name]): [msg]")
|
||||
@@ -54,21 +54,21 @@
|
||||
//log_admin("HELP: [key_name(src)]: [msg]")
|
||||
|
||||
/proc/CentCom_announce(text , mob/Sender)
|
||||
var/msg = copytext(sanitize(text), 1, MAX_MESSAGE_LEN)
|
||||
var/msg = copytext_char(sanitize(text), 1, MAX_MESSAGE_LEN)
|
||||
msg = "<span class='adminnotice'><b><font color=orange>CENTCOM:</font>[ADMIN_FULLMONTY(Sender)] [ADMIN_CENTCOM_REPLY(Sender)]:</b> [msg]</span>"
|
||||
to_chat(GLOB.admins, msg)
|
||||
for(var/obj/machinery/computer/communications/C in GLOB.machines)
|
||||
C.overrideCooldown()
|
||||
|
||||
/proc/Syndicate_announce(text , mob/Sender)
|
||||
var/msg = copytext(sanitize(text), 1, MAX_MESSAGE_LEN)
|
||||
var/msg = copytext_char(sanitize(text), 1, MAX_MESSAGE_LEN)
|
||||
msg = "<span class='adminnotice'><b><font color=crimson>SYNDICATE:</font>[ADMIN_FULLMONTY(Sender)] [ADMIN_SYNDICATE_REPLY(Sender)]:</b> [msg]</span>"
|
||||
to_chat(GLOB.admins, msg)
|
||||
for(var/obj/machinery/computer/communications/C in GLOB.machines)
|
||||
C.overrideCooldown()
|
||||
|
||||
/proc/Nuke_request(text , mob/Sender)
|
||||
var/msg = copytext(sanitize(text), 1, MAX_MESSAGE_LEN)
|
||||
var/msg = copytext_char(sanitize(text), 1, MAX_MESSAGE_LEN)
|
||||
msg = "<span class='adminnotice'><b><font color=orange>NUKE CODE REQUEST:</font>[ADMIN_FULLMONTY(Sender)] [ADMIN_CENTCOM_REPLY(Sender)] [ADMIN_SET_SD_CODE]:</b> [msg]</span>"
|
||||
to_chat(GLOB.admins, msg)
|
||||
for(var/obj/machinery/computer/communications/C in GLOB.machines)
|
||||
|
||||
@@ -211,7 +211,7 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
return
|
||||
|
||||
/datum/antagonist/proc/edit_memory(mob/user)
|
||||
var/new_memo = copytext(trim(input(user,"Write new memory", "Memory", antag_memory) as null|message),1,MAX_MESSAGE_LEN)
|
||||
var/new_memo = stripped_multiline_input(user, "Write new memory", "Memory", antag_memory, MAX_MESSAGE_LEN)
|
||||
if (isnull(new_memo))
|
||||
return
|
||||
antag_memory = new_memo
|
||||
|
||||
@@ -203,7 +203,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
|
||||
|
||||
/mob/camera/blob/proc/blob_talk(message)
|
||||
|
||||
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
|
||||
message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN))
|
||||
|
||||
if (!message)
|
||||
return
|
||||
|
||||
@@ -220,8 +220,8 @@
|
||||
streak = ""
|
||||
restraining = 0
|
||||
streak = streak+element
|
||||
if(length(streak) > max_streak_length)
|
||||
streak = copytext(streak,2)
|
||||
if(length_char(streak) > max_streak_length)
|
||||
streak = streak[1]
|
||||
return
|
||||
/datum/martial_art/hunter/basic_hit(mob/living/carbon/human/A,mob/living/carbon/human/D)
|
||||
var/damage = rand(A.dna.species.punchdamagelow, A.dna.species.punchdamagehigh)
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
return
|
||||
if(client.handle_spam_prevention(message,MUTE_IC))
|
||||
return
|
||||
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
|
||||
message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN))
|
||||
if(!message)
|
||||
return
|
||||
src.log_talk(message, LOG_SAY, tag="clockwork eminence")
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
var/wizard_name_second = pick(GLOB.wizard_second)
|
||||
var/randomname = "[wizard_name_first] [wizard_name_second]"
|
||||
var/mob/living/wiz_mob = owner.current
|
||||
var/newname = copytext(sanitize(input(wiz_mob, "You are the [name]. Would you like to change your name to something else?", "Name change", randomname) as null|text),1,MAX_NAME_LEN)
|
||||
var/newname = reject_bad_name(stripped_input(wiz_mob, "You are the [name]. Would you like to change your name to something else?", "Name change", randomname, MAX_NAME_LEN))
|
||||
|
||||
if (!newname)
|
||||
newname = randomname
|
||||
|
||||
@@ -43,7 +43,7 @@ GLOBAL_LIST_INIT(potentialRandomZlevels, generateMapList(filename = "[global.con
|
||||
t = trim(t)
|
||||
if (length(t) == 0)
|
||||
continue
|
||||
else if (copytext(t, 1, 2) == "#")
|
||||
else if (t[1] == "#")
|
||||
continue
|
||||
|
||||
var/pos = findtext(t, " ")
|
||||
|
||||
@@ -411,7 +411,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
|
||||
winset(src, "[child]", "[entries[child]]")
|
||||
if (!ispath(child, /datum/verbs/menu))
|
||||
var/atom/verb/verbpath = child
|
||||
if (copytext(verbpath.name,1,2) != "@")
|
||||
if (verbpath.name[1] != "@")
|
||||
new child(src)
|
||||
|
||||
for (var/thing in prefs.menuoptions)
|
||||
|
||||
@@ -225,7 +225,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var/auto_fit_viewport = TRUE
|
||||
|
||||
var/uplink_spawn_loc = UPLINK_PDA
|
||||
|
||||
|
||||
var/sprint_spacebar = FALSE
|
||||
var/sprint_toggle = FALSE
|
||||
|
||||
@@ -1684,9 +1684,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
medical_records = rec
|
||||
|
||||
if("flavor_text")
|
||||
var/msg = stripped_multiline_input(usr, "Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!", "Flavor Text", html_decode(features["flavor_text"]), MAX_MESSAGE_LEN*2, TRUE)
|
||||
if(!isnull(msg))
|
||||
msg = copytext(msg, 1, MAX_MESSAGE_LEN*2)
|
||||
var/msg = stripped_multiline_input(usr, "Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!", "Flavor Text", html_decode(features["flavor_text"]), MAX_MESSAGE_LEN, TRUE)
|
||||
if(msg)
|
||||
msg = msg
|
||||
features["flavor_text"] = msg
|
||||
|
||||
if("hair")
|
||||
|
||||
@@ -60,7 +60,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
/datum/preferences/proc/load_path(ckey,filename="preferences.sav")
|
||||
if(!ckey)
|
||||
return
|
||||
path = "data/player_saves/[copytext(ckey,1,2)]/[ckey]/[filename]"
|
||||
path = "data/player_saves/[ckey[1]]/[ckey]/[filename]"
|
||||
|
||||
/datum/preferences/proc/load_preferences()
|
||||
if(!path)
|
||||
|
||||
@@ -31,7 +31,7 @@ GLOBAL_VAR_INIT(normal_aooc_colour, "#ce254f")
|
||||
if(QDELETED(src))
|
||||
return
|
||||
|
||||
msg = copytext(sanitize(msg), 1, MAX_MESSAGE_LEN)
|
||||
msg = copytext_char(sanitize(msg), 1, MAX_MESSAGE_LEN)
|
||||
var/raw_msg = msg
|
||||
|
||||
if(!msg)
|
||||
|
||||
@@ -16,7 +16,7 @@ GLOBAL_VAR_INIT(normal_looc_colour, "#6699CC")
|
||||
to_chat(src, "Guests may not use OOC.")
|
||||
return
|
||||
|
||||
msg = copytext(sanitize(msg), 1, MAX_MESSAGE_LEN)
|
||||
msg = copytext_char(sanitize(msg), 1, MAX_MESSAGE_LEN)
|
||||
if(!msg)
|
||||
return
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8")
|
||||
if(QDELETED(src))
|
||||
return
|
||||
|
||||
msg = copytext(sanitize(msg), 1, MAX_MESSAGE_LEN)
|
||||
msg = copytext_char(sanitize(msg), 1, MAX_MESSAGE_LEN)
|
||||
var/raw_msg = msg
|
||||
|
||||
if(!msg)
|
||||
@@ -36,7 +36,7 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8")
|
||||
|
||||
msg = emoji_parse(msg)
|
||||
|
||||
if((copytext(msg, 1, 2) in list(".",";",":","#")) || (findtext(lowertext(copytext(msg, 1, 5)), "say")))
|
||||
if((msg[1] in list(".",";",":","#")) || findtext_char(msg, "say", 1, 5))
|
||||
if(alert("Your message \"[raw_msg]\" looks like it was meant for in game communication, say it in OOC?", "Meant for OOC?", "No", "Yes") != "Yes")
|
||||
return
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@
|
||||
var/tagname = null
|
||||
|
||||
/obj/item/clothing/neck/petcollar/attack_self(mob/user)
|
||||
tagname = copytext(sanitize(input(user, "Would you like to change the name on the tag?", "Name your new pet", "Spot") as null|text),1,MAX_NAME_LEN)
|
||||
tagname = stripped_input(user, "Would you like to change the name on the tag?", "Name your new pet", "Spot", MAX_NAME_LEN)
|
||||
name = "[initial(name)] - [tagname]"
|
||||
|
||||
/obj/item/clothing/neck/petcollar/worn_overlays(isinhands, icon_file)
|
||||
|
||||
@@ -12,14 +12,14 @@
|
||||
parsed += copytext(text, pos, search)
|
||||
if(search)
|
||||
pos = search
|
||||
search = findtext(text, ":", pos+1)
|
||||
search = findtext(text, ":", pos + length(text[pos]))
|
||||
if(search)
|
||||
emoji = lowertext(copytext(text, pos+1, search))
|
||||
emoji = lowertext(copytext(text, pos + length(text[pos]), search))
|
||||
var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/goonchat)
|
||||
var/tag = sheet.icon_tag("emoji-[emoji]")
|
||||
if(tag)
|
||||
parsed += tag
|
||||
pos = search + 1
|
||||
pos = search + length(text[pos])
|
||||
else
|
||||
parsed += copytext(text, pos, search)
|
||||
pos = search
|
||||
@@ -30,3 +30,24 @@
|
||||
break
|
||||
return parsed
|
||||
|
||||
/proc/emoji_sanitize(text) //cuts any text that would not be parsed as an emoji
|
||||
. = text
|
||||
if(!CONFIG_GET(flag/emojis))
|
||||
return
|
||||
var/static/list/emojis = icon_states(icon('icons/emoji.dmi'))
|
||||
var/final = "" //only tags are added to this
|
||||
var/pos = 1
|
||||
var/search = 0
|
||||
while(1)
|
||||
search = findtext(text, ":", pos)
|
||||
if(search)
|
||||
pos = search
|
||||
search = findtext(text, ":", pos + length(text[pos]))
|
||||
if(search)
|
||||
var/word = lowertext(copytext(text, pos + length(text[pos]), search))
|
||||
if(word in emojis)
|
||||
final += lowertext(copytext(text, pos, search + length(text[search])))
|
||||
pos = search + length(text[search])
|
||||
continue
|
||||
break
|
||||
return final
|
||||
|
||||
@@ -12,7 +12,7 @@ GLOBAL_VAR_INIT(total_runtimes_skipped, 0)
|
||||
return ..()
|
||||
|
||||
//this is snowflake because of a byond bug (ID:2306577), do not attempt to call non-builtin procs in this if
|
||||
if(copytext(E.name,1,32) == "Maximum recursion level reached")
|
||||
if(copytext(E.name, 1, 32) == "Maximum recursion level reached")//32 == length() of that string + 1
|
||||
//log to world while intentionally triggering the byond bug.
|
||||
log_world("runtime error: [E.name]\n[E.desc]")
|
||||
//if we got to here without silently ending, the byond bug has been fixed.
|
||||
@@ -102,7 +102,7 @@ GLOBAL_VAR_INIT(total_runtimes_skipped, 0)
|
||||
usrinfo = null
|
||||
continue // Our usr info is better, replace it
|
||||
|
||||
if(copytext(line, 1, 3) != " ")
|
||||
if(copytext(line, 1, 3) != " ")//3 == length(" ") + 1
|
||||
desclines += (" " + line) // Pad any unpadded lines, so they look pretty
|
||||
else
|
||||
desclines += line
|
||||
|
||||
@@ -62,8 +62,8 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
|
||||
// Arguments are in the form "param[paramname]=thing"
|
||||
var/list/params = list()
|
||||
for(var/key in href_list)
|
||||
if(length(key) > 7 && findtext(key, "param")) // 7 is the amount of characters in the basic param key template.
|
||||
var/param_name = copytext(key, 7, -1)
|
||||
if(length_char(key) > 7 && findtext(key, "param")) // 7 is the amount of characters in the basic param key template.
|
||||
var/param_name = copytext_char(key, 7, -1)
|
||||
var/item = href_list[key]
|
||||
|
||||
params[param_name] = item
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
// Returns special prefixes for the station name on certain days. You wind up with names like "Christmas Object Epsilon". See new_station_name()
|
||||
/datum/holiday/proc/getStationPrefix()
|
||||
//get the first word of the Holiday and use that
|
||||
var/i = findtext(name," ",1,0)
|
||||
return copytext(name,1,i)
|
||||
var/i = findtext(name," ")
|
||||
return copytext(name, 1, i)
|
||||
|
||||
// Return 1 if this holidy should be celebrated today
|
||||
/datum/holiday/proc/shouldCelebrate(dd, mm, yy, ww, ddd)
|
||||
|
||||
@@ -401,7 +401,7 @@
|
||||
/obj/machinery/plantgenes/proc/repaint_seed()
|
||||
if(!seed)
|
||||
return
|
||||
if(copytext(seed.name, 1, 13) == "experimental")
|
||||
if(copytext(seed.name, 1, 13) == "experimental")//13 == length("experimental") + 1
|
||||
return // Already modded name and icon
|
||||
seed.name = "experimental " + seed.name
|
||||
seed.icon_state = "seed-x"
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
new_data = uppertext(new_data)
|
||||
if(length(new_data) != 7) // We can hex if we want to, we can leave your strings behind
|
||||
return // Cause your strings don't hex and if they don't hex
|
||||
var/friends = copytext(new_data, 2, 8) // Well they're are no strings of mine
|
||||
var/friends = copytext_char(new_data, 2, 8) // Well they're are no strings of mine
|
||||
// I say, we can go where we want to, a place where they will never find
|
||||
var/safety_dance = 1
|
||||
while(safety_dance >= 7) // And we can act like we come from out of this world.log
|
||||
var/hex = copytext(friends, safety_dance, safety_dance+1)
|
||||
var/hex = copytext_char(friends, safety_dance, safety_dance+1)
|
||||
if(!(hex in list("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")))
|
||||
return // Leave the fake one far behind,
|
||||
safety_dance++
|
||||
|
||||
@@ -224,8 +224,8 @@
|
||||
|
||||
var/split = min(index+1, length(text))
|
||||
|
||||
var/before_text = copytext(text, 1, split)
|
||||
var/after_text = copytext(text, split, 0)
|
||||
var/before_text = copytext_char(text, 1, split)
|
||||
var/after_text = copytext_char(text, split)
|
||||
|
||||
set_pin_data(IC_OUTPUT, 1, before_text)
|
||||
set_pin_data(IC_OUTPUT, 2, after_text)
|
||||
@@ -331,7 +331,7 @@
|
||||
var/strin = get_pin_data(IC_INPUT, 1)
|
||||
var/delimiter = get_pin_data(IC_INPUT, 2)
|
||||
if(delimiter == null)
|
||||
set_pin_data(IC_OUTPUT, 1, string2charlist(strin))
|
||||
set_pin_data(IC_OUTPUT, 1, text2charlist(strin))
|
||||
else
|
||||
set_pin_data(IC_OUTPUT, 1, splittext(strin, delimiter))
|
||||
push_data()
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
|
||||
. = ""
|
||||
var/list/words = list()
|
||||
while(length(.) < length(input))
|
||||
while(length_char(.) < length_char(input))
|
||||
words += generate_code_phrase(return_list=TRUE)
|
||||
. = jointext(words, ", ")
|
||||
|
||||
. = capitalize(.)
|
||||
|
||||
var/input_ending = copytext(input, length(input))
|
||||
var/input_ending = copytext_char(input, -1)
|
||||
|
||||
var/static/list/endings
|
||||
if(!endings)
|
||||
|
||||
@@ -81,11 +81,11 @@
|
||||
if(lookup)
|
||||
return lookup
|
||||
|
||||
var/input_size = length(input)
|
||||
var/input_size = length_char(input)
|
||||
var/scrambled_text = ""
|
||||
var/capitalize = TRUE
|
||||
|
||||
while(length(scrambled_text) < input_size)
|
||||
while(length_char(scrambled_text) < input_size)
|
||||
var/next = pick(syllables)
|
||||
if(capitalize)
|
||||
next = capitalize(next)
|
||||
@@ -99,10 +99,10 @@
|
||||
scrambled_text += " "
|
||||
|
||||
scrambled_text = trim(scrambled_text)
|
||||
var/ending = copytext(scrambled_text, length(scrambled_text))
|
||||
var/ending = copytext_char(scrambled_text, -1)
|
||||
if(ending == ".")
|
||||
scrambled_text = copytext(scrambled_text,1,length(scrambled_text)-1)
|
||||
var/input_ending = copytext(input, input_size)
|
||||
scrambled_text = copytext_char(scrambled_text, 1, -2)
|
||||
var/input_ending = copytext_char(input, -1)
|
||||
if(input_ending in list("!","?","."))
|
||||
scrambled_text += input_ending
|
||||
|
||||
|
||||
@@ -384,9 +384,9 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
|
||||
if(checkoutperiod < 1)
|
||||
checkoutperiod = 1
|
||||
if(href_list["editbook"])
|
||||
buffer_book = copytext(sanitize(input("Enter the book's title:") as text|null),1,MAX_MESSAGE_LEN)
|
||||
buffer_book = stripped_input(usr, "Enter the book's title:")
|
||||
if(href_list["editmob"])
|
||||
buffer_mob = copytext(sanitize(input("Enter the recipient's name:") as text|null),1,MAX_NAME_LEN)
|
||||
buffer_mob = stripped_input(usr, "Enter the recipient's name:", max_length = MAX_NAME_LEN)
|
||||
if(href_list["checkout"])
|
||||
var/datum/borrowbook/b = new /datum/borrowbook
|
||||
b.bookname = sanitize(buffer_book)
|
||||
@@ -403,7 +403,7 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
|
||||
if(b && istype(b))
|
||||
inventory.Remove(b)
|
||||
if(href_list["setauthor"])
|
||||
var/newauthor = copytext(sanitize(input("Enter the author's name: ") as text|null),1,MAX_MESSAGE_LEN)
|
||||
var/newauthor = stripped_input(usr, "Enter the author's name: ")
|
||||
if(newauthor)
|
||||
scanner.cache.author = newauthor
|
||||
if(href_list["setcategory"])
|
||||
|
||||
@@ -150,7 +150,7 @@
|
||||
/obj/structure/chisel_message/update_icon()
|
||||
..()
|
||||
var/hash = md5(hidden_message)
|
||||
var/newcolor = copytext(hash, 1, 7)
|
||||
var/newcolor = copytext_char(hash, 1, 7)
|
||||
add_atom_colour("#[newcolor]", FIXED_COLOUR_PRIORITY)
|
||||
light_color = "#[newcolor]"
|
||||
light_power = 0.3
|
||||
|
||||
@@ -241,7 +241,8 @@
|
||||
var/variables_start = findtext(full_def, "{")
|
||||
var/path_text = trim_text(copytext(full_def, 1, variables_start))
|
||||
var/atom_def = text2path(path_text) //path definition, e.g /obj/foo/bar
|
||||
old_position = dpos + 1
|
||||
if(dpos)
|
||||
old_position = dpos + length(model[dpos])
|
||||
|
||||
if(!ispath(atom_def, /atom)) // Skip the item if the path does not exist. Fix your crap, mappers!
|
||||
if(bad_paths)
|
||||
@@ -253,7 +254,7 @@
|
||||
var/list/fields = list()
|
||||
|
||||
if(variables_start)//if there's any variable
|
||||
full_def = copytext(full_def,variables_start+1,length(full_def))//removing the last '}'
|
||||
full_def = copytext(full_def, variables_start + length(full_def[variables_start]), -length(copytext_char(full_def, -1))) //removing the last '}'
|
||||
fields = readlist(full_def, ";")
|
||||
if(fields.len)
|
||||
if(!trim(fields[fields.len]))
|
||||
@@ -423,12 +424,13 @@
|
||||
|
||||
var/trim_left = trim_text(copytext(text,old_position,(equal_position ? equal_position : position)))
|
||||
var/left_constant = delimiter == ";" ? trim_left : parse_constant(trim_left)
|
||||
old_position = position + 1
|
||||
if(position)
|
||||
old_position = position + length(text[position])
|
||||
|
||||
if(equal_position && !isnum(left_constant))
|
||||
// Associative var, so do the association.
|
||||
// Note that numbers cannot be keys - the RHS is dropped if so.
|
||||
var/trim_right = trim_text(copytext(text,equal_position+1,position))
|
||||
var/trim_right = trim_text(copytext(text, equal_position + length(text[equal_position]), position))
|
||||
var/right_constant = parse_constant(trim_right)
|
||||
.[left_constant] = right_constant
|
||||
|
||||
@@ -442,12 +444,12 @@
|
||||
return num
|
||||
|
||||
// string
|
||||
if(findtext(text,"\"",1,2))
|
||||
return copytext(text,2,findtext(text,"\"",3,0))
|
||||
if(text[1] == "\"")
|
||||
return copytext(text, length(text[1]) + 1, findtext(text, "\"", length(text[1]) + 1))
|
||||
|
||||
// list
|
||||
if(copytext(text,1,6) == "list(")
|
||||
return readlist(copytext(text,6,length(text)))
|
||||
if(copytext(text, 1, 6) == "list(")//6 == length("list(") + 1
|
||||
return readlist(copytext(text, 6, -1))
|
||||
|
||||
// typepath
|
||||
var/path = text2path(text)
|
||||
@@ -455,8 +457,8 @@
|
||||
return path
|
||||
|
||||
// file
|
||||
if(copytext(text,1,2) == "'")
|
||||
return file(copytext(text,2,length(text)))
|
||||
if(text[1] == "'")
|
||||
return file(copytext_char(text, 2, -1))
|
||||
|
||||
// null
|
||||
if(text == "null")
|
||||
|
||||
@@ -60,8 +60,9 @@
|
||||
// build_cache will check bad paths for us
|
||||
var/list/modelCache = build_cache(TRUE, report.bad_paths)
|
||||
|
||||
var/static/regex/area_or_turf = regex(@"/(turf|area)/")
|
||||
for(var/path in report.bad_paths)
|
||||
if(copytext(path, 1, 7) == "/turf/" || copytext(path, 1, 7) == "/area/")
|
||||
if(area_or_turf.Find("[path]", 1, 1))
|
||||
report.loadable = FALSE
|
||||
|
||||
// check for tiles with the wrong number of turfs or areas
|
||||
|
||||
@@ -157,19 +157,22 @@
|
||||
var/input = input(usr, "Enter [codelen] digits. All digits must be unique.", "Deca-Code Lock", "") as text
|
||||
if(user.canUseTopic(src, BE_CLOSE))
|
||||
var/list/sanitised = list()
|
||||
var/sanitycheck = 1
|
||||
for(var/i=1,i<=length(input),i++) //put the guess into a list
|
||||
sanitised += text2num(copytext(input,i,i+1))
|
||||
for(var/i=1,i<=(length(input)-1),i++) //compare each digit in the guess to all those following it
|
||||
for(var/j=(i+1),j<=length(input),j++)
|
||||
var/sanitycheck = TRUE
|
||||
var/char = ""
|
||||
var/length_input = length(input)
|
||||
for(var/i = 1, i <= length_input, i += length(char)) //put the guess into a list
|
||||
char = input[i]
|
||||
sanitised += text2num(char)
|
||||
for(var/i = 1, i <= length(sanitised) - 1, i++) //compare each digit in the guess to all those following it
|
||||
for(var/j = i + 1, j <= length(sanitised), j++)
|
||||
if(sanitised[i] == sanitised[j])
|
||||
sanitycheck = null //if a digit is repeated, reject the input
|
||||
if (input == code)
|
||||
sanitycheck = FALSE //if a digit is repeated, reject the input
|
||||
if(input == code)
|
||||
to_chat(user, "<span class='notice'>The crate unlocks!</span>")
|
||||
locked = FALSE
|
||||
cut_overlays()
|
||||
add_overlay("securecrateg")
|
||||
else if (input == null || sanitycheck == null || length(input) != codelen)
|
||||
else if(!input || !sanitycheck || length(sanitised) != codelen)
|
||||
to_chat(user, "<span class='notice'>You leave the crate alone.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>A red light flashes.</span>")
|
||||
@@ -195,20 +198,27 @@
|
||||
else
|
||||
to_chat(user, "<span class='notice'>* Anti-Tamper Bomb will activate after [attempts] failed access attempts.</span>")
|
||||
if(lastattempt != null)
|
||||
var/list/guess = list()
|
||||
var/list/answer = list()
|
||||
var/bulls = 0
|
||||
var/cows = 0
|
||||
for(var/i=1,i<=length(lastattempt),i++)
|
||||
guess += text2num(copytext(lastattempt,i,i+1))
|
||||
for(var/i=1,i<=length(lastattempt),i++)
|
||||
answer += text2num(copytext(code,i,i+1))
|
||||
for(var/i = 1, i < codelen + 1, i++) // Go through list and count matches
|
||||
if( answer.Find(guess[i],1,codelen+1))
|
||||
++cows
|
||||
if( answer[i] == guess[i])
|
||||
var/bulls = 0 //right position, right number
|
||||
var/cows = 0 //wrong position but in the puzzle
|
||||
|
||||
var/lastattempt_char = ""
|
||||
var/length_lastattempt = length(lastattempt)
|
||||
var/lastattempt_it = 1
|
||||
|
||||
var/code_char = ""
|
||||
var/length_code = length(code)
|
||||
var/code_it = 1
|
||||
|
||||
while(lastattempt_it <= length_lastattempt && code_it <= length_code) // Go through list and count matches
|
||||
lastattempt_char = lastattempt[lastattempt_it]
|
||||
code_char = code[code_it]
|
||||
if(lastattempt_char == code_char)
|
||||
++bulls
|
||||
--cows
|
||||
else if(findtext(code, lastattempt_char))
|
||||
++cows
|
||||
|
||||
lastattempt_it += length(lastattempt_char)
|
||||
code_it += length(code_char)
|
||||
|
||||
to_chat(user, "<span class='notice'>Last code attempt, [lastattempt], had [bulls] correct digits at correct positions and [cows] correct digits at incorrect positions.</span>")
|
||||
return
|
||||
|
||||
@@ -230,5 +230,5 @@ GLOBAL_LIST_EMPTY(silo_access_logs)
|
||||
var/val = round(materials[key]) / MINERAL_MATERIAL_AMOUNT
|
||||
msg += sep
|
||||
sep = ", "
|
||||
msg += "[amount < 0 ? "-" : "+"][val] [copytext(key, 2)]"
|
||||
msg += "[amount < 0 ? "-" : "+"][val] [copytext(key, length(key[1]) + 1)]"
|
||||
formatted = msg.Join()
|
||||
|
||||
@@ -232,14 +232,16 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
|
||||
var/b_val
|
||||
var/g_val
|
||||
var/color_format = length(input_color)
|
||||
if(color_format != length_char(input_color))
|
||||
return 0
|
||||
if(color_format == 3)
|
||||
r_val = hex2num(copytext(input_color, 1, 2))*16
|
||||
g_val = hex2num(copytext(input_color, 2, 3))*16
|
||||
b_val = hex2num(copytext(input_color, 3, 0))*16
|
||||
r_val = hex2num(copytext(input_color, 1, 2)) * 16
|
||||
g_val = hex2num(copytext(input_color, 2, 3)) * 16
|
||||
b_val = hex2num(copytext(input_color, 3, 0)) * 16
|
||||
else if(color_format == 6)
|
||||
r_val = hex2num(copytext(input_color, 1, 3))
|
||||
g_val = hex2num(copytext(input_color, 3, 5))
|
||||
b_val = hex2num(copytext(input_color, 5, 0))
|
||||
b_val = hex2num(copytext(input_color, 5, 7))
|
||||
else
|
||||
return 0 //If the color format is not 3 or 6, you're using an unexpected way to represent a color.
|
||||
|
||||
@@ -253,7 +255,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
|
||||
if(b_val > 255)
|
||||
b_val = 255
|
||||
|
||||
return num2hex(r_val, 2) + num2hex(g_val, 2) + num2hex(b_val, 2)
|
||||
return copytext(rgb(r_val, g_val, b_val), 2)
|
||||
|
||||
/*
|
||||
Transfer_mind is there to check if mob is being deleted/not going to have a body.
|
||||
@@ -262,7 +264,7 @@ Works together with spawning an observer, noted above.
|
||||
|
||||
/mob/proc/ghostize(can_reenter_corpse = TRUE, special = FALSE, penalize = FALSE)
|
||||
penalize = suiciding || penalize // suicide squad.
|
||||
if(!key || cmptext(copytext(key,1,2),"@") || (SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, can_reenter_corpse, special, penalize) & COMPONENT_BLOCK_GHOSTING))
|
||||
if(!key || key[1] == "@" || (SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, can_reenter_corpse, special, penalize) & COMPONENT_BLOCK_GHOSTING))
|
||||
return //mob has no key, is an aghost or some component hijacked.
|
||||
stop_sound_channel(CHANNEL_HEARTBEAT) //Stop heartbeat sounds because You Are A Ghost Now
|
||||
var/mob/dead/observer/ghost = new(src) // Transfer safety to observer spawning proc.
|
||||
@@ -357,7 +359,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
if(!can_reenter_corpse)
|
||||
to_chat(src, "<span class='warning'>You cannot re-enter your body.</span>")
|
||||
return
|
||||
if(mind.current.key && copytext(mind.current.key,1,2)!="@") //makes sure we don't accidentally kick any clients
|
||||
if(mind.current.key && mind.current.key[1] != "@") //makes sure we don't accidentally kick any clients
|
||||
to_chat(usr, "<span class='warning'>Another consciousness is in your body...It is resisting you.</span>")
|
||||
return
|
||||
client.change_view(CONFIG_GET(string/default_view))
|
||||
|
||||
@@ -1,43 +1,42 @@
|
||||
/mob/dead/observer/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
|
||||
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
|
||||
if (!message)
|
||||
return
|
||||
|
||||
var/message_mode = get_message_mode(message)
|
||||
if(client && (message_mode == MODE_ADMIN || message_mode == MODE_DEADMIN))
|
||||
message = copytext(message, 3)
|
||||
if(findtext(message, " ", 1, 2))
|
||||
message = copytext(message, 2)
|
||||
|
||||
if(message_mode == MODE_ADMIN)
|
||||
client.cmd_admin_say(message)
|
||||
else if(message_mode == MODE_DEADMIN)
|
||||
client.dsay(message)
|
||||
return
|
||||
|
||||
src.log_talk(message, LOG_SAY, tag="ghost")
|
||||
|
||||
if(check_emote(message))
|
||||
return
|
||||
|
||||
. = say_dead(message)
|
||||
|
||||
/mob/dead/observer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
|
||||
. = ..()
|
||||
var/atom/movable/to_follow = speaker
|
||||
if(radio_freq)
|
||||
var/atom/movable/virtualspeaker/V = speaker
|
||||
|
||||
if(isAI(V.source))
|
||||
var/mob/living/silicon/ai/S = V.source
|
||||
to_follow = S.eyeobj
|
||||
else
|
||||
to_follow = V.source
|
||||
var/link = FOLLOW_LINK(src, to_follow)
|
||||
// Create map text prior to modifying message for goonchat
|
||||
if (client?.prefs.chat_on_map && (client.prefs.see_chat_non_mob || ismob(speaker)))
|
||||
create_chat_message(speaker, message_language, raw_message, spans, message_mode)
|
||||
// Recompose the message, because it's scrambled by default
|
||||
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source)
|
||||
to_chat(src, "[link] [message]")
|
||||
|
||||
/mob/dead/observer/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
|
||||
message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN))
|
||||
if (!message)
|
||||
return
|
||||
|
||||
var/message_mode = get_message_mode(message)
|
||||
if(client && (message_mode == MODE_ADMIN || message_mode == MODE_DEADMIN))
|
||||
message = copytext_char(message, 3)
|
||||
message = trim_left(message)
|
||||
|
||||
if(message_mode == MODE_ADMIN)
|
||||
client.cmd_admin_say(message)
|
||||
else if(message_mode == MODE_DEADMIN)
|
||||
client.dsay(message)
|
||||
return
|
||||
|
||||
src.log_talk(message, LOG_SAY, tag="ghost")
|
||||
|
||||
if(check_emote(message))
|
||||
return
|
||||
|
||||
. = say_dead(message)
|
||||
|
||||
/mob/dead/observer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
|
||||
. = ..()
|
||||
var/atom/movable/to_follow = speaker
|
||||
if(radio_freq)
|
||||
var/atom/movable/virtualspeaker/V = speaker
|
||||
|
||||
if(isAI(V.source))
|
||||
var/mob/living/silicon/ai/S = V.source
|
||||
to_follow = S.eyeobj
|
||||
else
|
||||
to_follow = V.source
|
||||
var/link = FOLLOW_LINK(src, to_follow)
|
||||
// Create map text prior to modifying message for goonchat
|
||||
if (client?.prefs.chat_on_map && (client.prefs.see_chat_non_mob || ismob(speaker)))
|
||||
create_chat_message(speaker, message_language, raw_message, spans, message_mode)
|
||||
// Recompose the message, because it's scrambled by default
|
||||
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source)
|
||||
to_chat(src, "[link] [message]")
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
var/param = message
|
||||
var/custom_param = findchar(act, " ")
|
||||
if(custom_param)
|
||||
param = copytext(act, custom_param + 1, length(act) + 1)
|
||||
param = copytext(act, custom_param + length(act[custom_param]))
|
||||
act = copytext(act, 1, custom_param)
|
||||
|
||||
var/datum/emote/E
|
||||
|
||||
@@ -185,7 +185,7 @@
|
||||
var/datum/disease/D = thing
|
||||
blood_data["viruses"] += D.Copy()
|
||||
|
||||
blood_data["blood_DNA"] = copytext(dna.unique_enzymes,1,0)
|
||||
blood_data["blood_DNA"] = dna.unique_enzymes
|
||||
blood_data["bloodcolor"] = bloodtype_to_color(dna.blood_type)
|
||||
if(disease_resistances && disease_resistances.len)
|
||||
blood_data["resistances"] = disease_resistances.Copy()
|
||||
@@ -204,7 +204,7 @@
|
||||
|
||||
if(!suiciding)
|
||||
blood_data["cloneable"] = 1
|
||||
blood_data["blood_type"] = copytext(dna.blood_type,1,0)
|
||||
blood_data["blood_type"] = dna.blood_type
|
||||
blood_data["gender"] = gender
|
||||
blood_data["real_name"] = real_name
|
||||
blood_data["features"] = dna.features
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user