mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-10 02:16:05 +00:00
All the EOLs are now LF.
Fuck you too 0D :^)
This commit is contained in:
@@ -1,109 +1,109 @@
|
||||
//checks if a file exists and contains text
|
||||
//returns text as a string if these conditions are met
|
||||
/proc/return_file_text(filename)
|
||||
if(fexists(filename) == 0)
|
||||
error("File not found ([filename])")
|
||||
return
|
||||
|
||||
var/text = file2text(filename)
|
||||
if(!text)
|
||||
error("File empty ([filename])")
|
||||
return
|
||||
|
||||
return text
|
||||
|
||||
/proc/get_maps(root="maps/voting/")
|
||||
var/list/maps = list()
|
||||
var/recursion_limit = 20 //lots of maps waiting to be played, feels like TF2
|
||||
//Get our potential maps
|
||||
//testing("starting in [root]")
|
||||
for(var/potential in flist(root))
|
||||
if(copytext(potential,-1,0 != "/")) continue // Not a directory, ignore it.
|
||||
//testing("Inside [root + potential]")
|
||||
if(!recursion_limit) break
|
||||
//our current working directory
|
||||
var/path = root + potential
|
||||
//The DMB that has the map we want.
|
||||
var/binary
|
||||
//Looking for a binary
|
||||
var/min = -1
|
||||
var/max = -1
|
||||
var/skipping = 0
|
||||
for(var/binaries in flist(path))
|
||||
//testing("Checking file [binaries]")
|
||||
if(copytext(binaries,-15,0 == "playercount.txt"))
|
||||
var/list/lines = file2list(path+binaries)
|
||||
for(var/line in lines)
|
||||
if(findtext(line,"max")) max = text2num(copytext(line,5,0))
|
||||
else if(findtext(line,"min")) min = text2num(copytext(line,5,0))
|
||||
else warning("Our file had excessive lines, skipping.")
|
||||
if(!isnull(min) && !isnull(max))
|
||||
if((min != -1) && clients.len < min)
|
||||
skipping = 1
|
||||
else if((max != -1) && clients.len > max)
|
||||
skipping = 2
|
||||
if(copytext(binaries,-4,0) == ".dmb")
|
||||
if(binary)
|
||||
warning("Extra DMB [binary] in map folder, skipping.")
|
||||
continue
|
||||
binary = binaries
|
||||
continue
|
||||
if(skipping)
|
||||
message_admins("Skipping map [binary] due to [skipping == 1 ? "not enough players." : "too many players."]")
|
||||
warning("Skipping map [binary] due to [skipping == 1 ? "not enough players." : "too many players."]")
|
||||
binary = null
|
||||
continue
|
||||
if(!binary)
|
||||
warning("Map folder [path] does not contain a valid byond binary, skipping.")
|
||||
else
|
||||
maps[potential] = path + binary
|
||||
binary = null
|
||||
recursion_limit--
|
||||
return maps
|
||||
|
||||
//Sends resource files to client cache
|
||||
/client/proc/getFiles()
|
||||
for(var/file in args)
|
||||
src << browse_rsc(file)
|
||||
|
||||
/client/proc/browse_files(root="data/logs/", max_iterations=10, list/valid_extensions=list(".txt",".log",".htm", ".csv"))
|
||||
var/path = root
|
||||
|
||||
for(var/i=0, i<max_iterations, i++)
|
||||
var/list/choices = flist(path)
|
||||
if(path != root)
|
||||
choices.Insert(1,"/")
|
||||
|
||||
var/choice = input(src,"Choose a file to access:","Download",null) as null|anything in choices
|
||||
switch(choice)
|
||||
if(null)
|
||||
return
|
||||
if("/")
|
||||
path = root
|
||||
continue
|
||||
path += choice
|
||||
|
||||
if(copytext(path,-1,0) != "/") //didn't choose a directory, no need to iterate again
|
||||
break
|
||||
|
||||
var/extension = copytext(path,-4,0)
|
||||
if( !fexists(path) || !(extension in valid_extensions) )
|
||||
//checks if a file exists and contains text
|
||||
//returns text as a string if these conditions are met
|
||||
/proc/return_file_text(filename)
|
||||
if(fexists(filename) == 0)
|
||||
error("File not found ([filename])")
|
||||
return
|
||||
|
||||
var/text = file2text(filename)
|
||||
if(!text)
|
||||
error("File empty ([filename])")
|
||||
return
|
||||
|
||||
return text
|
||||
|
||||
/proc/get_maps(root="maps/voting/")
|
||||
var/list/maps = list()
|
||||
var/recursion_limit = 20 //lots of maps waiting to be played, feels like TF2
|
||||
//Get our potential maps
|
||||
//testing("starting in [root]")
|
||||
for(var/potential in flist(root))
|
||||
if(copytext(potential,-1,0 != "/")) continue // Not a directory, ignore it.
|
||||
//testing("Inside [root + potential]")
|
||||
if(!recursion_limit) break
|
||||
//our current working directory
|
||||
var/path = root + potential
|
||||
//The DMB that has the map we want.
|
||||
var/binary
|
||||
//Looking for a binary
|
||||
var/min = -1
|
||||
var/max = -1
|
||||
var/skipping = 0
|
||||
for(var/binaries in flist(path))
|
||||
//testing("Checking file [binaries]")
|
||||
if(copytext(binaries,-15,0 == "playercount.txt"))
|
||||
var/list/lines = file2list(path+binaries)
|
||||
for(var/line in lines)
|
||||
if(findtext(line,"max")) max = text2num(copytext(line,5,0))
|
||||
else if(findtext(line,"min")) min = text2num(copytext(line,5,0))
|
||||
else warning("Our file had excessive lines, skipping.")
|
||||
if(!isnull(min) && !isnull(max))
|
||||
if((min != -1) && clients.len < min)
|
||||
skipping = 1
|
||||
else if((max != -1) && clients.len > max)
|
||||
skipping = 2
|
||||
if(copytext(binaries,-4,0) == ".dmb")
|
||||
if(binary)
|
||||
warning("Extra DMB [binary] in map folder, skipping.")
|
||||
continue
|
||||
binary = binaries
|
||||
continue
|
||||
if(skipping)
|
||||
message_admins("Skipping map [binary] due to [skipping == 1 ? "not enough players." : "too many players."]")
|
||||
warning("Skipping map [binary] due to [skipping == 1 ? "not enough players." : "too many players."]")
|
||||
binary = null
|
||||
continue
|
||||
if(!binary)
|
||||
warning("Map folder [path] does not contain a valid byond binary, skipping.")
|
||||
else
|
||||
maps[potential] = path + binary
|
||||
binary = null
|
||||
recursion_limit--
|
||||
return maps
|
||||
|
||||
//Sends resource files to client cache
|
||||
/client/proc/getFiles()
|
||||
for(var/file in args)
|
||||
src << browse_rsc(file)
|
||||
|
||||
/client/proc/browse_files(root="data/logs/", max_iterations=10, list/valid_extensions=list(".txt",".log",".htm", ".csv"))
|
||||
var/path = root
|
||||
|
||||
for(var/i=0, i<max_iterations, i++)
|
||||
var/list/choices = flist(path)
|
||||
if(path != root)
|
||||
choices.Insert(1,"/")
|
||||
|
||||
var/choice = input(src,"Choose a file to access:","Download",null) as null|anything in choices
|
||||
switch(choice)
|
||||
if(null)
|
||||
return
|
||||
if("/")
|
||||
path = root
|
||||
continue
|
||||
path += choice
|
||||
|
||||
if(copytext(path,-1,0) != "/") //didn't choose a directory, no need to iterate again
|
||||
break
|
||||
|
||||
var/extension = copytext(path,-4,0)
|
||||
if( !fexists(path) || !(extension in valid_extensions) )
|
||||
to_chat(src, "<font color='red'>Error: browse_files(): File not found/Invalid file([path]).</font>")
|
||||
return
|
||||
|
||||
return path
|
||||
|
||||
#define FTPDELAY 200 //200 tick delay to discourage spam
|
||||
/* This proc is a failsafe to prevent spamming of file requests.
|
||||
It is just a timer that only permits a download every [FTPDELAY] ticks.
|
||||
This can be changed by modifying FTPDELAY's value above.
|
||||
|
||||
PLEASE USE RESPONSIBLY, Some log files canr each sizes of 4MB! */
|
||||
/client/proc/file_spam_check()
|
||||
var/time_to_wait = fileaccess_timer - world.time
|
||||
if(time_to_wait > 0)
|
||||
return
|
||||
|
||||
return path
|
||||
|
||||
#define FTPDELAY 200 //200 tick delay to discourage spam
|
||||
/* This proc is a failsafe to prevent spamming of file requests.
|
||||
It is just a timer that only permits a download every [FTPDELAY] ticks.
|
||||
This can be changed by modifying FTPDELAY's value above.
|
||||
|
||||
PLEASE USE RESPONSIBLY, Some log files canr each sizes of 4MB! */
|
||||
/client/proc/file_spam_check()
|
||||
var/time_to_wait = fileaccess_timer - world.time
|
||||
if(time_to_wait > 0)
|
||||
to_chat(src, "<font color='red'>Error: file_spam_check(): Spam. Please wait [round(time_to_wait/10)] seconds.</font>")
|
||||
return 1
|
||||
fileaccess_timer = world.time + FTPDELAY
|
||||
return 0
|
||||
return 1
|
||||
fileaccess_timer = world.time + FTPDELAY
|
||||
return 0
|
||||
#undef FTPDELAY
|
||||
@@ -1,67 +1,67 @@
|
||||
var/list/clients = list() //list of all clients
|
||||
var/list/admins = list() //list of all clients whom are admins
|
||||
var/list/directory = list() //list of all ckeys with associated client
|
||||
|
||||
//Since it didn't really belong in any other category, I'm putting this here
|
||||
//This is for procs to replace all the goddamn 'in world's that are chilling around the code
|
||||
|
||||
var/global/list/player_list = list() //List of all mobs **with clients attached**. Excludes /mob/new_player
|
||||
var/global/list/mob_list = list() //List of all mobs, including clientless
|
||||
var/global/list/living_mob_list = list() //List of all alive mobs, including clientless. Excludes /mob/new_player
|
||||
var/global/list/dead_mob_list = list() //List of all dead mobs, including clientless. Excludes /mob/new_player
|
||||
var/list/observers = new/list()
|
||||
var/global/list/areas = list()
|
||||
var/global/list/turfs = list()
|
||||
|
||||
var/global/list/chemical_reactions_list //list of all /datum/chemical_reaction datums. Used during chemical reactions
|
||||
var/global/list/chemical_reagents_list //list of all /datum/reagent datums indexed by reagent id. Used by chemistry stuff
|
||||
var/global/list/landmarks_list = list() //list of all landmarks created
|
||||
var/global/list/surgery_steps = list() //list of all surgery steps |BS12
|
||||
var/global/list/mechas_list = list() //list of all mechs. Used by hostile mobs target tracking.
|
||||
|
||||
// Posters
|
||||
var/global/list/datum/poster/poster_designs = typesof(/datum/poster) - /datum/poster - /datum/poster/goldstar
|
||||
|
||||
//Preferences stuff
|
||||
//Underwear
|
||||
var/global/list/underwear_m = list("White", "Grey", "Green", "Blue", "Black", "Mankini", "Love-Hearts", "Black2", "Grey2", "Stripey", "Kinky", "None") //Curse whoever made male/female underwear diffrent colours
|
||||
var/global/list/underwear_f = list("Red", "White", "Yellow", "Blue", "Black", "Thong", "Babydoll", "Baby-Blue", "Green", "Pink", "Kinky", "None")
|
||||
//Backpacks
|
||||
var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Alt")
|
||||
|
||||
// This is stupid as fuck.
|
||||
var/list/hit_appends = list("-OOF", "-ACK", "-UGH", "-HRNK", "-HURGH", "-GLORF")
|
||||
|
||||
//*-hud user lists
|
||||
var/global/list/table_recipes = list() //list of all table craft recipes
|
||||
var/global/list/med_hud_users = list() //list of all entities using a medical HUD.
|
||||
var/global/list/sec_hud_users = list() //list of all entities using a security HUD.
|
||||
|
||||
//////////////////////////
|
||||
/////Initial Building/////
|
||||
//////////////////////////
|
||||
|
||||
/proc/make_datum_references_lists()
|
||||
var/list/paths
|
||||
//Surgery Steps - Initialize all /datum/surgery_step into a list
|
||||
paths = typesof(/datum/surgery_step)-/datum/surgery_step
|
||||
for(var/T in paths)
|
||||
var/datum/surgery_step/S = new T
|
||||
surgery_steps += S
|
||||
sort_surgeries()
|
||||
|
||||
|
||||
/* // Uncomment to debug chemical reaction list.
|
||||
/client/verb/debug_chemical_list()
|
||||
|
||||
|
||||
for (var/reaction in chemical_reactions_list)
|
||||
. += "chemical_reactions_list\[\"[reaction]\"\] = \"[chemical_reactions_list[reaction]]\"\n"
|
||||
if(islist(chemical_reactions_list[reaction]))
|
||||
var/list/L = chemical_reactions_list[reaction]
|
||||
for(var/t in L)
|
||||
. += " has: [t]\n"
|
||||
var/list/clients = list() //list of all clients
|
||||
var/list/admins = list() //list of all clients whom are admins
|
||||
var/list/directory = list() //list of all ckeys with associated client
|
||||
|
||||
//Since it didn't really belong in any other category, I'm putting this here
|
||||
//This is for procs to replace all the goddamn 'in world's that are chilling around the code
|
||||
|
||||
var/global/list/player_list = list() //List of all mobs **with clients attached**. Excludes /mob/new_player
|
||||
var/global/list/mob_list = list() //List of all mobs, including clientless
|
||||
var/global/list/living_mob_list = list() //List of all alive mobs, including clientless. Excludes /mob/new_player
|
||||
var/global/list/dead_mob_list = list() //List of all dead mobs, including clientless. Excludes /mob/new_player
|
||||
var/list/observers = new/list()
|
||||
var/global/list/areas = list()
|
||||
var/global/list/turfs = list()
|
||||
|
||||
var/global/list/chemical_reactions_list //list of all /datum/chemical_reaction datums. Used during chemical reactions
|
||||
var/global/list/chemical_reagents_list //list of all /datum/reagent datums indexed by reagent id. Used by chemistry stuff
|
||||
var/global/list/landmarks_list = list() //list of all landmarks created
|
||||
var/global/list/surgery_steps = list() //list of all surgery steps |BS12
|
||||
var/global/list/mechas_list = list() //list of all mechs. Used by hostile mobs target tracking.
|
||||
|
||||
// Posters
|
||||
var/global/list/datum/poster/poster_designs = typesof(/datum/poster) - /datum/poster - /datum/poster/goldstar
|
||||
|
||||
//Preferences stuff
|
||||
//Underwear
|
||||
var/global/list/underwear_m = list("White", "Grey", "Green", "Blue", "Black", "Mankini", "Love-Hearts", "Black2", "Grey2", "Stripey", "Kinky", "None") //Curse whoever made male/female underwear diffrent colours
|
||||
var/global/list/underwear_f = list("Red", "White", "Yellow", "Blue", "Black", "Thong", "Babydoll", "Baby-Blue", "Green", "Pink", "Kinky", "None")
|
||||
//Backpacks
|
||||
var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Alt")
|
||||
|
||||
// This is stupid as fuck.
|
||||
var/list/hit_appends = list("-OOF", "-ACK", "-UGH", "-HRNK", "-HURGH", "-GLORF")
|
||||
|
||||
//*-hud user lists
|
||||
var/global/list/table_recipes = list() //list of all table craft recipes
|
||||
var/global/list/med_hud_users = list() //list of all entities using a medical HUD.
|
||||
var/global/list/sec_hud_users = list() //list of all entities using a security HUD.
|
||||
|
||||
//////////////////////////
|
||||
/////Initial Building/////
|
||||
//////////////////////////
|
||||
|
||||
/proc/make_datum_references_lists()
|
||||
var/list/paths
|
||||
//Surgery Steps - Initialize all /datum/surgery_step into a list
|
||||
paths = typesof(/datum/surgery_step)-/datum/surgery_step
|
||||
for(var/T in paths)
|
||||
var/datum/surgery_step/S = new T
|
||||
surgery_steps += S
|
||||
sort_surgeries()
|
||||
|
||||
|
||||
/* // Uncomment to debug chemical reaction list.
|
||||
/client/verb/debug_chemical_list()
|
||||
|
||||
|
||||
for (var/reaction in chemical_reactions_list)
|
||||
. += "chemical_reactions_list\[\"[reaction]\"\] = \"[chemical_reactions_list[reaction]]\"\n"
|
||||
if(islist(chemical_reactions_list[reaction]))
|
||||
var/list/L = chemical_reactions_list[reaction]
|
||||
for(var/t in L)
|
||||
. += " has: [t]\n"
|
||||
to_chat(world, .)
|
||||
*/
|
||||
|
||||
*/
|
||||
|
||||
var/global/list/escape_list = list()
|
||||
@@ -1,136 +1,136 @@
|
||||
proc
|
||||
getIconMask(atom/A)//By yours truly. Creates a dynamic mask for a mob/whatever. /N
|
||||
var/icon/alpha_mask = new(A.icon,A.icon_state)//So we want the default icon and icon state of A.
|
||||
for(var/I in A.overlays)//For every image in overlays. var/image/I will not work, don't try it.
|
||||
if(I:layer>A.layer) continue//If layer is greater than what we need, skip it.
|
||||
var/icon/image_overlay = new(I:icon,I:icon_state)//Blend only works with icon objects.
|
||||
//Also, icons cannot directly set icon_state. Slower than changing variables but whatever.
|
||||
alpha_mask.Blend(image_overlay,ICON_OR)//OR so they are lumped together in a nice overlay.
|
||||
return alpha_mask//And now return the mask.
|
||||
|
||||
/mob/proc/AddCamoOverlay(atom/A)//A is the atom which we are using as the overlay.
|
||||
var/icon/opacity_icon = new(A.icon, A.icon_state)//Don't really care for overlays/underlays.
|
||||
//Now we need to culculate overlays+underlays and add them together to form an image for a mask.
|
||||
//var/icon/alpha_mask = getFlatIcon(src)//Accurate but SLOW. Not designed for running each tick. Could have other uses I guess.
|
||||
var/icon/alpha_mask = getIconMask(src)//Which is why I created that proc. Also a little slow since it's blending a bunch of icons together but good enough.
|
||||
opacity_icon.AddAlphaMask(alpha_mask)//Likely the main source of lag for this proc. Probably not designed to run each tick.
|
||||
opacity_icon.ChangeOpacity(0.4)//Front end for MapColors so it's fast. 0.5 means half opacity and looks the best in my opinion.
|
||||
for(var/i=0,i<5,i++)//And now we add it as overlays. It's faster than creating an icon and then merging it.
|
||||
var/image/I = image("icon" = opacity_icon, "icon_state" = A.icon_state, "layer" = layer+0.8)//So it's above other stuff but below weapons and the like.
|
||||
switch(i)//Now to determine offset so the result is somewhat blurred.
|
||||
if(1) I.pixel_x--
|
||||
if(2) I.pixel_x++
|
||||
if(3) I.pixel_y--
|
||||
if(4) I.pixel_y++
|
||||
overlays += I//And finally add the overlay.
|
||||
|
||||
/proc/getHologramIcon(icon/A, safety=1)//If safety is on, a new icon is not created.
|
||||
var/icon/flat_icon = safety ? A : new(A)//Has to be a new icon to not constantly change the same icon.
|
||||
flat_icon.ColorTone(rgb(125,180,225))//Let's make it bluish.
|
||||
flat_icon.ChangeOpacity(0.5)//Make it half transparent.
|
||||
var/icon/alpha_mask = new('icons/effects/effects.dmi', "scanline")//Scanline effect.
|
||||
flat_icon.AddAlphaMask(alpha_mask)//Finally, let's mix in a distortion effect.
|
||||
return flat_icon
|
||||
|
||||
/proc/getStaticIcon(icon/A, safety=1)
|
||||
var/icon/flat_icon = safety ? A : new(A)
|
||||
flat_icon.Blend(rgb(255, 255, 255))
|
||||
flat_icon.BecomeAlphaMask()
|
||||
var/icon/static_icon = new/icon('icons/effects/effects.dmi', "static_base")
|
||||
static_icon.AddAlphaMask(flat_icon)
|
||||
return static_icon
|
||||
|
||||
/proc/getBlankIcon(icon/A, safety=1)
|
||||
var/icon/flat_icon = safety ? A : new(A)
|
||||
flat_icon.Blend(rgb(255, 255, 255))
|
||||
flat_icon.BecomeAlphaMask()
|
||||
var/icon/blank_icon = new/icon('icons/effects/effects.dmi', "blank_base")
|
||||
blank_icon.AddAlphaMask(flat_icon)
|
||||
return blank_icon
|
||||
|
||||
/proc/getLetterImage(atom/A, letter = "", uppercase = 0)
|
||||
if(!A)
|
||||
return
|
||||
|
||||
var/icon/atom_icon = new(A.icon, A.icon_state)
|
||||
|
||||
if(!letter)
|
||||
letter = copytext(A.name, 1, 2)
|
||||
if(uppercase == 1)
|
||||
letter = uppertext(letter)
|
||||
else if(uppercase == -1)
|
||||
letter = lowertext(letter)
|
||||
|
||||
var/image/text_image = new(loc = A)
|
||||
text_image.maptext = "<font size = 4><b>[letter]</b></font>"
|
||||
text_image.color = AverageColor(atom_icon)
|
||||
text_image.pixel_x = 6
|
||||
text_image.pixel_y = 5
|
||||
del(atom_icon)
|
||||
return text_image
|
||||
|
||||
//For photo camera.
|
||||
/proc/build_composite_icon(atom/A)
|
||||
var/icon/composite = icon(A.icon, A.icon_state, A.dir, 1)
|
||||
for(var/O in A.overlays)
|
||||
var/image/I = O
|
||||
var/icon/C = icon(I.icon, I.icon_state, I.dir, 1)
|
||||
C.Blend(I.color, ICON_MULTIPLY)
|
||||
composite.Blend(C, ICON_OVERLAY)
|
||||
return composite
|
||||
|
||||
proc/adjust_brightness(var/color, var/value)
|
||||
if (!color) return "#FFFFFF"
|
||||
if (!value) return color
|
||||
|
||||
var/list/RGB = ReadRGB(color)
|
||||
RGB[1] = Clamp(RGB[1]+value,0,255)
|
||||
RGB[2] = Clamp(RGB[2]+value,0,255)
|
||||
RGB[3] = Clamp(RGB[3]+value,0,255)
|
||||
return rgb(RGB[1],RGB[2],RGB[3])
|
||||
|
||||
/proc/ListColors(var/icon/I, var/ignoreGreyscale = 0)
|
||||
var/list/colors = list()
|
||||
for(var/x_pixel = 1 to I.Width())
|
||||
for(var/y_pixel = 1 to I.Height())
|
||||
var/this_color = I.GetPixel(x_pixel, y_pixel)
|
||||
if(this_color)
|
||||
if (ignoreGreyscale && ReadHSV(RGBtoHSV(this_color))[2] == 0) //If saturation is 0, must be greyscale
|
||||
continue
|
||||
colors.Add(this_color)
|
||||
return colors
|
||||
|
||||
/proc/AverageColor(var/icon/I, var/accurate = 0, var/ignoreGreyscale = 0)
|
||||
//Accurate: Use more accurate color averaging, usually has better results and prevents muddied or overly dark colors. Mad thanks to wwjnc.
|
||||
//ignoreGreyscale: Excempts greyscale colors from the color list, useful for filtering outlines or plate overlays.
|
||||
var/list/colors = ListColors(I, ignoreGreyscale)
|
||||
if(!colors.len)
|
||||
return null
|
||||
|
||||
var/list/colorsum = list(0, 0, 0) //Holds the sum of the RGB values to calculate the average
|
||||
var/list/RGB = list(0, 0, 0) //Temp list for each color
|
||||
var/total = colors.len
|
||||
|
||||
var/final_average
|
||||
if (accurate) //keeping it legible
|
||||
for(var/i = 1 to total)
|
||||
RGB = ReadRGB(colors[i])
|
||||
colorsum[1] += RGB[1]*RGB[1]
|
||||
colorsum[2] += RGB[2]*RGB[2]
|
||||
colorsum[3] += RGB[3]*RGB[3]
|
||||
final_average = rgb(sqrt(colorsum[1]/total), sqrt(colorsum[2]/total), sqrt(colorsum[3]/total))
|
||||
else
|
||||
for(var/i = 1 to total)
|
||||
RGB = ReadRGB(colors[i])
|
||||
colorsum[1] += RGB[1]
|
||||
colorsum[2] += RGB[2]
|
||||
colorsum[3] += RGB[3]
|
||||
final_average = rgb(colorsum[1]/total, colorsum[2]/total, colorsum[3]/total)
|
||||
return final_average
|
||||
|
||||
/proc/empty_Y_space(var/icon/I) //Returns the amount of lines containing only transparent pixels in an icon, starting from the bottom
|
||||
for(var/y_pixel = 1 to I.Height())
|
||||
for(var/x_pixel = 1 to I.Width())
|
||||
if (I.GetPixel(x_pixel, y_pixel))
|
||||
return y_pixel - 1
|
||||
return null
|
||||
proc
|
||||
getIconMask(atom/A)//By yours truly. Creates a dynamic mask for a mob/whatever. /N
|
||||
var/icon/alpha_mask = new(A.icon,A.icon_state)//So we want the default icon and icon state of A.
|
||||
for(var/I in A.overlays)//For every image in overlays. var/image/I will not work, don't try it.
|
||||
if(I:layer>A.layer) continue//If layer is greater than what we need, skip it.
|
||||
var/icon/image_overlay = new(I:icon,I:icon_state)//Blend only works with icon objects.
|
||||
//Also, icons cannot directly set icon_state. Slower than changing variables but whatever.
|
||||
alpha_mask.Blend(image_overlay,ICON_OR)//OR so they are lumped together in a nice overlay.
|
||||
return alpha_mask//And now return the mask.
|
||||
|
||||
/mob/proc/AddCamoOverlay(atom/A)//A is the atom which we are using as the overlay.
|
||||
var/icon/opacity_icon = new(A.icon, A.icon_state)//Don't really care for overlays/underlays.
|
||||
//Now we need to culculate overlays+underlays and add them together to form an image for a mask.
|
||||
//var/icon/alpha_mask = getFlatIcon(src)//Accurate but SLOW. Not designed for running each tick. Could have other uses I guess.
|
||||
var/icon/alpha_mask = getIconMask(src)//Which is why I created that proc. Also a little slow since it's blending a bunch of icons together but good enough.
|
||||
opacity_icon.AddAlphaMask(alpha_mask)//Likely the main source of lag for this proc. Probably not designed to run each tick.
|
||||
opacity_icon.ChangeOpacity(0.4)//Front end for MapColors so it's fast. 0.5 means half opacity and looks the best in my opinion.
|
||||
for(var/i=0,i<5,i++)//And now we add it as overlays. It's faster than creating an icon and then merging it.
|
||||
var/image/I = image("icon" = opacity_icon, "icon_state" = A.icon_state, "layer" = layer+0.8)//So it's above other stuff but below weapons and the like.
|
||||
switch(i)//Now to determine offset so the result is somewhat blurred.
|
||||
if(1) I.pixel_x--
|
||||
if(2) I.pixel_x++
|
||||
if(3) I.pixel_y--
|
||||
if(4) I.pixel_y++
|
||||
overlays += I//And finally add the overlay.
|
||||
|
||||
/proc/getHologramIcon(icon/A, safety=1)//If safety is on, a new icon is not created.
|
||||
var/icon/flat_icon = safety ? A : new(A)//Has to be a new icon to not constantly change the same icon.
|
||||
flat_icon.ColorTone(rgb(125,180,225))//Let's make it bluish.
|
||||
flat_icon.ChangeOpacity(0.5)//Make it half transparent.
|
||||
var/icon/alpha_mask = new('icons/effects/effects.dmi', "scanline")//Scanline effect.
|
||||
flat_icon.AddAlphaMask(alpha_mask)//Finally, let's mix in a distortion effect.
|
||||
return flat_icon
|
||||
|
||||
/proc/getStaticIcon(icon/A, safety=1)
|
||||
var/icon/flat_icon = safety ? A : new(A)
|
||||
flat_icon.Blend(rgb(255, 255, 255))
|
||||
flat_icon.BecomeAlphaMask()
|
||||
var/icon/static_icon = new/icon('icons/effects/effects.dmi', "static_base")
|
||||
static_icon.AddAlphaMask(flat_icon)
|
||||
return static_icon
|
||||
|
||||
/proc/getBlankIcon(icon/A, safety=1)
|
||||
var/icon/flat_icon = safety ? A : new(A)
|
||||
flat_icon.Blend(rgb(255, 255, 255))
|
||||
flat_icon.BecomeAlphaMask()
|
||||
var/icon/blank_icon = new/icon('icons/effects/effects.dmi', "blank_base")
|
||||
blank_icon.AddAlphaMask(flat_icon)
|
||||
return blank_icon
|
||||
|
||||
/proc/getLetterImage(atom/A, letter = "", uppercase = 0)
|
||||
if(!A)
|
||||
return
|
||||
|
||||
var/icon/atom_icon = new(A.icon, A.icon_state)
|
||||
|
||||
if(!letter)
|
||||
letter = copytext(A.name, 1, 2)
|
||||
if(uppercase == 1)
|
||||
letter = uppertext(letter)
|
||||
else if(uppercase == -1)
|
||||
letter = lowertext(letter)
|
||||
|
||||
var/image/text_image = new(loc = A)
|
||||
text_image.maptext = "<font size = 4><b>[letter]</b></font>"
|
||||
text_image.color = AverageColor(atom_icon)
|
||||
text_image.pixel_x = 6
|
||||
text_image.pixel_y = 5
|
||||
del(atom_icon)
|
||||
return text_image
|
||||
|
||||
//For photo camera.
|
||||
/proc/build_composite_icon(atom/A)
|
||||
var/icon/composite = icon(A.icon, A.icon_state, A.dir, 1)
|
||||
for(var/O in A.overlays)
|
||||
var/image/I = O
|
||||
var/icon/C = icon(I.icon, I.icon_state, I.dir, 1)
|
||||
C.Blend(I.color, ICON_MULTIPLY)
|
||||
composite.Blend(C, ICON_OVERLAY)
|
||||
return composite
|
||||
|
||||
proc/adjust_brightness(var/color, var/value)
|
||||
if (!color) return "#FFFFFF"
|
||||
if (!value) return color
|
||||
|
||||
var/list/RGB = ReadRGB(color)
|
||||
RGB[1] = Clamp(RGB[1]+value,0,255)
|
||||
RGB[2] = Clamp(RGB[2]+value,0,255)
|
||||
RGB[3] = Clamp(RGB[3]+value,0,255)
|
||||
return rgb(RGB[1],RGB[2],RGB[3])
|
||||
|
||||
/proc/ListColors(var/icon/I, var/ignoreGreyscale = 0)
|
||||
var/list/colors = list()
|
||||
for(var/x_pixel = 1 to I.Width())
|
||||
for(var/y_pixel = 1 to I.Height())
|
||||
var/this_color = I.GetPixel(x_pixel, y_pixel)
|
||||
if(this_color)
|
||||
if (ignoreGreyscale && ReadHSV(RGBtoHSV(this_color))[2] == 0) //If saturation is 0, must be greyscale
|
||||
continue
|
||||
colors.Add(this_color)
|
||||
return colors
|
||||
|
||||
/proc/AverageColor(var/icon/I, var/accurate = 0, var/ignoreGreyscale = 0)
|
||||
//Accurate: Use more accurate color averaging, usually has better results and prevents muddied or overly dark colors. Mad thanks to wwjnc.
|
||||
//ignoreGreyscale: Excempts greyscale colors from the color list, useful for filtering outlines or plate overlays.
|
||||
var/list/colors = ListColors(I, ignoreGreyscale)
|
||||
if(!colors.len)
|
||||
return null
|
||||
|
||||
var/list/colorsum = list(0, 0, 0) //Holds the sum of the RGB values to calculate the average
|
||||
var/list/RGB = list(0, 0, 0) //Temp list for each color
|
||||
var/total = colors.len
|
||||
|
||||
var/final_average
|
||||
if (accurate) //keeping it legible
|
||||
for(var/i = 1 to total)
|
||||
RGB = ReadRGB(colors[i])
|
||||
colorsum[1] += RGB[1]*RGB[1]
|
||||
colorsum[2] += RGB[2]*RGB[2]
|
||||
colorsum[3] += RGB[3]*RGB[3]
|
||||
final_average = rgb(sqrt(colorsum[1]/total), sqrt(colorsum[2]/total), sqrt(colorsum[3]/total))
|
||||
else
|
||||
for(var/i = 1 to total)
|
||||
RGB = ReadRGB(colors[i])
|
||||
colorsum[1] += RGB[1]
|
||||
colorsum[2] += RGB[2]
|
||||
colorsum[3] += RGB[3]
|
||||
final_average = rgb(colorsum[1]/total, colorsum[2]/total, colorsum[3]/total)
|
||||
return final_average
|
||||
|
||||
/proc/empty_Y_space(var/icon/I) //Returns the amount of lines containing only transparent pixels in an icon, starting from the bottom
|
||||
for(var/y_pixel = 1 to I.Height())
|
||||
for(var/x_pixel = 1 to I.Width())
|
||||
if (I.GetPixel(x_pixel, y_pixel))
|
||||
return y_pixel - 1
|
||||
return null
|
||||
|
||||
@@ -1,339 +1,339 @@
|
||||
/*
|
||||
* Holds procs to help with list operations
|
||||
* Contains groups:
|
||||
* Misc
|
||||
* Sorting
|
||||
*/
|
||||
|
||||
/*
|
||||
* Misc
|
||||
*/
|
||||
|
||||
//Returns a list in plain english as a string
|
||||
/proc/english_list(var/list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" )
|
||||
var/total = input.len
|
||||
if (!total)
|
||||
return "[nothing_text]"
|
||||
else if (total == 1)
|
||||
return "[input[1]]"
|
||||
else if (total == 2)
|
||||
return "[input[1]][and_text][input[2]]"
|
||||
else
|
||||
var/output = ""
|
||||
var/index = 1
|
||||
while (index < total)
|
||||
if (index == total - 1)
|
||||
comma_text = final_comma_text
|
||||
|
||||
output += "[input[index]][comma_text]"
|
||||
index++
|
||||
|
||||
return "[output][and_text][input[index]]"
|
||||
|
||||
//Returns list element or null. Should prevent "index out of bounds" error.
|
||||
/proc/listgetindex(list/L, index)
|
||||
if(istype(L))
|
||||
if(isnum(index))
|
||||
if(IsInRange(index,1,L.len))
|
||||
return L[index]
|
||||
else if(index in L)
|
||||
return L[index]
|
||||
return
|
||||
|
||||
/proc/islist(list/L)
|
||||
if(istype(L))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//Return either pick(list) or null if list is not of type /list or is empty
|
||||
/proc/safepick(list/L)
|
||||
if(istype(L) && L.len)
|
||||
return pick(L)
|
||||
|
||||
//Checks if the list is empty
|
||||
/proc/isemptylist(list/L)
|
||||
if(!L.len)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//Checks for specific types in a list
|
||||
/proc/is_type_in_list(var/atom/A, var/list/L)
|
||||
for(var/type in L)
|
||||
if(istype(A, type))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//Empties the list by setting the length to 0. Hopefully the elements get garbage collected
|
||||
/proc/clearlist(list/list)
|
||||
if(istype(list))
|
||||
list.len = 0
|
||||
return
|
||||
|
||||
//Removes any null entries from the list
|
||||
/proc/listclearnulls(list/L)
|
||||
if(istype(L))
|
||||
var/i=1
|
||||
for(var/thing in L)
|
||||
if(thing != null)
|
||||
++i
|
||||
continue
|
||||
L.Cut(i,i+1)
|
||||
|
||||
/*
|
||||
* Returns list containing all the entries from first list that are not present in second.
|
||||
* If skiprep = 1, repeated elements are treated as one.
|
||||
* If either of arguments is not a list, returns null
|
||||
*/
|
||||
/proc/difflist(var/list/first, var/list/second, var/skiprep=0)
|
||||
if(!islist(first) || !islist(second))
|
||||
return
|
||||
var/list/result = new
|
||||
if(skiprep)
|
||||
for(var/e in first)
|
||||
if(!(e in result) && !(e in second))
|
||||
result += e
|
||||
else
|
||||
result = first - second
|
||||
return result
|
||||
|
||||
/*
|
||||
* Returns list containing entries that are in either list but not both.
|
||||
* If skipref = 1, repeated elements are treated as one.
|
||||
* If either of arguments is not a list, returns null
|
||||
*/
|
||||
/proc/uniquemergelist(var/list/first, var/list/second, var/skiprep=0)
|
||||
if(!islist(first) || !islist(second))
|
||||
return
|
||||
var/list/result = new
|
||||
if(skiprep)
|
||||
result = difflist(first, second, skiprep)+difflist(second, first, skiprep)
|
||||
else
|
||||
result = first ^ second
|
||||
return result
|
||||
|
||||
//Pretends to pick an element based on its weight but really just seems to pick a random element.
|
||||
/proc/pickweight(list/L)
|
||||
var/total = 0
|
||||
var/item
|
||||
for (item in L)
|
||||
if (!L[item])
|
||||
L[item] = 1
|
||||
total += L[item]
|
||||
|
||||
total = rand(1, total)
|
||||
for (item in L)
|
||||
total -=L [item]
|
||||
if (total <= 0)
|
||||
return item
|
||||
|
||||
return null
|
||||
|
||||
//Pick a random element from the list and remove it from the list.
|
||||
/proc/pick_n_take(list/L)
|
||||
if(L.len)
|
||||
var/picked = rand(1,L.len)
|
||||
. = L[picked]
|
||||
L.Cut(picked,picked+1) //Cut is far more efficient that Remove()
|
||||
|
||||
//Returns the top(last) element from the list and removes it from the list (typical stack function)
|
||||
/proc/pop(list/L)
|
||||
if(L.len)
|
||||
. = L[L.len]
|
||||
L.len--
|
||||
|
||||
/proc/sorted_insert(list/L, thing, comparator)
|
||||
var/pos = L.len
|
||||
while(pos > 0 && call(comparator)(thing, L[pos]) > 0)
|
||||
pos--
|
||||
L.Insert(pos+1, thing)
|
||||
|
||||
// Returns the next item in a list
|
||||
/proc/next_list_item(var/item, var/list/L)
|
||||
var/i
|
||||
i = L.Find(item)
|
||||
if(i == L.len)
|
||||
i = 1
|
||||
else
|
||||
i++
|
||||
return L[i]
|
||||
|
||||
// Returns the previous item in a list
|
||||
/proc/previous_list_item(var/item, var/list/L)
|
||||
var/i
|
||||
i = L.Find(item)
|
||||
if(i == 1)
|
||||
i = L.len
|
||||
else
|
||||
i--
|
||||
if(i < L.len || i > L.len)
|
||||
warning("[__FILE__]L[__LINE__]: [i] is outside of bounds for list, ([L.len])")
|
||||
return
|
||||
return L[i]
|
||||
|
||||
/*
|
||||
* Sorting
|
||||
*/
|
||||
/*
|
||||
//Reverses the order of items in the list
|
||||
/proc/reverselist(var/list/input)
|
||||
var/list/output = list()
|
||||
for(var/i = input.len; i >= 1; i--)
|
||||
output += input[i]
|
||||
return output
|
||||
*/
|
||||
|
||||
//Randomize: Return the list in a random order
|
||||
/proc/shuffle(var/list/L)
|
||||
if(!L)
|
||||
return
|
||||
L = L.Copy()
|
||||
|
||||
for(var/i=1, i<=L.len, ++i)
|
||||
L.Swap(i,rand(1,L.len))
|
||||
|
||||
return L
|
||||
|
||||
//Return a list with no duplicate entries
|
||||
/proc/uniquelist(var/list/L)
|
||||
var/list/K = list()
|
||||
for(var/item in L)
|
||||
if(!(item in K))
|
||||
K += item
|
||||
return K
|
||||
|
||||
//for sorting clients or mobs by ckey
|
||||
/proc/sortKey(list/L, order=1)
|
||||
return sortTim(L, order >= 0 ? /proc/cmp_ckey_asc : /proc/cmp_ckey_dsc)
|
||||
|
||||
//Specifically for record datums in a list.
|
||||
/proc/sortRecord(list/L, field = "name", order = 1)
|
||||
cmp_field = field
|
||||
return sortTim(L, order >= 0 ? /proc/cmp_records_asc : /proc/cmp_records_dsc)
|
||||
|
||||
//any value in a list
|
||||
/proc/sortList(var/list/L, cmp=/proc/cmp_text_asc)
|
||||
return sortTim(L.Copy(), cmp)
|
||||
|
||||
//uses sortList() but uses the var's name specifically. This should probably be using mergeAtom() instead
|
||||
/proc/sortNames(var/list/L, order=1)
|
||||
return sortTim(L, order >= 0 ? /proc/cmp_name_asc : /proc/cmp_name_dsc)
|
||||
|
||||
|
||||
//Converts a bitfield to a list of numbers (or words if a wordlist is provided)
|
||||
/proc/bitfield2list(bitfield = 0, list/wordlist)
|
||||
var/list/r = list()
|
||||
if(istype(wordlist,/list))
|
||||
var/max = min(wordlist.len,16)
|
||||
var/bit = 1
|
||||
for(var/i=1, i<=max, i++)
|
||||
if(bitfield & bit)
|
||||
r += wordlist[i]
|
||||
bit = bit << 1
|
||||
else
|
||||
for(var/bit=1, bit<=65535, bit = bit << 1)
|
||||
if(bitfield & bit)
|
||||
r += bit
|
||||
|
||||
return r
|
||||
|
||||
// Returns the key based on the index
|
||||
/proc/get_key_by_index(var/list/L, var/index)
|
||||
var/i = 1
|
||||
for(var/key in L)
|
||||
if(index == i)
|
||||
return key
|
||||
i++
|
||||
return null
|
||||
|
||||
/proc/count_by_type(var/list/L, type)
|
||||
var/i = 0
|
||||
for(var/T in L)
|
||||
if(istype(T, type))
|
||||
i++
|
||||
return i
|
||||
|
||||
/proc/find_record(field, value, list/L)
|
||||
for(var/datum/data/record/R in L)
|
||||
if(R.fields[field] == value)
|
||||
return R
|
||||
|
||||
|
||||
//Move a single element from position fromIndex within a list, to position toIndex
|
||||
//All elements in the range [1,toIndex) before the move will be before the pivot afterwards
|
||||
//All elements in the range [toIndex, L.len+1) before the move will be after the pivot afterwards
|
||||
//In other words, it's as if the range [fromIndex,toIndex) have been rotated using a <<< operation common to other languages.
|
||||
//fromIndex and toIndex must be in the range [1,L.len+1]
|
||||
//This will preserve associations ~Carnie
|
||||
/proc/moveElement(list/L, fromIndex, toIndex)
|
||||
if(fromIndex == toIndex || fromIndex+1 == toIndex) //no need to move
|
||||
return
|
||||
if(fromIndex > toIndex)
|
||||
++fromIndex //since a null will be inserted before fromIndex, the index needs to be nudged right by one
|
||||
|
||||
L.Insert(toIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(fromIndex, fromIndex+1)
|
||||
|
||||
|
||||
//Move elements [fromIndex,fromIndex+len) to [toIndex-len, toIndex)
|
||||
//Same as moveElement but for ranges of elements
|
||||
//This will preserve associations ~Carnie
|
||||
/proc/moveRange(list/L, fromIndex, toIndex, len=1)
|
||||
var/distance = abs(toIndex - fromIndex)
|
||||
if(len >= distance) //there are more elements to be moved than the distance to be moved. Therefore the same result can be achieved (with fewer operations) by moving elements between where we are and where we are going. The result being, our range we are moving is shifted left or right by dist elements
|
||||
if(fromIndex <= toIndex)
|
||||
return //no need to move
|
||||
fromIndex += len //we want to shift left instead of right
|
||||
|
||||
for(var/i=0, i<distance, ++i)
|
||||
L.Insert(fromIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(toIndex, toIndex+1)
|
||||
else
|
||||
if(fromIndex > toIndex)
|
||||
fromIndex += len
|
||||
|
||||
for(var/i=0, i<len, ++i)
|
||||
L.Insert(toIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(fromIndex, fromIndex+1)
|
||||
|
||||
//Move elements from [fromIndex, fromIndex+len) to [toIndex, toIndex+len)
|
||||
//Move any elements being overwritten by the move to the now-empty elements, preserving order
|
||||
//Note: if the two ranges overlap, only the destination order will be preserved fully, since some elements will be within both ranges ~Carnie
|
||||
/proc/swapRange(list/L, fromIndex, toIndex, len=1)
|
||||
var/distance = abs(toIndex - fromIndex)
|
||||
if(len > distance) //there is an overlap, therefore swapping each element will require more swaps than inserting new elements
|
||||
if(fromIndex < toIndex)
|
||||
toIndex += len
|
||||
else
|
||||
fromIndex += len
|
||||
|
||||
for(var/i=0, i<distance, ++i)
|
||||
L.Insert(fromIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(toIndex, toIndex+1)
|
||||
else
|
||||
if(toIndex > fromIndex)
|
||||
var/a = toIndex
|
||||
toIndex = fromIndex
|
||||
fromIndex = a
|
||||
|
||||
for(var/i=0, i<len, ++i)
|
||||
L.Swap(fromIndex++, toIndex++)
|
||||
|
||||
//replaces reverseList ~Carnie
|
||||
/proc/reverseRange(list/L, start=1, end=0)
|
||||
if(L.len)
|
||||
start = start % L.len
|
||||
end = end % (L.len+1)
|
||||
if(start <= 0)
|
||||
start += L.len
|
||||
if(end <= 0)
|
||||
end += L.len + 1
|
||||
|
||||
--end
|
||||
while(start < end)
|
||||
L.Swap(start++,end--)
|
||||
|
||||
return L
|
||||
/*
|
||||
* Holds procs to help with list operations
|
||||
* Contains groups:
|
||||
* Misc
|
||||
* Sorting
|
||||
*/
|
||||
|
||||
/*
|
||||
* Misc
|
||||
*/
|
||||
|
||||
//Returns a list in plain english as a string
|
||||
/proc/english_list(var/list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" )
|
||||
var/total = input.len
|
||||
if (!total)
|
||||
return "[nothing_text]"
|
||||
else if (total == 1)
|
||||
return "[input[1]]"
|
||||
else if (total == 2)
|
||||
return "[input[1]][and_text][input[2]]"
|
||||
else
|
||||
var/output = ""
|
||||
var/index = 1
|
||||
while (index < total)
|
||||
if (index == total - 1)
|
||||
comma_text = final_comma_text
|
||||
|
||||
output += "[input[index]][comma_text]"
|
||||
index++
|
||||
|
||||
return "[output][and_text][input[index]]"
|
||||
|
||||
//Returns list element or null. Should prevent "index out of bounds" error.
|
||||
/proc/listgetindex(list/L, index)
|
||||
if(istype(L))
|
||||
if(isnum(index))
|
||||
if(IsInRange(index,1,L.len))
|
||||
return L[index]
|
||||
else if(index in L)
|
||||
return L[index]
|
||||
return
|
||||
|
||||
/proc/islist(list/L)
|
||||
if(istype(L))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//Return either pick(list) or null if list is not of type /list or is empty
|
||||
/proc/safepick(list/L)
|
||||
if(istype(L) && L.len)
|
||||
return pick(L)
|
||||
|
||||
//Checks if the list is empty
|
||||
/proc/isemptylist(list/L)
|
||||
if(!L.len)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//Checks for specific types in a list
|
||||
/proc/is_type_in_list(var/atom/A, var/list/L)
|
||||
for(var/type in L)
|
||||
if(istype(A, type))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//Empties the list by setting the length to 0. Hopefully the elements get garbage collected
|
||||
/proc/clearlist(list/list)
|
||||
if(istype(list))
|
||||
list.len = 0
|
||||
return
|
||||
|
||||
//Removes any null entries from the list
|
||||
/proc/listclearnulls(list/L)
|
||||
if(istype(L))
|
||||
var/i=1
|
||||
for(var/thing in L)
|
||||
if(thing != null)
|
||||
++i
|
||||
continue
|
||||
L.Cut(i,i+1)
|
||||
|
||||
/*
|
||||
* Returns list containing all the entries from first list that are not present in second.
|
||||
* If skiprep = 1, repeated elements are treated as one.
|
||||
* If either of arguments is not a list, returns null
|
||||
*/
|
||||
/proc/difflist(var/list/first, var/list/second, var/skiprep=0)
|
||||
if(!islist(first) || !islist(second))
|
||||
return
|
||||
var/list/result = new
|
||||
if(skiprep)
|
||||
for(var/e in first)
|
||||
if(!(e in result) && !(e in second))
|
||||
result += e
|
||||
else
|
||||
result = first - second
|
||||
return result
|
||||
|
||||
/*
|
||||
* Returns list containing entries that are in either list but not both.
|
||||
* If skipref = 1, repeated elements are treated as one.
|
||||
* If either of arguments is not a list, returns null
|
||||
*/
|
||||
/proc/uniquemergelist(var/list/first, var/list/second, var/skiprep=0)
|
||||
if(!islist(first) || !islist(second))
|
||||
return
|
||||
var/list/result = new
|
||||
if(skiprep)
|
||||
result = difflist(first, second, skiprep)+difflist(second, first, skiprep)
|
||||
else
|
||||
result = first ^ second
|
||||
return result
|
||||
|
||||
//Pretends to pick an element based on its weight but really just seems to pick a random element.
|
||||
/proc/pickweight(list/L)
|
||||
var/total = 0
|
||||
var/item
|
||||
for (item in L)
|
||||
if (!L[item])
|
||||
L[item] = 1
|
||||
total += L[item]
|
||||
|
||||
total = rand(1, total)
|
||||
for (item in L)
|
||||
total -=L [item]
|
||||
if (total <= 0)
|
||||
return item
|
||||
|
||||
return null
|
||||
|
||||
//Pick a random element from the list and remove it from the list.
|
||||
/proc/pick_n_take(list/L)
|
||||
if(L.len)
|
||||
var/picked = rand(1,L.len)
|
||||
. = L[picked]
|
||||
L.Cut(picked,picked+1) //Cut is far more efficient that Remove()
|
||||
|
||||
//Returns the top(last) element from the list and removes it from the list (typical stack function)
|
||||
/proc/pop(list/L)
|
||||
if(L.len)
|
||||
. = L[L.len]
|
||||
L.len--
|
||||
|
||||
/proc/sorted_insert(list/L, thing, comparator)
|
||||
var/pos = L.len
|
||||
while(pos > 0 && call(comparator)(thing, L[pos]) > 0)
|
||||
pos--
|
||||
L.Insert(pos+1, thing)
|
||||
|
||||
// Returns the next item in a list
|
||||
/proc/next_list_item(var/item, var/list/L)
|
||||
var/i
|
||||
i = L.Find(item)
|
||||
if(i == L.len)
|
||||
i = 1
|
||||
else
|
||||
i++
|
||||
return L[i]
|
||||
|
||||
// Returns the previous item in a list
|
||||
/proc/previous_list_item(var/item, var/list/L)
|
||||
var/i
|
||||
i = L.Find(item)
|
||||
if(i == 1)
|
||||
i = L.len
|
||||
else
|
||||
i--
|
||||
if(i < L.len || i > L.len)
|
||||
warning("[__FILE__]L[__LINE__]: [i] is outside of bounds for list, ([L.len])")
|
||||
return
|
||||
return L[i]
|
||||
|
||||
/*
|
||||
* Sorting
|
||||
*/
|
||||
/*
|
||||
//Reverses the order of items in the list
|
||||
/proc/reverselist(var/list/input)
|
||||
var/list/output = list()
|
||||
for(var/i = input.len; i >= 1; i--)
|
||||
output += input[i]
|
||||
return output
|
||||
*/
|
||||
|
||||
//Randomize: Return the list in a random order
|
||||
/proc/shuffle(var/list/L)
|
||||
if(!L)
|
||||
return
|
||||
L = L.Copy()
|
||||
|
||||
for(var/i=1, i<=L.len, ++i)
|
||||
L.Swap(i,rand(1,L.len))
|
||||
|
||||
return L
|
||||
|
||||
//Return a list with no duplicate entries
|
||||
/proc/uniquelist(var/list/L)
|
||||
var/list/K = list()
|
||||
for(var/item in L)
|
||||
if(!(item in K))
|
||||
K += item
|
||||
return K
|
||||
|
||||
//for sorting clients or mobs by ckey
|
||||
/proc/sortKey(list/L, order=1)
|
||||
return sortTim(L, order >= 0 ? /proc/cmp_ckey_asc : /proc/cmp_ckey_dsc)
|
||||
|
||||
//Specifically for record datums in a list.
|
||||
/proc/sortRecord(list/L, field = "name", order = 1)
|
||||
cmp_field = field
|
||||
return sortTim(L, order >= 0 ? /proc/cmp_records_asc : /proc/cmp_records_dsc)
|
||||
|
||||
//any value in a list
|
||||
/proc/sortList(var/list/L, cmp=/proc/cmp_text_asc)
|
||||
return sortTim(L.Copy(), cmp)
|
||||
|
||||
//uses sortList() but uses the var's name specifically. This should probably be using mergeAtom() instead
|
||||
/proc/sortNames(var/list/L, order=1)
|
||||
return sortTim(L, order >= 0 ? /proc/cmp_name_asc : /proc/cmp_name_dsc)
|
||||
|
||||
|
||||
//Converts a bitfield to a list of numbers (or words if a wordlist is provided)
|
||||
/proc/bitfield2list(bitfield = 0, list/wordlist)
|
||||
var/list/r = list()
|
||||
if(istype(wordlist,/list))
|
||||
var/max = min(wordlist.len,16)
|
||||
var/bit = 1
|
||||
for(var/i=1, i<=max, i++)
|
||||
if(bitfield & bit)
|
||||
r += wordlist[i]
|
||||
bit = bit << 1
|
||||
else
|
||||
for(var/bit=1, bit<=65535, bit = bit << 1)
|
||||
if(bitfield & bit)
|
||||
r += bit
|
||||
|
||||
return r
|
||||
|
||||
// Returns the key based on the index
|
||||
/proc/get_key_by_index(var/list/L, var/index)
|
||||
var/i = 1
|
||||
for(var/key in L)
|
||||
if(index == i)
|
||||
return key
|
||||
i++
|
||||
return null
|
||||
|
||||
/proc/count_by_type(var/list/L, type)
|
||||
var/i = 0
|
||||
for(var/T in L)
|
||||
if(istype(T, type))
|
||||
i++
|
||||
return i
|
||||
|
||||
/proc/find_record(field, value, list/L)
|
||||
for(var/datum/data/record/R in L)
|
||||
if(R.fields[field] == value)
|
||||
return R
|
||||
|
||||
|
||||
//Move a single element from position fromIndex within a list, to position toIndex
|
||||
//All elements in the range [1,toIndex) before the move will be before the pivot afterwards
|
||||
//All elements in the range [toIndex, L.len+1) before the move will be after the pivot afterwards
|
||||
//In other words, it's as if the range [fromIndex,toIndex) have been rotated using a <<< operation common to other languages.
|
||||
//fromIndex and toIndex must be in the range [1,L.len+1]
|
||||
//This will preserve associations ~Carnie
|
||||
/proc/moveElement(list/L, fromIndex, toIndex)
|
||||
if(fromIndex == toIndex || fromIndex+1 == toIndex) //no need to move
|
||||
return
|
||||
if(fromIndex > toIndex)
|
||||
++fromIndex //since a null will be inserted before fromIndex, the index needs to be nudged right by one
|
||||
|
||||
L.Insert(toIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(fromIndex, fromIndex+1)
|
||||
|
||||
|
||||
//Move elements [fromIndex,fromIndex+len) to [toIndex-len, toIndex)
|
||||
//Same as moveElement but for ranges of elements
|
||||
//This will preserve associations ~Carnie
|
||||
/proc/moveRange(list/L, fromIndex, toIndex, len=1)
|
||||
var/distance = abs(toIndex - fromIndex)
|
||||
if(len >= distance) //there are more elements to be moved than the distance to be moved. Therefore the same result can be achieved (with fewer operations) by moving elements between where we are and where we are going. The result being, our range we are moving is shifted left or right by dist elements
|
||||
if(fromIndex <= toIndex)
|
||||
return //no need to move
|
||||
fromIndex += len //we want to shift left instead of right
|
||||
|
||||
for(var/i=0, i<distance, ++i)
|
||||
L.Insert(fromIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(toIndex, toIndex+1)
|
||||
else
|
||||
if(fromIndex > toIndex)
|
||||
fromIndex += len
|
||||
|
||||
for(var/i=0, i<len, ++i)
|
||||
L.Insert(toIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(fromIndex, fromIndex+1)
|
||||
|
||||
//Move elements from [fromIndex, fromIndex+len) to [toIndex, toIndex+len)
|
||||
//Move any elements being overwritten by the move to the now-empty elements, preserving order
|
||||
//Note: if the two ranges overlap, only the destination order will be preserved fully, since some elements will be within both ranges ~Carnie
|
||||
/proc/swapRange(list/L, fromIndex, toIndex, len=1)
|
||||
var/distance = abs(toIndex - fromIndex)
|
||||
if(len > distance) //there is an overlap, therefore swapping each element will require more swaps than inserting new elements
|
||||
if(fromIndex < toIndex)
|
||||
toIndex += len
|
||||
else
|
||||
fromIndex += len
|
||||
|
||||
for(var/i=0, i<distance, ++i)
|
||||
L.Insert(fromIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(toIndex, toIndex+1)
|
||||
else
|
||||
if(toIndex > fromIndex)
|
||||
var/a = toIndex
|
||||
toIndex = fromIndex
|
||||
fromIndex = a
|
||||
|
||||
for(var/i=0, i<len, ++i)
|
||||
L.Swap(fromIndex++, toIndex++)
|
||||
|
||||
//replaces reverseList ~Carnie
|
||||
/proc/reverseRange(list/L, start=1, end=0)
|
||||
if(L.len)
|
||||
start = start % L.len
|
||||
end = end % (L.len+1)
|
||||
if(start <= 0)
|
||||
start += L.len
|
||||
if(end <= 0)
|
||||
end += L.len + 1
|
||||
|
||||
--end
|
||||
while(start < end)
|
||||
L.Swap(start++,end--)
|
||||
|
||||
return L
|
||||
|
||||
@@ -1,137 +1,137 @@
|
||||
//print an error message to world.log
|
||||
/proc/error(msg)
|
||||
world.log << "## ERROR: [msg]"
|
||||
|
||||
/*
|
||||
* print a warning message to world.log
|
||||
*/
|
||||
/* see setup.dm
|
||||
//print an error message to world.log
|
||||
/proc/error(msg)
|
||||
world.log << "## ERROR: [msg]"
|
||||
|
||||
/*
|
||||
* print a warning message to world.log
|
||||
*/
|
||||
/* see setup.dm
|
||||
#define WARNING(MSG) to_chat(world, "##WARNING: [MSG] in [__FILE__] at line [__LINE__] src: [src] usr: [usr].")
|
||||
#define warning(msg) world.log << "## WARNING: [msg]"
|
||||
#define testing(msg) world.log << "## TESTING: [msg]"
|
||||
#define log_game(text) diary << html_decode("\[[time_stamp()]]GAME: [text]")
|
||||
|
||||
#define log_vote(text) diary << html_decode("\[[time_stamp()]]VOTE: [text]")
|
||||
|
||||
#define log_access(text) diary << html_decode("\[[time_stamp()]]ACCESS: [text]")
|
||||
|
||||
#define log_say(text) diary << html_decode("\[[time_stamp()]]SAY: [text]")
|
||||
|
||||
#define log_ooc(text) diary << html_decode("\[[time_stamp()]]OOC: [text]")
|
||||
|
||||
#define log_whisper(text) diary << html_decode("\[[time_stamp()]]WHISPER: [text]")
|
||||
|
||||
#define log_cultspeak(text) diary << html_decode("\[[time_stamp()]]CULT: [text]")
|
||||
|
||||
#define log_narspeak(text) diary << html_decode("\[[time_stamp()]]NARSIE: [text]")
|
||||
|
||||
#define log_emote(text) diary << html_decode("\[[time_stamp()]]EMOTE: [text]")
|
||||
|
||||
#define log_attack(text) diaryofmeanpeople << html_decode("\[[time_stamp()]]ATTACK: [text]")
|
||||
|
||||
#define log_adminsay(text) diary << html_decode("\[[time_stamp()]]ADMINSAY: [text]")
|
||||
|
||||
#define log_adminwarn(text) diary << html_decode("\[[time_stamp()]]ADMINWARN: [text]")
|
||||
#define log_pda(text) diary << html_decode("\[[time_stamp()]]PDA: [text]")
|
||||
*/
|
||||
|
||||
/proc/log_admin(raw_text)
|
||||
var/text_to_log = "\[[time_stamp()]]ADMIN: [raw_text]"
|
||||
|
||||
admin_log.Add(text_to_log)
|
||||
|
||||
if(config.log_admin)
|
||||
diary << html_decode(text_to_log)
|
||||
|
||||
if(config.log_admin_only)
|
||||
admin_diary << html_decode(text_to_log)
|
||||
|
||||
/proc/log_debug(text)
|
||||
if (config.log_debug)
|
||||
diary << html_decode("\[[time_stamp()]]DEBUG: [text]")
|
||||
|
||||
for(var/client/C in admins)
|
||||
if(C.prefs.toggles & CHAT_DEBUGLOGS)
|
||||
#define warning(msg) world.log << "## WARNING: [msg]"
|
||||
#define testing(msg) world.log << "## TESTING: [msg]"
|
||||
#define log_game(text) diary << html_decode("\[[time_stamp()]]GAME: [text]")
|
||||
|
||||
#define log_vote(text) diary << html_decode("\[[time_stamp()]]VOTE: [text]")
|
||||
|
||||
#define log_access(text) diary << html_decode("\[[time_stamp()]]ACCESS: [text]")
|
||||
|
||||
#define log_say(text) diary << html_decode("\[[time_stamp()]]SAY: [text]")
|
||||
|
||||
#define log_ooc(text) diary << html_decode("\[[time_stamp()]]OOC: [text]")
|
||||
|
||||
#define log_whisper(text) diary << html_decode("\[[time_stamp()]]WHISPER: [text]")
|
||||
|
||||
#define log_cultspeak(text) diary << html_decode("\[[time_stamp()]]CULT: [text]")
|
||||
|
||||
#define log_narspeak(text) diary << html_decode("\[[time_stamp()]]NARSIE: [text]")
|
||||
|
||||
#define log_emote(text) diary << html_decode("\[[time_stamp()]]EMOTE: [text]")
|
||||
|
||||
#define log_attack(text) diaryofmeanpeople << html_decode("\[[time_stamp()]]ATTACK: [text]")
|
||||
|
||||
#define log_adminsay(text) diary << html_decode("\[[time_stamp()]]ADMINSAY: [text]")
|
||||
|
||||
#define log_adminwarn(text) diary << html_decode("\[[time_stamp()]]ADMINWARN: [text]")
|
||||
#define log_pda(text) diary << html_decode("\[[time_stamp()]]PDA: [text]")
|
||||
*/
|
||||
|
||||
/proc/log_admin(raw_text)
|
||||
var/text_to_log = "\[[time_stamp()]]ADMIN: [raw_text]"
|
||||
|
||||
admin_log.Add(text_to_log)
|
||||
|
||||
if(config.log_admin)
|
||||
diary << html_decode(text_to_log)
|
||||
|
||||
if(config.log_admin_only)
|
||||
admin_diary << html_decode(text_to_log)
|
||||
|
||||
/proc/log_debug(text)
|
||||
if (config.log_debug)
|
||||
diary << html_decode("\[[time_stamp()]]DEBUG: [text]")
|
||||
|
||||
for(var/client/C in admins)
|
||||
if(C.prefs.toggles & CHAT_DEBUGLOGS)
|
||||
to_chat(C, "DEBUG: [text]")
|
||||
|
||||
|
||||
|
||||
|
||||
/proc/log_adminghost(text)
|
||||
if (config.log_adminghost)
|
||||
diary << html_decode("\[[time_stamp()]]ADMINGHOST: [text]")
|
||||
message_admins("\[ADMINGHOST\] [text]")
|
||||
|
||||
/proc/log_ghost(text)
|
||||
if (config.log_adminghost)
|
||||
diary << html_decode("\[[time_stamp()]]GHOST: [text]")
|
||||
message_admins("\[GHOST\] [text]")
|
||||
|
||||
|
||||
/**
|
||||
* Helper proc to log attacks or similar events between two mobs.
|
||||
*/
|
||||
/proc/add_attacklogs(var/mob/user, var/mob/target, var/what_done, var/object = null, var/addition = null, var/admin_warn = TRUE)
|
||||
var/user_txt = (user ? "[user][user.ckey ? " ([user.ckey])" : ""]" : "\<NULL USER\>")
|
||||
var/target_txt = (target ? "[target][target.ckey ? " ([target.ckey])" : ""]" : "\<NULL TARGET\>")
|
||||
var/object_txt = (object ? " with \the [object]" : "")
|
||||
var/intent_txt = (user ? " (INTENT: [uppertext(user.a_intent)])" : "")
|
||||
var/addition_txt = (addition ? " ([addition])" : "")
|
||||
|
||||
if (ismob(user))
|
||||
user.attack_log += text("\[[time_stamp()]\] <span class='danger'>Has [what_done] [target_txt][object_txt].[intent_txt][addition_txt]</span>")
|
||||
|
||||
if (ismob(target))
|
||||
target.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been [what_done] by [user_txt][object_txt].[intent_txt][addition_txt]</font>")
|
||||
target.LAssailant = (iscarbon(user) ? user : null)
|
||||
|
||||
var/log_msg = "<span class='danger'>[user_txt] [what_done] [target_txt][object_txt][intent_txt].</span>[addition_txt] ([formatJumpTo(user, "JMP")])"
|
||||
log_attack(log_msg)
|
||||
if (admin_warn)
|
||||
msg_admin_attack(log_msg)
|
||||
|
||||
/**
|
||||
* Helper proc to log detailed game events easier.
|
||||
*
|
||||
* @param user Subject of the action
|
||||
* @param what_done Description of the action that user has done (e.g. "toggled the PA to 3")
|
||||
* @param admin Whether to message the admins about this
|
||||
* @param tp_link Whether to add a jump link to the position of the action (i.e. user.loc)
|
||||
* @param tp_link_short Whether to make the jump link display 'JMP' instead of the area and coordinates
|
||||
* @param span_class What CSS class to use for the message.
|
||||
*/
|
||||
/proc/add_gamelogs(var/mob/user, var/what_done, var/admin = 1, var/tp_link = FALSE, var/tp_link_short = TRUE, var/span_class = "notice")
|
||||
var/user_text = (ismob(user) ? "[user] ([user.ckey])" : "<NULL USER>")
|
||||
var/link = (tp_link ? " ([formatJumpTo(user, (tp_link_short ? "JMP" : ""))])" : "")
|
||||
|
||||
var/msg = "<span class='[span_class]'>[user_text] has [what_done].</span>[link]"
|
||||
log_game(msg)
|
||||
if (admin)
|
||||
message_admins(msg)
|
||||
|
||||
/**
|
||||
* Helper function to log reagent transfers, usually 'bad' ones.
|
||||
*
|
||||
* @param user The user that performed the transfer
|
||||
* @param source The item from which the reagents are transferred.
|
||||
* @param target The destination of the transfer
|
||||
* @param amount The amount of units transferred
|
||||
* @param reagent_names List of reagent names to log
|
||||
*/
|
||||
/proc/log_reagents(var/mob/user, var/source, var/target, var/amount, var/list/reagent_names)
|
||||
if (amount == 0)
|
||||
return
|
||||
|
||||
if (reagent_names && reagent_names.len > 0)
|
||||
var/reagent_text = "<span class='danger'>[english_list(reagent_names)]</span>"
|
||||
add_gamelogs(user, "added [amount]u (inc. [reagent_text]) to \a [target] with \the [source]", admin = TRUE, tp_link = TRUE)
|
||||
else
|
||||
add_gamelogs(user, "added [amount]u to \a [target] with \the [source]", admin = TRUE, tp_link = FALSE)
|
||||
|
||||
|
||||
/**
|
||||
* Standardized method for tracking startup times.
|
||||
*/
|
||||
/proc/log_startup_progress(var/message)
|
||||
|
||||
|
||||
|
||||
|
||||
/proc/log_adminghost(text)
|
||||
if (config.log_adminghost)
|
||||
diary << html_decode("\[[time_stamp()]]ADMINGHOST: [text]")
|
||||
message_admins("\[ADMINGHOST\] [text]")
|
||||
|
||||
/proc/log_ghost(text)
|
||||
if (config.log_adminghost)
|
||||
diary << html_decode("\[[time_stamp()]]GHOST: [text]")
|
||||
message_admins("\[GHOST\] [text]")
|
||||
|
||||
|
||||
/**
|
||||
* Helper proc to log attacks or similar events between two mobs.
|
||||
*/
|
||||
/proc/add_attacklogs(var/mob/user, var/mob/target, var/what_done, var/object = null, var/addition = null, var/admin_warn = TRUE)
|
||||
var/user_txt = (user ? "[user][user.ckey ? " ([user.ckey])" : ""]" : "\<NULL USER\>")
|
||||
var/target_txt = (target ? "[target][target.ckey ? " ([target.ckey])" : ""]" : "\<NULL TARGET\>")
|
||||
var/object_txt = (object ? " with \the [object]" : "")
|
||||
var/intent_txt = (user ? " (INTENT: [uppertext(user.a_intent)])" : "")
|
||||
var/addition_txt = (addition ? " ([addition])" : "")
|
||||
|
||||
if (ismob(user))
|
||||
user.attack_log += text("\[[time_stamp()]\] <span class='danger'>Has [what_done] [target_txt][object_txt].[intent_txt][addition_txt]</span>")
|
||||
|
||||
if (ismob(target))
|
||||
target.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been [what_done] by [user_txt][object_txt].[intent_txt][addition_txt]</font>")
|
||||
target.LAssailant = (iscarbon(user) ? user : null)
|
||||
|
||||
var/log_msg = "<span class='danger'>[user_txt] [what_done] [target_txt][object_txt][intent_txt].</span>[addition_txt] ([formatJumpTo(user, "JMP")])"
|
||||
log_attack(log_msg)
|
||||
if (admin_warn)
|
||||
msg_admin_attack(log_msg)
|
||||
|
||||
/**
|
||||
* Helper proc to log detailed game events easier.
|
||||
*
|
||||
* @param user Subject of the action
|
||||
* @param what_done Description of the action that user has done (e.g. "toggled the PA to 3")
|
||||
* @param admin Whether to message the admins about this
|
||||
* @param tp_link Whether to add a jump link to the position of the action (i.e. user.loc)
|
||||
* @param tp_link_short Whether to make the jump link display 'JMP' instead of the area and coordinates
|
||||
* @param span_class What CSS class to use for the message.
|
||||
*/
|
||||
/proc/add_gamelogs(var/mob/user, var/what_done, var/admin = 1, var/tp_link = FALSE, var/tp_link_short = TRUE, var/span_class = "notice")
|
||||
var/user_text = (ismob(user) ? "[user] ([user.ckey])" : "<NULL USER>")
|
||||
var/link = (tp_link ? " ([formatJumpTo(user, (tp_link_short ? "JMP" : ""))])" : "")
|
||||
|
||||
var/msg = "<span class='[span_class]'>[user_text] has [what_done].</span>[link]"
|
||||
log_game(msg)
|
||||
if (admin)
|
||||
message_admins(msg)
|
||||
|
||||
/**
|
||||
* Helper function to log reagent transfers, usually 'bad' ones.
|
||||
*
|
||||
* @param user The user that performed the transfer
|
||||
* @param source The item from which the reagents are transferred.
|
||||
* @param target The destination of the transfer
|
||||
* @param amount The amount of units transferred
|
||||
* @param reagent_names List of reagent names to log
|
||||
*/
|
||||
/proc/log_reagents(var/mob/user, var/source, var/target, var/amount, var/list/reagent_names)
|
||||
if (amount == 0)
|
||||
return
|
||||
|
||||
if (reagent_names && reagent_names.len > 0)
|
||||
var/reagent_text = "<span class='danger'>[english_list(reagent_names)]</span>"
|
||||
add_gamelogs(user, "added [amount]u (inc. [reagent_text]) to \a [target] with \the [source]", admin = TRUE, tp_link = TRUE)
|
||||
else
|
||||
add_gamelogs(user, "added [amount]u to \a [target] with \the [source]", admin = TRUE, tp_link = FALSE)
|
||||
|
||||
|
||||
/**
|
||||
* Standardized method for tracking startup times.
|
||||
*/
|
||||
/proc/log_startup_progress(var/message)
|
||||
to_chat(world, "<span class='danger'>[message]</span>")
|
||||
world.log << message
|
||||
|
||||
@@ -1,240 +1,240 @@
|
||||
/**
|
||||
* Credits to Nickr5 for the useful procs I've taken from his library resource.
|
||||
*/
|
||||
|
||||
var/const/E = 2.71828183
|
||||
var/const/Sqrt2 = 1.41421356
|
||||
|
||||
/* //All point fingers and laugh at this joke of a list, I even heard using sqrt() is faster than this list lookup, honk.
|
||||
// List of square roots for the numbers 1-100.
|
||||
var/list/sqrtTable = list(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10)
|
||||
*/
|
||||
|
||||
/proc/Atan2(x, y)
|
||||
if (!x && !y)
|
||||
return 0
|
||||
|
||||
var/invcos = arccos(x / sqrt(x * x + y * y))
|
||||
return y >= 0 ? invcos : -invcos
|
||||
|
||||
proc/arctan(x)
|
||||
var/y=arcsin(x/sqrt(1+x*x))
|
||||
return y
|
||||
|
||||
/proc/Ceiling(x, y = 1)
|
||||
. = -round(-x / y) * y
|
||||
|
||||
//Moved to macros.dm to reduce pure calling overhead, this was being called shitloads, like, most calls of all procs.
|
||||
/*
|
||||
/proc/Clamp(const/val, const/min, const/max)
|
||||
if (val <= min)
|
||||
return min
|
||||
|
||||
if (val >= max)
|
||||
return max
|
||||
|
||||
return val
|
||||
*/
|
||||
|
||||
// cotangent
|
||||
/proc/Cot(x)
|
||||
return 1 / Tan(x)
|
||||
|
||||
// cosecant
|
||||
/proc/Csc(x)
|
||||
return 1 / sin(x)
|
||||
|
||||
/proc/Default(a, b)
|
||||
return a ? a : b
|
||||
|
||||
/proc/Floor(x = 0, y = 0)
|
||||
if(x == 0)
|
||||
return 0
|
||||
if(y == 0)
|
||||
return round(x)
|
||||
|
||||
if(x < y)
|
||||
return 0
|
||||
|
||||
var/diff = round(x, y) //finds x to the nearest value of y
|
||||
if(diff > x)
|
||||
return x - (y - (diff - x)) //diff minus x is the inverse of what we want to remove, so we subtract from y - the base unit - and subtract the result
|
||||
else
|
||||
return diff //this is good enough
|
||||
|
||||
// Greatest Common Divisor - Euclid's algorithm
|
||||
/proc/Gcd(a, b)
|
||||
return b ? Gcd(b, a % b) : a
|
||||
|
||||
/proc/Inverse(x)
|
||||
return 1 / x
|
||||
|
||||
/proc/IsAboutEqual(a, b, deviation = 0.1)
|
||||
return abs(a - b) <= deviation
|
||||
|
||||
/proc/IsEven(x)
|
||||
return x % 2 == 0
|
||||
|
||||
// Returns true if val is from min to max, inclusive.
|
||||
/proc/IsInRange(val, min, max)
|
||||
return min <= val && val <= max
|
||||
|
||||
/proc/IsInteger(x)
|
||||
return Floor(x) == x
|
||||
|
||||
/proc/IsOdd(x)
|
||||
return !IsEven(x)
|
||||
|
||||
/proc/IsMultiple(x, y)
|
||||
return x % y == 0
|
||||
|
||||
// Least Common Multiple
|
||||
/proc/Lcm(a, b)
|
||||
return abs(a) / Gcd(a, b) * abs(b)
|
||||
|
||||
/**
|
||||
* Generic lerp function.
|
||||
*/
|
||||
/proc/lerp(x, x0, x1, y0 = 0, y1 = 1)
|
||||
return y0 + (y1 - y0)*(x - x0)/(x1 - x0)
|
||||
|
||||
/**
|
||||
* Lerps x to a value between [a, b]. x must be in the range [0, 1].
|
||||
* My undying gratitude goes out to wwjnc.
|
||||
*
|
||||
* Basically this returns the number corresponding to a certain
|
||||
* percentage in a range. 0% would be a, 100% would be b, 50% would
|
||||
* be halfways between a and b, and so on.
|
||||
*
|
||||
* Other methods of lerping might not yield the exact value of a or b
|
||||
* when x = 0 or 1. This one guarantees that.
|
||||
*
|
||||
* Examples:
|
||||
* - mix(0.0, 30, 60) = 30
|
||||
* - mix(1.0, 30, 60) = 60
|
||||
* - mix(0.5, 30, 60) = 45
|
||||
* - mix(0.75, 30, 60) = 52.5
|
||||
*/
|
||||
/proc/mix(a, b, x)
|
||||
return a*(1 - x) + b*x
|
||||
|
||||
/**
|
||||
* Lerps x to a value between [0, 1]. x must be in the range [a, b].
|
||||
*
|
||||
* This is the counterpart to the mix() function. It returns the actual
|
||||
* percentage x is at inside the [a, b] range.
|
||||
*
|
||||
* Note that this is theoretically equivalent to calling lerp(x, a, b)
|
||||
* (y0 and y1 default to 0 and 1) but this one is slightly faster
|
||||
* because Byond is too dumb to optimize procs with default values. It
|
||||
* shouldn't matter which one you use (since there are no FP issues)
|
||||
* but this one is more explicit as to what you're doing.
|
||||
*
|
||||
* @todo Find a better name for this. I can't into english.
|
||||
* http://i.imgur.com/8Pu0x7M.png
|
||||
*/
|
||||
/proc/unmix(x, a, b, min = 0, max = 1)
|
||||
if(a==b) return 1
|
||||
return Clamp( (b - x)/(b - a), min, max )
|
||||
|
||||
/proc/Mean(...)
|
||||
var/values = 0
|
||||
var/sum = 0
|
||||
for(var/val in args)
|
||||
values++
|
||||
sum += val
|
||||
return sum / values
|
||||
|
||||
|
||||
/*
|
||||
* Returns the nth root of x.
|
||||
*/
|
||||
/proc/Root(const/n, const/x)
|
||||
return x ** (1 / n)
|
||||
|
||||
/*
|
||||
* Secant.
|
||||
*/
|
||||
/proc/Sec(const/x)
|
||||
return 1 / cos(x)
|
||||
|
||||
// The quadratic formula. Returns a list with the solutions, or an empty list
|
||||
// if they are imaginary.
|
||||
/proc/SolveQuadratic(a, b, c)
|
||||
ASSERT(a)
|
||||
. = list()
|
||||
var/d = b*b - 4 * a * c
|
||||
var/bottom = 2 * a
|
||||
if(d < 0) return
|
||||
var/root = sqrt(d)
|
||||
. += (-b + root) / bottom
|
||||
if(!d) return
|
||||
. += (-b - root) / bottom
|
||||
|
||||
/*
|
||||
* Tangent.
|
||||
*/
|
||||
/proc/Tan(const/x)
|
||||
return sin(x) / cos(x)
|
||||
|
||||
/proc/ToDegrees(const/radians)
|
||||
// 180 / Pi
|
||||
return radians * 57.2957795
|
||||
|
||||
/proc/ToRadians(const/degrees)
|
||||
// Pi / 180
|
||||
return degrees * 0.0174532925
|
||||
|
||||
// min is inclusive, max is exclusive
|
||||
/proc/Wrap(val, min, max)
|
||||
var/d = max - min
|
||||
var/t = Floor((val - min) / d)
|
||||
return val - (t * d)
|
||||
|
||||
/*
|
||||
* A very crude linear approximatiaon of pythagoras theorem.
|
||||
*/
|
||||
/proc/cheap_pythag(const/Ax, const/Ay)
|
||||
var/dx = abs(Ax)
|
||||
var/dy = abs(Ay)
|
||||
|
||||
if (dx >= dy)
|
||||
return dx + (0.5 * dy) // The longest side add half the shortest side approximates the hypotenuse.
|
||||
else
|
||||
return dy + (0.5 * dx)
|
||||
|
||||
/*
|
||||
* Magic constants obtained by using linear regression on right-angled triangles of sides 0<x<1, 0<y<1
|
||||
* They should approximate pythagoras theorem well enough for our needs.
|
||||
*/
|
||||
#define k1 0.934
|
||||
#define k2 0.427
|
||||
/proc/cheap_hypotenuse(const/Ax, const/Ay, const/Bx, const/By)
|
||||
var/dx = abs(Ax - Bx) // Sides of right-angled triangle.
|
||||
var/dy = abs(Ay - By)
|
||||
|
||||
if (dx >= dy)
|
||||
return (k1*dx) + (k2*dy) // No sqrt or powers :).
|
||||
else
|
||||
return (k2*dx) + (k1*dy)
|
||||
#undef k1
|
||||
#undef k2
|
||||
|
||||
//Checks if something's a power of 2, to check bitflags.
|
||||
//Thanks to wwjnc for this.
|
||||
/proc/test_bitflag(var/bitflag)
|
||||
return bitflag != 0 && !(bitflag & (bitflag - 1))
|
||||
|
||||
/*
|
||||
* Diminishing returns formula using a triangular number sequence.
|
||||
* Taken from http://lostsouls.org/grimoire_diminishing_returns
|
||||
*/
|
||||
/proc/triangular_seq(input, scale)
|
||||
if(input < 0)
|
||||
return -triangular_seq(-input, scale)
|
||||
var/mult = input/scale
|
||||
var/trinum = (sqrt(8 * mult + 1) - 1 ) / 2
|
||||
return trinum * scale
|
||||
/**
|
||||
* Credits to Nickr5 for the useful procs I've taken from his library resource.
|
||||
*/
|
||||
|
||||
var/const/E = 2.71828183
|
||||
var/const/Sqrt2 = 1.41421356
|
||||
|
||||
/* //All point fingers and laugh at this joke of a list, I even heard using sqrt() is faster than this list lookup, honk.
|
||||
// List of square roots for the numbers 1-100.
|
||||
var/list/sqrtTable = list(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10)
|
||||
*/
|
||||
|
||||
/proc/Atan2(x, y)
|
||||
if (!x && !y)
|
||||
return 0
|
||||
|
||||
var/invcos = arccos(x / sqrt(x * x + y * y))
|
||||
return y >= 0 ? invcos : -invcos
|
||||
|
||||
proc/arctan(x)
|
||||
var/y=arcsin(x/sqrt(1+x*x))
|
||||
return y
|
||||
|
||||
/proc/Ceiling(x, y = 1)
|
||||
. = -round(-x / y) * y
|
||||
|
||||
//Moved to macros.dm to reduce pure calling overhead, this was being called shitloads, like, most calls of all procs.
|
||||
/*
|
||||
/proc/Clamp(const/val, const/min, const/max)
|
||||
if (val <= min)
|
||||
return min
|
||||
|
||||
if (val >= max)
|
||||
return max
|
||||
|
||||
return val
|
||||
*/
|
||||
|
||||
// cotangent
|
||||
/proc/Cot(x)
|
||||
return 1 / Tan(x)
|
||||
|
||||
// cosecant
|
||||
/proc/Csc(x)
|
||||
return 1 / sin(x)
|
||||
|
||||
/proc/Default(a, b)
|
||||
return a ? a : b
|
||||
|
||||
/proc/Floor(x = 0, y = 0)
|
||||
if(x == 0)
|
||||
return 0
|
||||
if(y == 0)
|
||||
return round(x)
|
||||
|
||||
if(x < y)
|
||||
return 0
|
||||
|
||||
var/diff = round(x, y) //finds x to the nearest value of y
|
||||
if(diff > x)
|
||||
return x - (y - (diff - x)) //diff minus x is the inverse of what we want to remove, so we subtract from y - the base unit - and subtract the result
|
||||
else
|
||||
return diff //this is good enough
|
||||
|
||||
// Greatest Common Divisor - Euclid's algorithm
|
||||
/proc/Gcd(a, b)
|
||||
return b ? Gcd(b, a % b) : a
|
||||
|
||||
/proc/Inverse(x)
|
||||
return 1 / x
|
||||
|
||||
/proc/IsAboutEqual(a, b, deviation = 0.1)
|
||||
return abs(a - b) <= deviation
|
||||
|
||||
/proc/IsEven(x)
|
||||
return x % 2 == 0
|
||||
|
||||
// Returns true if val is from min to max, inclusive.
|
||||
/proc/IsInRange(val, min, max)
|
||||
return min <= val && val <= max
|
||||
|
||||
/proc/IsInteger(x)
|
||||
return Floor(x) == x
|
||||
|
||||
/proc/IsOdd(x)
|
||||
return !IsEven(x)
|
||||
|
||||
/proc/IsMultiple(x, y)
|
||||
return x % y == 0
|
||||
|
||||
// Least Common Multiple
|
||||
/proc/Lcm(a, b)
|
||||
return abs(a) / Gcd(a, b) * abs(b)
|
||||
|
||||
/**
|
||||
* Generic lerp function.
|
||||
*/
|
||||
/proc/lerp(x, x0, x1, y0 = 0, y1 = 1)
|
||||
return y0 + (y1 - y0)*(x - x0)/(x1 - x0)
|
||||
|
||||
/**
|
||||
* Lerps x to a value between [a, b]. x must be in the range [0, 1].
|
||||
* My undying gratitude goes out to wwjnc.
|
||||
*
|
||||
* Basically this returns the number corresponding to a certain
|
||||
* percentage in a range. 0% would be a, 100% would be b, 50% would
|
||||
* be halfways between a and b, and so on.
|
||||
*
|
||||
* Other methods of lerping might not yield the exact value of a or b
|
||||
* when x = 0 or 1. This one guarantees that.
|
||||
*
|
||||
* Examples:
|
||||
* - mix(0.0, 30, 60) = 30
|
||||
* - mix(1.0, 30, 60) = 60
|
||||
* - mix(0.5, 30, 60) = 45
|
||||
* - mix(0.75, 30, 60) = 52.5
|
||||
*/
|
||||
/proc/mix(a, b, x)
|
||||
return a*(1 - x) + b*x
|
||||
|
||||
/**
|
||||
* Lerps x to a value between [0, 1]. x must be in the range [a, b].
|
||||
*
|
||||
* This is the counterpart to the mix() function. It returns the actual
|
||||
* percentage x is at inside the [a, b] range.
|
||||
*
|
||||
* Note that this is theoretically equivalent to calling lerp(x, a, b)
|
||||
* (y0 and y1 default to 0 and 1) but this one is slightly faster
|
||||
* because Byond is too dumb to optimize procs with default values. It
|
||||
* shouldn't matter which one you use (since there are no FP issues)
|
||||
* but this one is more explicit as to what you're doing.
|
||||
*
|
||||
* @todo Find a better name for this. I can't into english.
|
||||
* http://i.imgur.com/8Pu0x7M.png
|
||||
*/
|
||||
/proc/unmix(x, a, b, min = 0, max = 1)
|
||||
if(a==b) return 1
|
||||
return Clamp( (b - x)/(b - a), min, max )
|
||||
|
||||
/proc/Mean(...)
|
||||
var/values = 0
|
||||
var/sum = 0
|
||||
for(var/val in args)
|
||||
values++
|
||||
sum += val
|
||||
return sum / values
|
||||
|
||||
|
||||
/*
|
||||
* Returns the nth root of x.
|
||||
*/
|
||||
/proc/Root(const/n, const/x)
|
||||
return x ** (1 / n)
|
||||
|
||||
/*
|
||||
* Secant.
|
||||
*/
|
||||
/proc/Sec(const/x)
|
||||
return 1 / cos(x)
|
||||
|
||||
// The quadratic formula. Returns a list with the solutions, or an empty list
|
||||
// if they are imaginary.
|
||||
/proc/SolveQuadratic(a, b, c)
|
||||
ASSERT(a)
|
||||
. = list()
|
||||
var/d = b*b - 4 * a * c
|
||||
var/bottom = 2 * a
|
||||
if(d < 0) return
|
||||
var/root = sqrt(d)
|
||||
. += (-b + root) / bottom
|
||||
if(!d) return
|
||||
. += (-b - root) / bottom
|
||||
|
||||
/*
|
||||
* Tangent.
|
||||
*/
|
||||
/proc/Tan(const/x)
|
||||
return sin(x) / cos(x)
|
||||
|
||||
/proc/ToDegrees(const/radians)
|
||||
// 180 / Pi
|
||||
return radians * 57.2957795
|
||||
|
||||
/proc/ToRadians(const/degrees)
|
||||
// Pi / 180
|
||||
return degrees * 0.0174532925
|
||||
|
||||
// min is inclusive, max is exclusive
|
||||
/proc/Wrap(val, min, max)
|
||||
var/d = max - min
|
||||
var/t = Floor((val - min) / d)
|
||||
return val - (t * d)
|
||||
|
||||
/*
|
||||
* A very crude linear approximatiaon of pythagoras theorem.
|
||||
*/
|
||||
/proc/cheap_pythag(const/Ax, const/Ay)
|
||||
var/dx = abs(Ax)
|
||||
var/dy = abs(Ay)
|
||||
|
||||
if (dx >= dy)
|
||||
return dx + (0.5 * dy) // The longest side add half the shortest side approximates the hypotenuse.
|
||||
else
|
||||
return dy + (0.5 * dx)
|
||||
|
||||
/*
|
||||
* Magic constants obtained by using linear regression on right-angled triangles of sides 0<x<1, 0<y<1
|
||||
* They should approximate pythagoras theorem well enough for our needs.
|
||||
*/
|
||||
#define k1 0.934
|
||||
#define k2 0.427
|
||||
/proc/cheap_hypotenuse(const/Ax, const/Ay, const/Bx, const/By)
|
||||
var/dx = abs(Ax - Bx) // Sides of right-angled triangle.
|
||||
var/dy = abs(Ay - By)
|
||||
|
||||
if (dx >= dy)
|
||||
return (k1*dx) + (k2*dy) // No sqrt or powers :).
|
||||
else
|
||||
return (k2*dx) + (k1*dy)
|
||||
#undef k1
|
||||
#undef k2
|
||||
|
||||
//Checks if something's a power of 2, to check bitflags.
|
||||
//Thanks to wwjnc for this.
|
||||
/proc/test_bitflag(var/bitflag)
|
||||
return bitflag != 0 && !(bitflag & (bitflag - 1))
|
||||
|
||||
/*
|
||||
* Diminishing returns formula using a triangular number sequence.
|
||||
* Taken from http://lostsouls.org/grimoire_diminishing_returns
|
||||
*/
|
||||
/proc/triangular_seq(input, scale)
|
||||
if(input < 0)
|
||||
return -triangular_seq(-input, scale)
|
||||
var/mult = input/scale
|
||||
var/trinum = (sqrt(8 * mult + 1) - 1 ) / 2
|
||||
return trinum * scale
|
||||
|
||||
@@ -1,169 +1,169 @@
|
||||
proc/random_hair_style(gender, species = "Human")
|
||||
var/h_style = "Bald"
|
||||
|
||||
var/list/valid_hairstyles = list()
|
||||
for(var/hairstyle in hair_styles_list)
|
||||
var/datum/sprite_accessory/S = hair_styles_list[hairstyle]
|
||||
if(gender == MALE && S.gender == FEMALE)
|
||||
continue
|
||||
if(gender == FEMALE && S.gender == MALE)
|
||||
continue
|
||||
if( !(species in S.species_allowed))
|
||||
continue
|
||||
valid_hairstyles[hairstyle] = hair_styles_list[hairstyle]
|
||||
|
||||
if(valid_hairstyles.len)
|
||||
h_style = pick(valid_hairstyles)
|
||||
|
||||
return h_style
|
||||
|
||||
/proc/GetOppositeDir(var/dir)
|
||||
switch(dir)
|
||||
if(NORTH) return SOUTH
|
||||
if(SOUTH) return NORTH
|
||||
if(EAST) return WEST
|
||||
if(WEST) return EAST
|
||||
if(SOUTHWEST) return NORTHEAST
|
||||
if(NORTHWEST) return SOUTHEAST
|
||||
if(NORTHEAST) return SOUTHWEST
|
||||
if(SOUTHEAST) return NORTHWEST
|
||||
return 0
|
||||
|
||||
proc/random_facial_hair_style(gender, species = "Human")
|
||||
var/f_style = "Shaved"
|
||||
|
||||
var/list/valid_facialhairstyles = list()
|
||||
for(var/facialhairstyle in facial_hair_styles_list)
|
||||
var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle]
|
||||
if(gender == MALE && S.gender == FEMALE)
|
||||
continue
|
||||
if(gender == FEMALE && S.gender == MALE)
|
||||
continue
|
||||
if( !(species in S.species_allowed))
|
||||
continue
|
||||
|
||||
valid_facialhairstyles[facialhairstyle] = facial_hair_styles_list[facialhairstyle]
|
||||
|
||||
if(valid_facialhairstyles.len)
|
||||
f_style = pick(valid_facialhairstyles)
|
||||
|
||||
return f_style
|
||||
|
||||
proc/random_name(gender, speciesName = "Human")
|
||||
var/datum/species/S = all_species[speciesName]
|
||||
if(S)
|
||||
return S.makeName(gender)
|
||||
else
|
||||
var/datum/species/human/H = new
|
||||
return H.makeName(gender)
|
||||
|
||||
|
||||
|
||||
proc/random_skin_tone()
|
||||
switch(pick(60;"caucasian", 15;"afroamerican", 10;"african", 10;"latino", 5;"albino"))
|
||||
if("caucasian") . = -10
|
||||
if("afroamerican") . = -115
|
||||
if("african") . = -165
|
||||
if("latino") . = -55
|
||||
if("albino") . = 34
|
||||
else . = rand(-185,34)
|
||||
return min(max( .+rand(-25, 25), -185),34)
|
||||
|
||||
proc/skintone2racedescription(tone)
|
||||
switch (tone)
|
||||
if(30 to INFINITY) return "albino"
|
||||
if(20 to 30) return "pale"
|
||||
if(5 to 15) return "light skinned"
|
||||
if(-10 to 5) return "white"
|
||||
if(-25 to -10) return "tan"
|
||||
if(-45 to -25) return "darker skinned"
|
||||
if(-65 to -45) return "brown"
|
||||
if(-INFINITY to -65) return "black"
|
||||
else return "unknown"
|
||||
|
||||
proc/age2agedescription(age)
|
||||
switch(age)
|
||||
if(0 to 1) return "infant"
|
||||
if(1 to 3) return "toddler"
|
||||
if(3 to 13) return "child"
|
||||
if(13 to 19) return "teenager"
|
||||
if(19 to 30) return "young adult"
|
||||
if(30 to 45) return "adult"
|
||||
if(45 to 60) return "middle-aged"
|
||||
if(60 to 70) return "aging"
|
||||
if(70 to INFINITY) return "elderly"
|
||||
else return "unknown"
|
||||
|
||||
proc/RoundHealth(health)
|
||||
switch(health)
|
||||
if(100 to INFINITY)
|
||||
return "health100"
|
||||
if(70 to 100)
|
||||
return "health80"
|
||||
if(50 to 70)
|
||||
return "health60"
|
||||
if(30 to 50)
|
||||
return "health40"
|
||||
if(18 to 30)
|
||||
return "health25"
|
||||
if(5 to 18)
|
||||
return "health10"
|
||||
if(1 to 5)
|
||||
return "health1"
|
||||
if(-99 to 0)
|
||||
return "health0"
|
||||
else
|
||||
return "health-100"
|
||||
return "0"
|
||||
|
||||
/*
|
||||
Proc for attack log creation, because really why not
|
||||
1 argument is the actor
|
||||
2 argument is the target of action
|
||||
3 is the description of action(like punched, throwed, or any other verb)
|
||||
4 should it make adminlog note or not
|
||||
5 is the tool with which the action was made(usually item) 5 and 6 are very similar(5 have "by " before it, that it) and are separated just to keep things in a bit more in order
|
||||
6 is additional information, anything that needs to be added
|
||||
*/
|
||||
|
||||
proc/add_logs(mob/user, mob/target, what_done, var/admin=1, var/object=null, var/addition=null)
|
||||
if(user && ismob(user))
|
||||
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Has [what_done] [target ? "[target.name][(ismob(target) && target.ckey) ? "([target.ckey])" : ""]" : "NON-EXISTANT SUBJECT"][object ? " with [object]" : " "][addition]</font>")
|
||||
if(target && ismob(target))
|
||||
target.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been [what_done] by [user ? "[user.name][(ismob(user) && user.ckey) ? "([user.ckey])" : ""]" : "NON-EXISTANT SUBJECT"][object ? " with [object]" : " "][addition]</font>")
|
||||
if(!iscarbon(user))
|
||||
target.LAssailant = null
|
||||
else
|
||||
target.LAssailant = user
|
||||
if(admin)
|
||||
log_attack("<font color='red'>[user ? "[user.name][(ismob(user) && user.ckey) ? "([user.ckey])" : ""]" : "NON-EXISTANT SUBJECT"] [what_done] [target ? "[target.name][(ismob(target) && target.ckey)? "([target.ckey])" : ""]" : "NON-EXISTANT SUBJECT"][object ? " with [object]" : " "][addition]</font>")
|
||||
|
||||
proc/add_ghostlogs(var/mob/user, var/obj/target, var/what_done, var/admin=1, var/addition=null)
|
||||
var/target_text = "NON-EXISTENT TARGET"
|
||||
var/subject_text = "NON-EXISTENT SUBJECT"
|
||||
if(target)
|
||||
target_text=target.name
|
||||
if(ismob(target))
|
||||
var/mob/M=target
|
||||
if(M.ckey)
|
||||
target_text += "([M.ckey])"
|
||||
if(user)
|
||||
subject_text=user.name
|
||||
if(ismob(user))
|
||||
var/mob/M=user
|
||||
if(M.ckey)
|
||||
subject_text += "([M.ckey])"
|
||||
if(user && ismob(user))
|
||||
user.attack_log += "\[[time_stamp()]\] GHOST: <font color='red'>Has [what_done] [target_text] [addition]</font>"
|
||||
if(target && ismob(target))
|
||||
var/mob/M=target
|
||||
M.attack_log += "\[[time_stamp()]\] GHOST: <font color='orange'>Has been [what_done] by [subject_text] [addition]</font>"
|
||||
if(admin)
|
||||
//message_admins("GHOST: [subject_text] [what_done] [target_text] [addition]")
|
||||
if(isAdminGhost(user))
|
||||
log_adminghost("[subject_text] [what_done] [target_text] [addition]")
|
||||
else
|
||||
log_ghost("[subject_text] [what_done] [target_text] [addition]")
|
||||
|
||||
/mob/proc/isVentCrawling()
|
||||
proc/random_hair_style(gender, species = "Human")
|
||||
var/h_style = "Bald"
|
||||
|
||||
var/list/valid_hairstyles = list()
|
||||
for(var/hairstyle in hair_styles_list)
|
||||
var/datum/sprite_accessory/S = hair_styles_list[hairstyle]
|
||||
if(gender == MALE && S.gender == FEMALE)
|
||||
continue
|
||||
if(gender == FEMALE && S.gender == MALE)
|
||||
continue
|
||||
if( !(species in S.species_allowed))
|
||||
continue
|
||||
valid_hairstyles[hairstyle] = hair_styles_list[hairstyle]
|
||||
|
||||
if(valid_hairstyles.len)
|
||||
h_style = pick(valid_hairstyles)
|
||||
|
||||
return h_style
|
||||
|
||||
/proc/GetOppositeDir(var/dir)
|
||||
switch(dir)
|
||||
if(NORTH) return SOUTH
|
||||
if(SOUTH) return NORTH
|
||||
if(EAST) return WEST
|
||||
if(WEST) return EAST
|
||||
if(SOUTHWEST) return NORTHEAST
|
||||
if(NORTHWEST) return SOUTHEAST
|
||||
if(NORTHEAST) return SOUTHWEST
|
||||
if(SOUTHEAST) return NORTHWEST
|
||||
return 0
|
||||
|
||||
proc/random_facial_hair_style(gender, species = "Human")
|
||||
var/f_style = "Shaved"
|
||||
|
||||
var/list/valid_facialhairstyles = list()
|
||||
for(var/facialhairstyle in facial_hair_styles_list)
|
||||
var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle]
|
||||
if(gender == MALE && S.gender == FEMALE)
|
||||
continue
|
||||
if(gender == FEMALE && S.gender == MALE)
|
||||
continue
|
||||
if( !(species in S.species_allowed))
|
||||
continue
|
||||
|
||||
valid_facialhairstyles[facialhairstyle] = facial_hair_styles_list[facialhairstyle]
|
||||
|
||||
if(valid_facialhairstyles.len)
|
||||
f_style = pick(valid_facialhairstyles)
|
||||
|
||||
return f_style
|
||||
|
||||
proc/random_name(gender, speciesName = "Human")
|
||||
var/datum/species/S = all_species[speciesName]
|
||||
if(S)
|
||||
return S.makeName(gender)
|
||||
else
|
||||
var/datum/species/human/H = new
|
||||
return H.makeName(gender)
|
||||
|
||||
|
||||
|
||||
proc/random_skin_tone()
|
||||
switch(pick(60;"caucasian", 15;"afroamerican", 10;"african", 10;"latino", 5;"albino"))
|
||||
if("caucasian") . = -10
|
||||
if("afroamerican") . = -115
|
||||
if("african") . = -165
|
||||
if("latino") . = -55
|
||||
if("albino") . = 34
|
||||
else . = rand(-185,34)
|
||||
return min(max( .+rand(-25, 25), -185),34)
|
||||
|
||||
proc/skintone2racedescription(tone)
|
||||
switch (tone)
|
||||
if(30 to INFINITY) return "albino"
|
||||
if(20 to 30) return "pale"
|
||||
if(5 to 15) return "light skinned"
|
||||
if(-10 to 5) return "white"
|
||||
if(-25 to -10) return "tan"
|
||||
if(-45 to -25) return "darker skinned"
|
||||
if(-65 to -45) return "brown"
|
||||
if(-INFINITY to -65) return "black"
|
||||
else return "unknown"
|
||||
|
||||
proc/age2agedescription(age)
|
||||
switch(age)
|
||||
if(0 to 1) return "infant"
|
||||
if(1 to 3) return "toddler"
|
||||
if(3 to 13) return "child"
|
||||
if(13 to 19) return "teenager"
|
||||
if(19 to 30) return "young adult"
|
||||
if(30 to 45) return "adult"
|
||||
if(45 to 60) return "middle-aged"
|
||||
if(60 to 70) return "aging"
|
||||
if(70 to INFINITY) return "elderly"
|
||||
else return "unknown"
|
||||
|
||||
proc/RoundHealth(health)
|
||||
switch(health)
|
||||
if(100 to INFINITY)
|
||||
return "health100"
|
||||
if(70 to 100)
|
||||
return "health80"
|
||||
if(50 to 70)
|
||||
return "health60"
|
||||
if(30 to 50)
|
||||
return "health40"
|
||||
if(18 to 30)
|
||||
return "health25"
|
||||
if(5 to 18)
|
||||
return "health10"
|
||||
if(1 to 5)
|
||||
return "health1"
|
||||
if(-99 to 0)
|
||||
return "health0"
|
||||
else
|
||||
return "health-100"
|
||||
return "0"
|
||||
|
||||
/*
|
||||
Proc for attack log creation, because really why not
|
||||
1 argument is the actor
|
||||
2 argument is the target of action
|
||||
3 is the description of action(like punched, throwed, or any other verb)
|
||||
4 should it make adminlog note or not
|
||||
5 is the tool with which the action was made(usually item) 5 and 6 are very similar(5 have "by " before it, that it) and are separated just to keep things in a bit more in order
|
||||
6 is additional information, anything that needs to be added
|
||||
*/
|
||||
|
||||
proc/add_logs(mob/user, mob/target, what_done, var/admin=1, var/object=null, var/addition=null)
|
||||
if(user && ismob(user))
|
||||
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Has [what_done] [target ? "[target.name][(ismob(target) && target.ckey) ? "([target.ckey])" : ""]" : "NON-EXISTANT SUBJECT"][object ? " with [object]" : " "][addition]</font>")
|
||||
if(target && ismob(target))
|
||||
target.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been [what_done] by [user ? "[user.name][(ismob(user) && user.ckey) ? "([user.ckey])" : ""]" : "NON-EXISTANT SUBJECT"][object ? " with [object]" : " "][addition]</font>")
|
||||
if(!iscarbon(user))
|
||||
target.LAssailant = null
|
||||
else
|
||||
target.LAssailant = user
|
||||
if(admin)
|
||||
log_attack("<font color='red'>[user ? "[user.name][(ismob(user) && user.ckey) ? "([user.ckey])" : ""]" : "NON-EXISTANT SUBJECT"] [what_done] [target ? "[target.name][(ismob(target) && target.ckey)? "([target.ckey])" : ""]" : "NON-EXISTANT SUBJECT"][object ? " with [object]" : " "][addition]</font>")
|
||||
|
||||
proc/add_ghostlogs(var/mob/user, var/obj/target, var/what_done, var/admin=1, var/addition=null)
|
||||
var/target_text = "NON-EXISTENT TARGET"
|
||||
var/subject_text = "NON-EXISTENT SUBJECT"
|
||||
if(target)
|
||||
target_text=target.name
|
||||
if(ismob(target))
|
||||
var/mob/M=target
|
||||
if(M.ckey)
|
||||
target_text += "([M.ckey])"
|
||||
if(user)
|
||||
subject_text=user.name
|
||||
if(ismob(user))
|
||||
var/mob/M=user
|
||||
if(M.ckey)
|
||||
subject_text += "([M.ckey])"
|
||||
if(user && ismob(user))
|
||||
user.attack_log += "\[[time_stamp()]\] GHOST: <font color='red'>Has [what_done] [target_text] [addition]</font>"
|
||||
if(target && ismob(target))
|
||||
var/mob/M=target
|
||||
M.attack_log += "\[[time_stamp()]\] GHOST: <font color='orange'>Has been [what_done] by [subject_text] [addition]</font>"
|
||||
if(admin)
|
||||
//message_admins("GHOST: [subject_text] [what_done] [target_text] [addition]")
|
||||
if(isAdminGhost(user))
|
||||
log_adminghost("[subject_text] [what_done] [target_text] [addition]")
|
||||
else
|
||||
log_ghost("[subject_text] [what_done] [target_text] [addition]")
|
||||
|
||||
/mob/proc/isVentCrawling()
|
||||
return (istype(loc, /obj/machinery/atmospherics)) // Crude but no other situation would put them inside of this
|
||||
@@ -1,327 +1,327 @@
|
||||
var/church_name = null
|
||||
/proc/church_name()
|
||||
if (church_name)
|
||||
return church_name
|
||||
|
||||
var/name = ""
|
||||
|
||||
name += pick("Holy", "United", "First", "Second", "Last")
|
||||
|
||||
if (prob(20))
|
||||
name += " Space"
|
||||
|
||||
name += {"[pick("Church", "Cathedral", "Body", "Worshippers", "Movement", "Witnesses")] of [religion_name()]"}
|
||||
return name
|
||||
|
||||
var/command_name = null
|
||||
/proc/command_name()
|
||||
if (command_name)
|
||||
return command_name
|
||||
|
||||
var/name = ""
|
||||
|
||||
if (prob(10))
|
||||
name += pick("Super", "Ultra")
|
||||
name += " "
|
||||
|
||||
// Prefix
|
||||
if (name)
|
||||
name += pick("", "Central", "System", "Home", "Galactic")
|
||||
else
|
||||
name += pick("Central", "System", "Home", "Galactic")
|
||||
if (name)
|
||||
name += " "
|
||||
|
||||
// Suffix
|
||||
name += pick("Federation", "Command", "Alliance", "Unity", "Empire", "Confederation", "Protectorate", "Commonwealth", "Imperium", "Republic")
|
||||
name += " "
|
||||
|
||||
command_name = name
|
||||
return name
|
||||
|
||||
/proc/change_command_name(var/name)
|
||||
|
||||
|
||||
command_name = name
|
||||
|
||||
return name
|
||||
|
||||
var/religion_name = null
|
||||
/proc/religion_name()
|
||||
if (religion_name)
|
||||
return religion_name
|
||||
|
||||
var/name = ""
|
||||
|
||||
name += pick("bee", "science", "edu", "captain", "assistant", "monkey", "alien", "space", "unit", "sprocket", "gadget", "bomb", "revolution", "beyond", "station", "goon", "robot", "ivor", "hobnob")
|
||||
name += pick("ism", "ia", "ology", "istism", "ites", "ick", "ian", "ity")
|
||||
|
||||
return capitalize(name)
|
||||
|
||||
/proc/station_name()
|
||||
if(station_name)
|
||||
return station_name
|
||||
var/random = rand(1,5)
|
||||
var/name = ""
|
||||
|
||||
//Rare: Pre-Prefix
|
||||
if (prob(10))
|
||||
name = pick("Imperium", "Heretical", "Cuban", "Psychic", "Elegant", "Common", "Uncommon", "Rare", "Unique", "Houseruled", "Religious", "Atheist", "Traditional", "Houseruled", "Mad", "Super", "Ultra", "Secret", "Top Secret", "Deep", "Death", "Zybourne", "Central", "Main", "Government", "Uoi", "Fat", "Automated", "Experimental", "Augmented")
|
||||
station_name = name + " "
|
||||
|
||||
// Prefix
|
||||
switch(Holiday)
|
||||
//get normal name
|
||||
if(null,"",0)
|
||||
name = pick("", "Stanford", "Dorf", "Alium", "Prefix", "Clowning", "Aegis", "Ishimura", "Scaredy", "Death-World", "Mime", "Honk", "Rogue", "MacRagge", "Ultrameens", "Safety", "Paranoia", "Explosive", "Neckbear", "Donk", "Muppet", "North", "West", "East", "South", "Slant-ways", "Widdershins", "Rimward", "Expensive", "Procreatory", "Imperial", "Unidentified", "Immoral", "Carp", "Ork", "Pete", "Control", "Nettle", "Aspie", "Class", "Crab", "Fist","Corrogated","Skeleton","Race", "Fatguy", "Gentleman", "Capitalist", "Communist", "Bear", "Beard", "Derp", "Space", "Spess", "Star", "Moon", "System", "Mining", "Neckbeard", "Research", "Supply", "Military", "Orbital", "Battle", "Science", "Asteroid", "Home", "Production", "Transport", "Delivery", "Extraplanetary", "Orbital", "Correctional", "Robot", "Hats", "Pizza")
|
||||
if(name)
|
||||
station_name += name + " "
|
||||
|
||||
//For special days like christmas, easter, new-years etc ~Carn
|
||||
if("Friday the 13th")
|
||||
name = pick("Mike","Friday","Evil","Myers","Murder","Deathly","Stabby")
|
||||
station_name += name + " "
|
||||
random = 13
|
||||
else
|
||||
//get the first word of the Holiday and use that
|
||||
var/i = findtext(Holiday," ",1,0)
|
||||
name = copytext(Holiday,1,i)
|
||||
station_name += name + " "
|
||||
|
||||
// Suffix
|
||||
name = pick("Station", "Fortress", "Frontier", "Suffix", "Death-trap", "Space-hulk", "Lab", "Hazard","Spess Junk", "Fishery", "No-Moon", "Tomb", "Crypt", "Hut", "Monkey", "Bomb", "Trade Post", "Fortress", "Village", "Town", "City", "Edition", "Hive", "Complex", "Base", "Facility", "Depot", "Outpost", "Installation", "Drydock", "Observatory", "Array", "Relay", "Monitor", "Platform", "Construct", "Hangar", "Prison", "Center", "Port", "Waystation", "Factory", "Waypoint", "Stopover", "Hub", "HQ", "Office", "Object", "Fortification", "Colony", "Planet-Cracker", "Roost", "Fat Camp")
|
||||
station_name += name + " "
|
||||
|
||||
// ID Number
|
||||
switch(random)
|
||||
if(1)
|
||||
station_name += "[rand(1, 99)]"
|
||||
if(2)
|
||||
station_name += pick("Alpha", "Beta", "Gamma", "Delta", "Epsilon", "Zeta", "Eta", "Theta", "Iota", "Kappa", "Lambda", "Mu", "Nu", "Xi", "Omicron", "Pi", "Rho", "Sigma", "Tau", "Upsilon", "Phi", "Chi", "Psi", "Omega")
|
||||
if(3)
|
||||
station_name += pick("II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX")
|
||||
if(4)
|
||||
station_name += pick("Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot", "Golf", "Hotel", "India", "Juliet", "Kilo", "Lima", "Mike", "November", "Oscar", "Papa", "Quebec", "Romeo", "Sierra", "Tango", "Uniform", "Victor", "Whiskey", "X-ray", "Yankee", "Zulu")
|
||||
if(5)
|
||||
station_name += pick("One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen")
|
||||
if(13)
|
||||
station_name += pick("13","XIII","Thirteen")
|
||||
|
||||
|
||||
if (config && config.server_name)
|
||||
world.name = "[config.server_name]: [name]"
|
||||
else
|
||||
world.name = station_name
|
||||
|
||||
return station_name
|
||||
|
||||
/proc/world_name(var/name)
|
||||
|
||||
|
||||
station_name = name
|
||||
|
||||
if (config && config.server_name)
|
||||
world.name = "[config.server_name]: [name]"
|
||||
else
|
||||
world.name = name
|
||||
|
||||
return name
|
||||
|
||||
var/syndicate_name = null
|
||||
/proc/syndicate_name()
|
||||
if (syndicate_name)
|
||||
return syndicate_name
|
||||
|
||||
var/name = ""
|
||||
|
||||
// Prefix
|
||||
name += pick("Clandestine", "Prima", "Blue", "Zero-G", "Max", "Blasto", "Waffle", "North", "Omni", "Newton", "Cyber", "Bonk", "Gene", "Gib")
|
||||
|
||||
// Suffix
|
||||
if (prob(80))
|
||||
name += " "
|
||||
|
||||
// Full
|
||||
if (prob(60))
|
||||
name += pick("Syndicate", "Consortium", "Collective", "Corporation", "Group", "Holdings", "Biotech", "Industries", "Systems", "Products", "Chemicals", "Enterprises", "Family", "Creations", "International", "Intergalactic", "Interplanetary", "Foundation", "Positronics", "Hive")
|
||||
// Broken
|
||||
else
|
||||
name += pick("Syndi", "Corp", "Bio", "System", "Prod", "Chem", "Inter", "Hive")
|
||||
name += pick("", "-")
|
||||
name += pick("Tech", "Sun", "Co", "Tek", "X", "Inc", "Code")
|
||||
// Small
|
||||
else
|
||||
name += pick("-", "*", "")
|
||||
name += pick("Tech", "Sun", "Co", "Tek", "X", "Inc", "Gen", "Star", "Dyne", "Code", "Hive")
|
||||
|
||||
syndicate_name = name
|
||||
return name
|
||||
|
||||
|
||||
//Traitors and traitor silicons will get these. Revs will not.
|
||||
var/syndicate_code_phrase//Code phrase for traitors.
|
||||
var/syndicate_code_response//Code response for traitors.
|
||||
|
||||
/*
|
||||
Should be expanded.
|
||||
How this works:
|
||||
Instead of "I'm looking for James Smith," the traitor would say "James Smith" as part of a conversation.
|
||||
Another traitor may then respond with: "They enjoy running through the void-filled vacuum of the derelict."
|
||||
The phrase should then have the words: James Smith.
|
||||
The response should then have the words: run, void, and derelict.
|
||||
This way assures that the code is suited to the conversation and is unpredicatable.
|
||||
Obviously, some people will be better at this than others but in theory, everyone should be able to do it and it only enhances roleplay.
|
||||
Can probably be done through "{ }" but I don't really see the practical benefit.
|
||||
One example of an earlier system is commented below.
|
||||
/N
|
||||
*/
|
||||
|
||||
/proc/generate_code_phrase()//Proc is used for phrase and response in master_controller.dm
|
||||
|
||||
|
||||
var/code_phrase = ""//What is returned when the proc finishes.
|
||||
var/words = pick(//How many words there will be. Minimum of two. 2, 4 and 5 have a lesser chance of being selected. 3 is the most likely.
|
||||
50; 2,
|
||||
200; 3,
|
||||
50; 4,
|
||||
25; 5
|
||||
)
|
||||
|
||||
var/safety[] = list(1,2,3)//Tells the proc which options to remove later on.
|
||||
var/nouns[] = list("love","hate","anger","peace","pride","sympathy","bravery","loyalty","honesty","integrity","compassion","charity","success","courage","deceit","skill","beauty","brilliance","pain","misery","beliefs","dreams","justice","truth","faith","liberty","knowledge","thought","information","culture","trust","dedication","progress","education","hospitality","leisure","trouble","friendships", "relaxation")
|
||||
var/drinks[] = list("vodka and tonic","gin fizz","bahama mama","manhattan","black Russian","whiskey soda","long island tea","margarita","Irish coffee"," manly dwarf","Irish cream","doctor's delight","Beepksy Smash","tequila sunrise","brave bull","gargle blaster","bloody mary","whiskey cola","white Russian","vodka martini","martini","Cuba libre","kahlua","vodka","wine","moonshine")
|
||||
var/locations[] = teleportlocs.len ? teleportlocs : drinks//if null, defaults to drinks instead.
|
||||
|
||||
var/names[] = list()
|
||||
for(var/datum/data/record/t in data_core.general)//Picks from crew manifest.
|
||||
names += t.fields["name"]
|
||||
|
||||
var/maxwords = words//Extra var to check for duplicates.
|
||||
|
||||
for(words,words>0,words--)//Randomly picks from one of the choices below.
|
||||
|
||||
if(words==1&&(1 in safety)&&(2 in safety))//If there is only one word remaining and choice 1 or 2 have not been selected.
|
||||
safety = list(pick(1,2))//Select choice 1 or 2.
|
||||
else if(words==1&&maxwords==2)//Else if there is only one word remaining (and there were two originally), and 1 or 2 were chosen,
|
||||
safety = list(3)//Default to list 3
|
||||
|
||||
switch(pick(safety))//Chance based on the safety list.
|
||||
if(1)//1 and 2 can only be selected once each to prevent more than two specific names/places/etc.
|
||||
switch(rand(1,2))//Mainly to add more options later.
|
||||
if(1)
|
||||
if(names.len&&prob(70))
|
||||
code_phrase += pick(names)
|
||||
else
|
||||
code_phrase += pick(pick(first_names_male,first_names_female))
|
||||
code_phrase += " "
|
||||
code_phrase += pick(last_names)
|
||||
if(2)
|
||||
code_phrase += pick(get_all_jobs())//Returns a job.
|
||||
safety -= 1
|
||||
if(2)
|
||||
switch(rand(1,2))//Places or things.
|
||||
if(1)
|
||||
code_phrase += pick(drinks)
|
||||
if(2)
|
||||
code_phrase += pick(locations)
|
||||
safety -= 2
|
||||
if(3)
|
||||
switch(rand(1,3))//Nouns, adjectives, verbs. Can be selected more than once.
|
||||
if(1)
|
||||
code_phrase += pick(nouns)
|
||||
if(2)
|
||||
code_phrase += pick(adjectives)
|
||||
if(3)
|
||||
code_phrase += pick(verbs)
|
||||
if(words==1)
|
||||
code_phrase += "."
|
||||
else
|
||||
code_phrase += ", "
|
||||
|
||||
return code_phrase
|
||||
|
||||
/*
|
||||
//This proc tests the gen above.
|
||||
/client/verb/test_code_phrase()
|
||||
set name = "Generate Code Phrase"
|
||||
set category = "Debug"
|
||||
|
||||
var/church_name = null
|
||||
/proc/church_name()
|
||||
if (church_name)
|
||||
return church_name
|
||||
|
||||
var/name = ""
|
||||
|
||||
name += pick("Holy", "United", "First", "Second", "Last")
|
||||
|
||||
if (prob(20))
|
||||
name += " Space"
|
||||
|
||||
name += {"[pick("Church", "Cathedral", "Body", "Worshippers", "Movement", "Witnesses")] of [religion_name()]"}
|
||||
return name
|
||||
|
||||
var/command_name = null
|
||||
/proc/command_name()
|
||||
if (command_name)
|
||||
return command_name
|
||||
|
||||
var/name = ""
|
||||
|
||||
if (prob(10))
|
||||
name += pick("Super", "Ultra")
|
||||
name += " "
|
||||
|
||||
// Prefix
|
||||
if (name)
|
||||
name += pick("", "Central", "System", "Home", "Galactic")
|
||||
else
|
||||
name += pick("Central", "System", "Home", "Galactic")
|
||||
if (name)
|
||||
name += " "
|
||||
|
||||
// Suffix
|
||||
name += pick("Federation", "Command", "Alliance", "Unity", "Empire", "Confederation", "Protectorate", "Commonwealth", "Imperium", "Republic")
|
||||
name += " "
|
||||
|
||||
command_name = name
|
||||
return name
|
||||
|
||||
/proc/change_command_name(var/name)
|
||||
|
||||
|
||||
command_name = name
|
||||
|
||||
return name
|
||||
|
||||
var/religion_name = null
|
||||
/proc/religion_name()
|
||||
if (religion_name)
|
||||
return religion_name
|
||||
|
||||
var/name = ""
|
||||
|
||||
name += pick("bee", "science", "edu", "captain", "assistant", "monkey", "alien", "space", "unit", "sprocket", "gadget", "bomb", "revolution", "beyond", "station", "goon", "robot", "ivor", "hobnob")
|
||||
name += pick("ism", "ia", "ology", "istism", "ites", "ick", "ian", "ity")
|
||||
|
||||
return capitalize(name)
|
||||
|
||||
/proc/station_name()
|
||||
if(station_name)
|
||||
return station_name
|
||||
var/random = rand(1,5)
|
||||
var/name = ""
|
||||
|
||||
//Rare: Pre-Prefix
|
||||
if (prob(10))
|
||||
name = pick("Imperium", "Heretical", "Cuban", "Psychic", "Elegant", "Common", "Uncommon", "Rare", "Unique", "Houseruled", "Religious", "Atheist", "Traditional", "Houseruled", "Mad", "Super", "Ultra", "Secret", "Top Secret", "Deep", "Death", "Zybourne", "Central", "Main", "Government", "Uoi", "Fat", "Automated", "Experimental", "Augmented")
|
||||
station_name = name + " "
|
||||
|
||||
// Prefix
|
||||
switch(Holiday)
|
||||
//get normal name
|
||||
if(null,"",0)
|
||||
name = pick("", "Stanford", "Dorf", "Alium", "Prefix", "Clowning", "Aegis", "Ishimura", "Scaredy", "Death-World", "Mime", "Honk", "Rogue", "MacRagge", "Ultrameens", "Safety", "Paranoia", "Explosive", "Neckbear", "Donk", "Muppet", "North", "West", "East", "South", "Slant-ways", "Widdershins", "Rimward", "Expensive", "Procreatory", "Imperial", "Unidentified", "Immoral", "Carp", "Ork", "Pete", "Control", "Nettle", "Aspie", "Class", "Crab", "Fist","Corrogated","Skeleton","Race", "Fatguy", "Gentleman", "Capitalist", "Communist", "Bear", "Beard", "Derp", "Space", "Spess", "Star", "Moon", "System", "Mining", "Neckbeard", "Research", "Supply", "Military", "Orbital", "Battle", "Science", "Asteroid", "Home", "Production", "Transport", "Delivery", "Extraplanetary", "Orbital", "Correctional", "Robot", "Hats", "Pizza")
|
||||
if(name)
|
||||
station_name += name + " "
|
||||
|
||||
//For special days like christmas, easter, new-years etc ~Carn
|
||||
if("Friday the 13th")
|
||||
name = pick("Mike","Friday","Evil","Myers","Murder","Deathly","Stabby")
|
||||
station_name += name + " "
|
||||
random = 13
|
||||
else
|
||||
//get the first word of the Holiday and use that
|
||||
var/i = findtext(Holiday," ",1,0)
|
||||
name = copytext(Holiday,1,i)
|
||||
station_name += name + " "
|
||||
|
||||
// Suffix
|
||||
name = pick("Station", "Fortress", "Frontier", "Suffix", "Death-trap", "Space-hulk", "Lab", "Hazard","Spess Junk", "Fishery", "No-Moon", "Tomb", "Crypt", "Hut", "Monkey", "Bomb", "Trade Post", "Fortress", "Village", "Town", "City", "Edition", "Hive", "Complex", "Base", "Facility", "Depot", "Outpost", "Installation", "Drydock", "Observatory", "Array", "Relay", "Monitor", "Platform", "Construct", "Hangar", "Prison", "Center", "Port", "Waystation", "Factory", "Waypoint", "Stopover", "Hub", "HQ", "Office", "Object", "Fortification", "Colony", "Planet-Cracker", "Roost", "Fat Camp")
|
||||
station_name += name + " "
|
||||
|
||||
// ID Number
|
||||
switch(random)
|
||||
if(1)
|
||||
station_name += "[rand(1, 99)]"
|
||||
if(2)
|
||||
station_name += pick("Alpha", "Beta", "Gamma", "Delta", "Epsilon", "Zeta", "Eta", "Theta", "Iota", "Kappa", "Lambda", "Mu", "Nu", "Xi", "Omicron", "Pi", "Rho", "Sigma", "Tau", "Upsilon", "Phi", "Chi", "Psi", "Omega")
|
||||
if(3)
|
||||
station_name += pick("II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX")
|
||||
if(4)
|
||||
station_name += pick("Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot", "Golf", "Hotel", "India", "Juliet", "Kilo", "Lima", "Mike", "November", "Oscar", "Papa", "Quebec", "Romeo", "Sierra", "Tango", "Uniform", "Victor", "Whiskey", "X-ray", "Yankee", "Zulu")
|
||||
if(5)
|
||||
station_name += pick("One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen")
|
||||
if(13)
|
||||
station_name += pick("13","XIII","Thirteen")
|
||||
|
||||
|
||||
if (config && config.server_name)
|
||||
world.name = "[config.server_name]: [name]"
|
||||
else
|
||||
world.name = station_name
|
||||
|
||||
return station_name
|
||||
|
||||
/proc/world_name(var/name)
|
||||
|
||||
|
||||
station_name = name
|
||||
|
||||
if (config && config.server_name)
|
||||
world.name = "[config.server_name]: [name]"
|
||||
else
|
||||
world.name = name
|
||||
|
||||
return name
|
||||
|
||||
var/syndicate_name = null
|
||||
/proc/syndicate_name()
|
||||
if (syndicate_name)
|
||||
return syndicate_name
|
||||
|
||||
var/name = ""
|
||||
|
||||
// Prefix
|
||||
name += pick("Clandestine", "Prima", "Blue", "Zero-G", "Max", "Blasto", "Waffle", "North", "Omni", "Newton", "Cyber", "Bonk", "Gene", "Gib")
|
||||
|
||||
// Suffix
|
||||
if (prob(80))
|
||||
name += " "
|
||||
|
||||
// Full
|
||||
if (prob(60))
|
||||
name += pick("Syndicate", "Consortium", "Collective", "Corporation", "Group", "Holdings", "Biotech", "Industries", "Systems", "Products", "Chemicals", "Enterprises", "Family", "Creations", "International", "Intergalactic", "Interplanetary", "Foundation", "Positronics", "Hive")
|
||||
// Broken
|
||||
else
|
||||
name += pick("Syndi", "Corp", "Bio", "System", "Prod", "Chem", "Inter", "Hive")
|
||||
name += pick("", "-")
|
||||
name += pick("Tech", "Sun", "Co", "Tek", "X", "Inc", "Code")
|
||||
// Small
|
||||
else
|
||||
name += pick("-", "*", "")
|
||||
name += pick("Tech", "Sun", "Co", "Tek", "X", "Inc", "Gen", "Star", "Dyne", "Code", "Hive")
|
||||
|
||||
syndicate_name = name
|
||||
return name
|
||||
|
||||
|
||||
//Traitors and traitor silicons will get these. Revs will not.
|
||||
var/syndicate_code_phrase//Code phrase for traitors.
|
||||
var/syndicate_code_response//Code response for traitors.
|
||||
|
||||
/*
|
||||
Should be expanded.
|
||||
How this works:
|
||||
Instead of "I'm looking for James Smith," the traitor would say "James Smith" as part of a conversation.
|
||||
Another traitor may then respond with: "They enjoy running through the void-filled vacuum of the derelict."
|
||||
The phrase should then have the words: James Smith.
|
||||
The response should then have the words: run, void, and derelict.
|
||||
This way assures that the code is suited to the conversation and is unpredicatable.
|
||||
Obviously, some people will be better at this than others but in theory, everyone should be able to do it and it only enhances roleplay.
|
||||
Can probably be done through "{ }" but I don't really see the practical benefit.
|
||||
One example of an earlier system is commented below.
|
||||
/N
|
||||
*/
|
||||
|
||||
/proc/generate_code_phrase()//Proc is used for phrase and response in master_controller.dm
|
||||
|
||||
|
||||
var/code_phrase = ""//What is returned when the proc finishes.
|
||||
var/words = pick(//How many words there will be. Minimum of two. 2, 4 and 5 have a lesser chance of being selected. 3 is the most likely.
|
||||
50; 2,
|
||||
200; 3,
|
||||
50; 4,
|
||||
25; 5
|
||||
)
|
||||
|
||||
var/safety[] = list(1,2,3)//Tells the proc which options to remove later on.
|
||||
var/nouns[] = list("love","hate","anger","peace","pride","sympathy","bravery","loyalty","honesty","integrity","compassion","charity","success","courage","deceit","skill","beauty","brilliance","pain","misery","beliefs","dreams","justice","truth","faith","liberty","knowledge","thought","information","culture","trust","dedication","progress","education","hospitality","leisure","trouble","friendships", "relaxation")
|
||||
var/drinks[] = list("vodka and tonic","gin fizz","bahama mama","manhattan","black Russian","whiskey soda","long island tea","margarita","Irish coffee"," manly dwarf","Irish cream","doctor's delight","Beepksy Smash","tequila sunrise","brave bull","gargle blaster","bloody mary","whiskey cola","white Russian","vodka martini","martini","Cuba libre","kahlua","vodka","wine","moonshine")
|
||||
var/locations[] = teleportlocs.len ? teleportlocs : drinks//if null, defaults to drinks instead.
|
||||
|
||||
var/names[] = list()
|
||||
for(var/datum/data/record/t in data_core.general)//Picks from crew manifest.
|
||||
names += t.fields["name"]
|
||||
|
||||
var/maxwords = words//Extra var to check for duplicates.
|
||||
|
||||
for(words,words>0,words--)//Randomly picks from one of the choices below.
|
||||
|
||||
if(words==1&&(1 in safety)&&(2 in safety))//If there is only one word remaining and choice 1 or 2 have not been selected.
|
||||
safety = list(pick(1,2))//Select choice 1 or 2.
|
||||
else if(words==1&&maxwords==2)//Else if there is only one word remaining (and there were two originally), and 1 or 2 were chosen,
|
||||
safety = list(3)//Default to list 3
|
||||
|
||||
switch(pick(safety))//Chance based on the safety list.
|
||||
if(1)//1 and 2 can only be selected once each to prevent more than two specific names/places/etc.
|
||||
switch(rand(1,2))//Mainly to add more options later.
|
||||
if(1)
|
||||
if(names.len&&prob(70))
|
||||
code_phrase += pick(names)
|
||||
else
|
||||
code_phrase += pick(pick(first_names_male,first_names_female))
|
||||
code_phrase += " "
|
||||
code_phrase += pick(last_names)
|
||||
if(2)
|
||||
code_phrase += pick(get_all_jobs())//Returns a job.
|
||||
safety -= 1
|
||||
if(2)
|
||||
switch(rand(1,2))//Places or things.
|
||||
if(1)
|
||||
code_phrase += pick(drinks)
|
||||
if(2)
|
||||
code_phrase += pick(locations)
|
||||
safety -= 2
|
||||
if(3)
|
||||
switch(rand(1,3))//Nouns, adjectives, verbs. Can be selected more than once.
|
||||
if(1)
|
||||
code_phrase += pick(nouns)
|
||||
if(2)
|
||||
code_phrase += pick(adjectives)
|
||||
if(3)
|
||||
code_phrase += pick(verbs)
|
||||
if(words==1)
|
||||
code_phrase += "."
|
||||
else
|
||||
code_phrase += ", "
|
||||
|
||||
return code_phrase
|
||||
|
||||
/*
|
||||
//This proc tests the gen above.
|
||||
/client/verb/test_code_phrase()
|
||||
set name = "Generate Code Phrase"
|
||||
set category = "Debug"
|
||||
|
||||
to_chat(world, "<span class='warning'>Code Phrase is: </span>[generate_code_phrase()]")
|
||||
return
|
||||
|
||||
|
||||
This was an earlier attempt at code phrase system, aside from an even earlier attempt (and failure).
|
||||
This system more or less works as intended--aside from being unfinished--but it's still very predictable.
|
||||
Particularly, the phrase opening statements are pretty easy to recognize and identify when metagaming.
|
||||
I think the above-used method solves this issue by using words in a sequence, providing for much greater flexibility.
|
||||
/N
|
||||
|
||||
switch(choice)
|
||||
if(1)
|
||||
syndicate_code_phrase += pick("I'm looking for","Have you seen","Maybe you've seen","I'm trying to find","I'm tracking")
|
||||
syndicate_code_phrase += " "
|
||||
syndicate_code_phrase += pick(pick(first_names_male,first_names_female))
|
||||
syndicate_code_phrase += " "
|
||||
syndicate_code_phrase += pick(last_names)
|
||||
syndicate_code_phrase += "."
|
||||
if(2)
|
||||
syndicate_code_phrase += pick("How do I get to","How do I find","Where is","Where do I find")
|
||||
syndicate_code_phrase += " "
|
||||
syndicate_code_phrase += pick("Escape","Engineering","Atmos","the bridge","the brig","Clown Planet","CentCom","the library","the chapel","a bathroom","Med Bay","Tool Storage","the escape shuttle","Robotics","a locker room","the living quarters","the gym","the autolathe","QM","the bar","the theater","the derelict")
|
||||
syndicate_code_phrase += "?"
|
||||
if(3)
|
||||
if(prob(70))
|
||||
syndicate_code_phrase += pick("Get me","I want","I'd like","Make me")
|
||||
syndicate_code_phrase += " a "
|
||||
else
|
||||
syndicate_code_phrase += pick("One")
|
||||
syndicate_code_phrase += " "
|
||||
syndicate_code_phrase += pick("vodka and tonic","gin fizz","bahama mama","manhattan","black Russian","whiskey soda","long island tea","margarita","Irish coffee"," manly dwarf","Irish cream","doctor's delight","Beepksy Smash","tequila sunrise","brave bull","gargle blaster","bloody mary","whiskey cola","white Russian","vodka martini","martini","Cuba libre","kahlua","vodka","wine","moonshine")
|
||||
syndicate_code_phrase += "."
|
||||
if(4)
|
||||
syndicate_code_phrase += pick("I wish I was","My dad was","His mom was","Where do I find","The hero this station needs is","I'd fuck","I wouldn't trust","Someone caught","HoS caught","Someone found","I'd wrestle","I wanna kill")
|
||||
syndicate_code_phrase += " [pick("a","the")] "
|
||||
syndicate_code_phrase += pick("wizard","ninja","xeno","lizard","slime","monkey","syndicate","cyborg","clown","space carp","singularity","singulo","mime")
|
||||
syndicate_code_phrase += "."
|
||||
if(5)
|
||||
syndicate_code_phrase += pick("Do we have","Is there","Where is","Where's","Who's")
|
||||
syndicate_code_phrase += " "
|
||||
syndicate_code_phrase += "[pick(get_all_jobs())]"
|
||||
syndicate_code_phrase += "?"
|
||||
|
||||
switch(choice)
|
||||
if(1)
|
||||
if(prob(80))
|
||||
syndicate_code_response += pick("Try looking for them near","I they ran off to","Yes. I saw them near","Nope. I'm heading to","Try searching")
|
||||
syndicate_code_response += " "
|
||||
syndicate_code_response += pick("Escape","Engineering","Atmos","the bridge","the brig","Clown Planet","CentCom","the library","the chapel","a bathroom","Med Bay","Tool Storage","the escape shuttle","Robotics","a locker room","the living quarters","the gym","the autolathe","QM","the bar","the theater","the derelict")
|
||||
syndicate_code_response += "."
|
||||
else if(prob(60))
|
||||
syndicate_code_response += pick("No. I'm busy, sorry.","I don't have the time.","Not sure, maybe?","There is no time.")
|
||||
else
|
||||
syndicate_code_response += pick("*shrug*","*smile*","*blink*","*sigh*","*laugh*","*nod*","*giggle*")
|
||||
if(2)
|
||||
if(prob(80))
|
||||
syndicate_code_response += pick("Go to","Navigate to","Try","Sure, run to","Try searching","It's near","It's around")
|
||||
syndicate_code_response += " the "
|
||||
syndicate_code_response += pick("[pick("south","north","east","west")] maitenance door","nearby maitenance","teleporter","[pick("cold","dead")] space","morgue","vacuum","[pick("south","north","east","west")] hall ","[pick("south","north","east","west")] hallway","[pick("white","black","red","green","blue","pink","purple")] [pick("rabbit","frog","lion","tiger","panther","snake","facehugger")]")
|
||||
syndicate_code_response += "."
|
||||
else if(prob(60))
|
||||
syndicate_code_response += pick("Try asking","Ask","Talk to","Go see","Follow","Hunt down")
|
||||
syndicate_code_response += " "
|
||||
if(prob(50))
|
||||
syndicate_code_response += pick(pick(first_names_male,first_names_female))
|
||||
syndicate_code_response += " "
|
||||
syndicate_code_response += pick(last_names)
|
||||
else
|
||||
syndicate_code_response += " the "
|
||||
syndicate_code_response += "[pic(get_all_jobs())]"
|
||||
syndicate_code_response += "."
|
||||
else
|
||||
syndicate_code_response += pick("*shrug*","*smile*","*blink*","*sigh*","*laugh*","*nod*","*giggle*")
|
||||
if(3)
|
||||
if(4)
|
||||
if(5)
|
||||
|
||||
return
|
||||
return
|
||||
|
||||
|
||||
This was an earlier attempt at code phrase system, aside from an even earlier attempt (and failure).
|
||||
This system more or less works as intended--aside from being unfinished--but it's still very predictable.
|
||||
Particularly, the phrase opening statements are pretty easy to recognize and identify when metagaming.
|
||||
I think the above-used method solves this issue by using words in a sequence, providing for much greater flexibility.
|
||||
/N
|
||||
|
||||
switch(choice)
|
||||
if(1)
|
||||
syndicate_code_phrase += pick("I'm looking for","Have you seen","Maybe you've seen","I'm trying to find","I'm tracking")
|
||||
syndicate_code_phrase += " "
|
||||
syndicate_code_phrase += pick(pick(first_names_male,first_names_female))
|
||||
syndicate_code_phrase += " "
|
||||
syndicate_code_phrase += pick(last_names)
|
||||
syndicate_code_phrase += "."
|
||||
if(2)
|
||||
syndicate_code_phrase += pick("How do I get to","How do I find","Where is","Where do I find")
|
||||
syndicate_code_phrase += " "
|
||||
syndicate_code_phrase += pick("Escape","Engineering","Atmos","the bridge","the brig","Clown Planet","CentCom","the library","the chapel","a bathroom","Med Bay","Tool Storage","the escape shuttle","Robotics","a locker room","the living quarters","the gym","the autolathe","QM","the bar","the theater","the derelict")
|
||||
syndicate_code_phrase += "?"
|
||||
if(3)
|
||||
if(prob(70))
|
||||
syndicate_code_phrase += pick("Get me","I want","I'd like","Make me")
|
||||
syndicate_code_phrase += " a "
|
||||
else
|
||||
syndicate_code_phrase += pick("One")
|
||||
syndicate_code_phrase += " "
|
||||
syndicate_code_phrase += pick("vodka and tonic","gin fizz","bahama mama","manhattan","black Russian","whiskey soda","long island tea","margarita","Irish coffee"," manly dwarf","Irish cream","doctor's delight","Beepksy Smash","tequila sunrise","brave bull","gargle blaster","bloody mary","whiskey cola","white Russian","vodka martini","martini","Cuba libre","kahlua","vodka","wine","moonshine")
|
||||
syndicate_code_phrase += "."
|
||||
if(4)
|
||||
syndicate_code_phrase += pick("I wish I was","My dad was","His mom was","Where do I find","The hero this station needs is","I'd fuck","I wouldn't trust","Someone caught","HoS caught","Someone found","I'd wrestle","I wanna kill")
|
||||
syndicate_code_phrase += " [pick("a","the")] "
|
||||
syndicate_code_phrase += pick("wizard","ninja","xeno","lizard","slime","monkey","syndicate","cyborg","clown","space carp","singularity","singulo","mime")
|
||||
syndicate_code_phrase += "."
|
||||
if(5)
|
||||
syndicate_code_phrase += pick("Do we have","Is there","Where is","Where's","Who's")
|
||||
syndicate_code_phrase += " "
|
||||
syndicate_code_phrase += "[pick(get_all_jobs())]"
|
||||
syndicate_code_phrase += "?"
|
||||
|
||||
switch(choice)
|
||||
if(1)
|
||||
if(prob(80))
|
||||
syndicate_code_response += pick("Try looking for them near","I they ran off to","Yes. I saw them near","Nope. I'm heading to","Try searching")
|
||||
syndicate_code_response += " "
|
||||
syndicate_code_response += pick("Escape","Engineering","Atmos","the bridge","the brig","Clown Planet","CentCom","the library","the chapel","a bathroom","Med Bay","Tool Storage","the escape shuttle","Robotics","a locker room","the living quarters","the gym","the autolathe","QM","the bar","the theater","the derelict")
|
||||
syndicate_code_response += "."
|
||||
else if(prob(60))
|
||||
syndicate_code_response += pick("No. I'm busy, sorry.","I don't have the time.","Not sure, maybe?","There is no time.")
|
||||
else
|
||||
syndicate_code_response += pick("*shrug*","*smile*","*blink*","*sigh*","*laugh*","*nod*","*giggle*")
|
||||
if(2)
|
||||
if(prob(80))
|
||||
syndicate_code_response += pick("Go to","Navigate to","Try","Sure, run to","Try searching","It's near","It's around")
|
||||
syndicate_code_response += " the "
|
||||
syndicate_code_response += pick("[pick("south","north","east","west")] maitenance door","nearby maitenance","teleporter","[pick("cold","dead")] space","morgue","vacuum","[pick("south","north","east","west")] hall ","[pick("south","north","east","west")] hallway","[pick("white","black","red","green","blue","pink","purple")] [pick("rabbit","frog","lion","tiger","panther","snake","facehugger")]")
|
||||
syndicate_code_response += "."
|
||||
else if(prob(60))
|
||||
syndicate_code_response += pick("Try asking","Ask","Talk to","Go see","Follow","Hunt down")
|
||||
syndicate_code_response += " "
|
||||
if(prob(50))
|
||||
syndicate_code_response += pick(pick(first_names_male,first_names_female))
|
||||
syndicate_code_response += " "
|
||||
syndicate_code_response += pick(last_names)
|
||||
else
|
||||
syndicate_code_response += " the "
|
||||
syndicate_code_response += "[pic(get_all_jobs())]"
|
||||
syndicate_code_response += "."
|
||||
else
|
||||
syndicate_code_response += pick("*shrug*","*smile*","*blink*","*sigh*","*laugh*","*nod*","*giggle*")
|
||||
if(3)
|
||||
if(4)
|
||||
if(5)
|
||||
|
||||
return
|
||||
*/
|
||||
@@ -1,46 +1,46 @@
|
||||
//general stuff
|
||||
/proc/sanitize_integer(number, min=0, max=1, default=0)
|
||||
if(isnum(number))
|
||||
number = round(number)
|
||||
if(min <= number && number <= max)
|
||||
return number
|
||||
return default
|
||||
|
||||
/proc/sanitize_text(text, default="")
|
||||
if(istext(text))
|
||||
return text
|
||||
return default
|
||||
|
||||
/proc/sanitize_inlist(value, list/List, default)
|
||||
if(value in List) return value
|
||||
if(default) return default
|
||||
if(List && List.len)return List[1]
|
||||
|
||||
|
||||
|
||||
//more specialised stuff
|
||||
/proc/sanitize_gender(gender,neuter=0,plural=0, default="male")
|
||||
switch(gender)
|
||||
if(MALE, FEMALE)return gender
|
||||
if(NEUTER)
|
||||
if(neuter) return gender
|
||||
else return default
|
||||
if(PLURAL)
|
||||
if(plural) return gender
|
||||
else return default
|
||||
return default
|
||||
|
||||
/proc/sanitize_hexcolor(color, default="#000000")
|
||||
if(!istext(color)) return default
|
||||
var/len = length(color)
|
||||
if(len != 7 && len !=4) return default
|
||||
if(text2ascii(color,1) != 35) return default //35 is the ascii code for "#"
|
||||
. = "#"
|
||||
for(var/i=2,i<=len,i++)
|
||||
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
|
||||
else return default
|
||||
return .
|
||||
//general stuff
|
||||
/proc/sanitize_integer(number, min=0, max=1, default=0)
|
||||
if(isnum(number))
|
||||
number = round(number)
|
||||
if(min <= number && number <= max)
|
||||
return number
|
||||
return default
|
||||
|
||||
/proc/sanitize_text(text, default="")
|
||||
if(istext(text))
|
||||
return text
|
||||
return default
|
||||
|
||||
/proc/sanitize_inlist(value, list/List, default)
|
||||
if(value in List) return value
|
||||
if(default) return default
|
||||
if(List && List.len)return List[1]
|
||||
|
||||
|
||||
|
||||
//more specialised stuff
|
||||
/proc/sanitize_gender(gender,neuter=0,plural=0, default="male")
|
||||
switch(gender)
|
||||
if(MALE, FEMALE)return gender
|
||||
if(NEUTER)
|
||||
if(neuter) return gender
|
||||
else return default
|
||||
if(PLURAL)
|
||||
if(plural) return gender
|
||||
else return default
|
||||
return default
|
||||
|
||||
/proc/sanitize_hexcolor(color, default="#000000")
|
||||
if(!istext(color)) return default
|
||||
var/len = length(color)
|
||||
if(len != 7 && len !=4) return default
|
||||
if(text2ascii(color,1) != 35) return default //35 is the ascii code for "#"
|
||||
. = "#"
|
||||
for(var/i=2,i<=len,i++)
|
||||
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
|
||||
else return default
|
||||
return .
|
||||
|
||||
@@ -1,480 +1,480 @@
|
||||
/*
|
||||
* Holds procs designed to help with filtering text
|
||||
* Contains groups:
|
||||
* SQL sanitization
|
||||
* Text sanitization
|
||||
* Text searches
|
||||
* Text modification
|
||||
* Misc
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* SQL sanitization
|
||||
*/
|
||||
|
||||
// Run all strings to be used in an SQL query through this proc first to properly escape out injection attempts.
|
||||
/proc/sanitizeSQL(var/t as text)
|
||||
//var/sanitized_text = replacetext(t, "'", "\\'")
|
||||
//sanitized_text = replacetext(sanitized_text, "\"", "\\\"")
|
||||
|
||||
var/sqltext = dbcon.Quote(t)
|
||||
//testing("sanitizeSQL(): BEFORE copytext(): [sqltext]")
|
||||
sqltext = copytext(sqltext, 2, length(sqltext))//Quote() adds quotes around input, we already do that
|
||||
//testing("sanitizeSQL(): AFTER copytext(): [sqltext]")
|
||||
return sqltext
|
||||
|
||||
/*
|
||||
/mob/verb/SanitizeTest(var/t as text)
|
||||
/*
|
||||
* Holds procs designed to help with filtering text
|
||||
* Contains groups:
|
||||
* SQL sanitization
|
||||
* Text sanitization
|
||||
* Text searches
|
||||
* Text modification
|
||||
* Misc
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* SQL sanitization
|
||||
*/
|
||||
|
||||
// Run all strings to be used in an SQL query through this proc first to properly escape out injection attempts.
|
||||
/proc/sanitizeSQL(var/t as text)
|
||||
//var/sanitized_text = replacetext(t, "'", "\\'")
|
||||
//sanitized_text = replacetext(sanitized_text, "\"", "\\\"")
|
||||
|
||||
var/sqltext = dbcon.Quote(t)
|
||||
//testing("sanitizeSQL(): BEFORE copytext(): [sqltext]")
|
||||
sqltext = copytext(sqltext, 2, length(sqltext))//Quote() adds quotes around input, we already do that
|
||||
//testing("sanitizeSQL(): AFTER copytext(): [sqltext]")
|
||||
return sqltext
|
||||
|
||||
/*
|
||||
/mob/verb/SanitizeTest(var/t as text)
|
||||
to_chat(src, "IN: [t]")
|
||||
to_chat(src, "OUT: [sanitizeSQL(t)]")
|
||||
*/
|
||||
/*
|
||||
* Text sanitization
|
||||
*/
|
||||
|
||||
//Simply removes < and > and limits the length of the message
|
||||
/proc/strip_html_simple(var/t,var/limit=MAX_MESSAGE_LEN)
|
||||
var/list/strip_chars = list("<",">")
|
||||
t = copytext(t,1,limit)
|
||||
for(var/char in strip_chars)
|
||||
var/index = findtext(t, char)
|
||||
while(index)
|
||||
t = copytext(t, 1, index) + copytext(t, index+1)
|
||||
index = findtext(t, char)
|
||||
return t
|
||||
|
||||
/proc/strip_html_properly(input = "")
|
||||
// these store the position of < and > respectively
|
||||
var/opentag = 0
|
||||
var/closetag = 0
|
||||
|
||||
while (input)
|
||||
opentag = rfindtext(input, "<")
|
||||
closetag = findtext(input, ">", opentag + 1)
|
||||
|
||||
if (!opentag || !closetag)
|
||||
break
|
||||
|
||||
input = copytext(input, 1, opentag) + copytext(input, closetag + 1)
|
||||
|
||||
return input
|
||||
|
||||
/proc/rfindtext(Haystack, Needle, Start = 1, End = 0)
|
||||
var/i = findtext(Haystack, Needle, Start, End)
|
||||
|
||||
while (i)
|
||||
. = i
|
||||
i = findtext(Haystack, Needle, i + 1, End)
|
||||
|
||||
//Removes a few problematic characters
|
||||
/proc/sanitize_simple(var/t,var/list/repl_chars = list("\n"="#","\t"="#","<22>"="<22>"))
|
||||
for(var/char in repl_chars)
|
||||
var/index = findtext(t, char)
|
||||
while(index)
|
||||
t = copytext(t, 1, index) + repl_chars[char] + copytext(t, index+1)
|
||||
index = findtext(t, char)
|
||||
return t
|
||||
|
||||
//Runs byond's sanitization proc along-side sanitize_simple
|
||||
/proc/sanitize(var/t,var/list/repl_chars = null)
|
||||
return html_encode(sanitize_simple(t,repl_chars))
|
||||
|
||||
//Runs sanitize and strip_html_simple
|
||||
//I believe strip_html_simple() is required to run first to prevent '<' from displaying as '<' after sanitize() calls byond's html_encode()
|
||||
/proc/strip_html(var/t,var/limit=MAX_MESSAGE_LEN)
|
||||
return copytext((sanitize(strip_html_simple(t))),1,limit)
|
||||
|
||||
//Runs byond's sanitization proc along-side strip_html_simple
|
||||
//I believe strip_html_simple() is required to run first to prevent '<' from displaying as '<' that html_encode() would cause
|
||||
/proc/adminscrub(var/t,var/limit=MAX_MESSAGE_LEN)
|
||||
return copytext((html_encode(strip_html_simple(t))),1,limit)
|
||||
|
||||
/proc/reverse_text(txt)
|
||||
var/i = length(txt)+1
|
||||
. = ""
|
||||
while(--i)
|
||||
. += copytext(txt,i,i+1)
|
||||
|
||||
/*
|
||||
* returns null if there is any bad text in the string
|
||||
*/
|
||||
/proc/reject_bad_text(const/text, var/max_length = 512)
|
||||
var/text_length = length(text)
|
||||
|
||||
if(text_length > max_length)
|
||||
return // message too long
|
||||
|
||||
var/non_whitespace = FALSE
|
||||
|
||||
for(var/i = 1 to text_length)
|
||||
switch(text2ascii(text, i))
|
||||
if(62, 60, 92, 47)
|
||||
return // rejects the text if it contains these bad characters: <, >, \ or /
|
||||
if(127 to 255)
|
||||
return // rejects weird letters like <20>
|
||||
if(0 to 31)
|
||||
return // more weird stuff
|
||||
if(32)
|
||||
continue //whitespace
|
||||
else
|
||||
non_whitespace = TRUE
|
||||
|
||||
if(non_whitespace)
|
||||
return text // only accepts the text if it has some non-spaces
|
||||
|
||||
// Used to get a sanitized input.
|
||||
/proc/stripped_input(var/mob/user, var/message = "", var/title = "", var/default = "", var/max_length=MAX_MESSAGE_LEN)
|
||||
var/name = input(user, message, title, default)
|
||||
return strip_html_simple(name, max_length)
|
||||
|
||||
//Filters out undesirable characters from names
|
||||
/proc/reject_bad_name(var/t_in, var/allow_numbers=0, var/max_length=MAX_NAME_LEN)
|
||||
if(!t_in || length(t_in) > max_length)
|
||||
return //Rejects the input if it is null or if it is longer then the max length allowed
|
||||
|
||||
var/number_of_alphanumeric = 0
|
||||
var/last_char_group = 0
|
||||
var/t_out = ""
|
||||
|
||||
for(var/i=1, i<=length(t_in), i++)
|
||||
var/ascii_char = text2ascii(t_in,i)
|
||||
switch(ascii_char)
|
||||
// A .. Z
|
||||
if(65 to 90) //Uppercase Letters
|
||||
t_out += ascii2text(ascii_char)
|
||||
number_of_alphanumeric++
|
||||
last_char_group = 4
|
||||
|
||||
// a .. z
|
||||
if(97 to 122) //Lowercase Letters
|
||||
if(last_char_group<2) t_out += ascii2text(ascii_char-32) //Force uppercase first character
|
||||
else t_out += ascii2text(ascii_char)
|
||||
number_of_alphanumeric++
|
||||
last_char_group = 4
|
||||
|
||||
// 0 .. 9
|
||||
if(48 to 57) //Numbers
|
||||
if(!last_char_group) continue //suppress at start of string
|
||||
if(!allow_numbers) continue
|
||||
t_out += ascii2text(ascii_char)
|
||||
number_of_alphanumeric++
|
||||
last_char_group = 3
|
||||
|
||||
// ' - .
|
||||
if(39,45,46) //Common name punctuation
|
||||
if(!last_char_group) continue
|
||||
t_out += ascii2text(ascii_char)
|
||||
last_char_group = 2
|
||||
|
||||
// ~ | @ : # $ % & * +
|
||||
if(126,124,64,58,35,36,37,38,42,43) //Other symbols that we'll allow (mainly for AI)
|
||||
if(!last_char_group) continue //suppress at start of string
|
||||
if(!allow_numbers) continue
|
||||
t_out += ascii2text(ascii_char)
|
||||
last_char_group = 2
|
||||
|
||||
//Space
|
||||
if(32)
|
||||
if(last_char_group <= 1) continue //suppress double-spaces and spaces at start of string
|
||||
t_out += ascii2text(ascii_char)
|
||||
last_char_group = 1
|
||||
else
|
||||
return
|
||||
|
||||
if(number_of_alphanumeric < 2) return //protects against tiny names like "A" and also names like "' ' ' ' ' ' ' '"
|
||||
|
||||
if(last_char_group == 1)
|
||||
t_out = copytext(t_out,1,length(t_out)) //removes the last character (in this case a space)
|
||||
|
||||
for(var/bad_name in list("space","floor","wall","r-wall","monkey","unknown","inactive ai","plating")) //prevents these common metagamey names
|
||||
if(cmptext(t_out,bad_name)) return //(not case sensitive)
|
||||
|
||||
return t_out
|
||||
|
||||
//checks text for html tags
|
||||
//if tag is not in whitelist (var/list/paper_tag_whitelist in global.dm)
|
||||
//relpaces < with <
|
||||
proc/checkhtml(var/t)
|
||||
t = sanitize_simple(t, list("&#"="."))
|
||||
var/p = findtext(t,"<",1)
|
||||
while (p) //going through all the tags
|
||||
var/start = p++
|
||||
var/tag = copytext(t,p, p+1)
|
||||
if (tag != "/")
|
||||
while (reject_bad_text(copytext(t, p, p+1), 1))
|
||||
tag = copytext(t,start, p)
|
||||
p++
|
||||
tag = copytext(t,start+1, p)
|
||||
if (!(tag in paper_tag_whitelist)) //if it's unkown tag, disarming it
|
||||
t = copytext(t,1,start-1) + "<" + copytext(t,start+1)
|
||||
p = findtext(t,"<",p)
|
||||
return t
|
||||
/*
|
||||
* Text searches
|
||||
*/
|
||||
|
||||
//Checks the beginning of a string for a specified sub-string
|
||||
//Returns the position of the substring or 0 if it was not found
|
||||
/proc/dd_hasprefix(text, prefix)
|
||||
var/start = 1
|
||||
var/end = length(prefix) + 1
|
||||
return findtext(text, prefix, start, end)
|
||||
|
||||
//Checks the beginning of a string for a specified sub-string. This proc is case sensitive
|
||||
//Returns the position of the substring or 0 if it was not found
|
||||
/proc/dd_hasprefix_case(text, prefix)
|
||||
var/start = 1
|
||||
var/end = length(prefix) + 1
|
||||
return findtextEx(text, prefix, start, end)
|
||||
|
||||
//Checks the end of a string for a specified substring.
|
||||
//Returns the position of the substring or 0 if it was not found
|
||||
/proc/dd_hassuffix(text, suffix)
|
||||
var/start = length(text) - length(suffix)
|
||||
if(start)
|
||||
return findtext(text, suffix, start, null)
|
||||
return
|
||||
|
||||
//Checks the end of a string for a specified substring. This proc is case sensitive
|
||||
//Returns the position of the substring or 0 if it was not found
|
||||
/proc/dd_hassuffix_case(text, suffix)
|
||||
var/start = length(text) - length(suffix)
|
||||
if(start)
|
||||
return findtextEx(text, suffix, start, null)
|
||||
|
||||
/*
|
||||
* Text modification
|
||||
*/
|
||||
/proc/replacetext(text, find, replacement)
|
||||
return list2text(text2list(text, find), replacement)
|
||||
|
||||
/proc/replacetextEx(text, find, replacement)
|
||||
return list2text(text2listEx(text, find), replacement)
|
||||
|
||||
//Adds 'u' number of zeros ahead of the text 't'
|
||||
/proc/add_zero(t, u)
|
||||
while (length(t) < u)
|
||||
t = "0[t]"
|
||||
return t
|
||||
|
||||
//Adds 'u' number of spaces ahead of the text 't'
|
||||
/proc/add_lspace(t, u)
|
||||
while(length(t) < u)
|
||||
t = " [t]"
|
||||
return t
|
||||
|
||||
//Adds 'u' number of spaces behind the text 't'
|
||||
/proc/add_tspace(t, u)
|
||||
while(length(t) < u)
|
||||
t = "[t] "
|
||||
return t
|
||||
|
||||
//Returns a string with reserved characters and spaces before the first letter removed
|
||||
/proc/trim_left(text)
|
||||
for (var/i = 1 to length(text))
|
||||
if (text2ascii(text, i) > 32)
|
||||
return copytext(text, i)
|
||||
return ""
|
||||
|
||||
//Returns a string with reserved characters and spaces after the last letter removed
|
||||
/proc/trim_right(text)
|
||||
for (var/i = length(text), i > 0, i--)
|
||||
if (text2ascii(text, i) > 32)
|
||||
return copytext(text, 1, i + 1)
|
||||
|
||||
return ""
|
||||
|
||||
//Returns a string with reserved characters and spaces before the first word and after the last word removed.
|
||||
/proc/trim(text)
|
||||
return trim_left(trim_right(text))
|
||||
|
||||
//Returns a string with the first element of the string capitalized.
|
||||
/proc/capitalize(var/t as text)
|
||||
return uppertext(copytext(t, 1, 2)) + copytext(t, 2)
|
||||
|
||||
//Centers text by adding spaces to either side of the string.
|
||||
/proc/dd_centertext(message, length)
|
||||
var/new_message = message
|
||||
var/size = length(message)
|
||||
var/delta = length - size
|
||||
if(size == length)
|
||||
return new_message
|
||||
if(size > length)
|
||||
return copytext(new_message, 1, length + 1)
|
||||
if(delta == 1)
|
||||
return new_message + " "
|
||||
if(delta % 2)
|
||||
new_message = " " + new_message
|
||||
delta--
|
||||
var/spaces = add_lspace("",delta/2-1)
|
||||
return spaces + new_message + spaces
|
||||
|
||||
//Limits the length of the text. Note: MAX_MESSAGE_LEN and MAX_NAME_LEN are widely used for this purpose
|
||||
/proc/dd_limittext(message, length)
|
||||
var/size = length(message)
|
||||
if(size <= length)
|
||||
return message
|
||||
return copytext(message, 1, length + 1)
|
||||
|
||||
/proc/stringmerge(var/text,var/compare,replace = "*")
|
||||
//This proc fills in all spaces with the "replace" var (* by default) with whatever
|
||||
//is in the other string at the same spot (assuming it is not a replace char).
|
||||
//This is used for fingerprints
|
||||
var/newtext = text
|
||||
if(length(text) != length(compare))
|
||||
return 0
|
||||
for(var/i = 1, i < length(text), i++)
|
||||
var/a = copytext(text,i,i+1)
|
||||
var/b = copytext(compare,i,i+1)
|
||||
//if it isn't both the same letter, or if they are both the replacement character
|
||||
//(no way to know what it was supposed to be)
|
||||
if(a != b)
|
||||
if(a == replace) //if A is the replacement char
|
||||
newtext = copytext(newtext,1,i) + b + copytext(newtext, i+1)
|
||||
else if(b == replace) //if B is the replacement char
|
||||
newtext = copytext(newtext,1,i) + a + copytext(newtext, i+1)
|
||||
else //The lists disagree, Uh-oh!
|
||||
return 0
|
||||
return newtext
|
||||
|
||||
/proc/stringpercent(var/text,character = "*")
|
||||
//This proc returns the number of chars of the string that is the character
|
||||
//This is used for detective work to determine fingerprint completion.
|
||||
if(!text || !character)
|
||||
return 0
|
||||
var/count = 0
|
||||
for(var/i = 1, i <= length(text), i++)
|
||||
var/a = copytext(text,i,i+1)
|
||||
if(a == character)
|
||||
count++
|
||||
return count
|
||||
|
||||
/**
|
||||
* Format number with thousands seperators.
|
||||
* @param number Number to format.
|
||||
* @param sep seperator to use
|
||||
*/
|
||||
/proc/format_num(var/number, var/sep=",")
|
||||
var/c="" // Current char
|
||||
var/list/parts = text2list("[number]",".")
|
||||
var/origtext = "[parts[1]]"
|
||||
var/len = length(origtext)
|
||||
var/offset = len % 3
|
||||
for(var/i=1;i<=len;i++)
|
||||
c = copytext(origtext,i,i+1)
|
||||
. += c
|
||||
if((i%3)==offset && i!=len)
|
||||
. += sep
|
||||
if(parts.len==2)
|
||||
. += ".[parts[2]]"
|
||||
|
||||
var/global/list/watt_suffixes = list("W", "KW", "MW", "GW", "TW", "PW", "EW", "ZW", "YW")
|
||||
/proc/format_watts(var/number)
|
||||
if(number<0) return "-[format_watts(number)]"
|
||||
if(number==0) return "0 W"
|
||||
|
||||
var/i=1
|
||||
while (round(number/1000) >= 1)
|
||||
number/=1000
|
||||
i++
|
||||
return "[format_num(number)] [watt_suffixes[i]]"
|
||||
|
||||
|
||||
// Custom algorithm since stackoverflow is full of complete garbage and even the MS algorithm sucks.
|
||||
// Uses recursion, in places.
|
||||
// (c)2015 Rob "N3X15" Nelson <nexisentertainment@gmail.com>
|
||||
// Available under the MIT license.
|
||||
|
||||
var/list/number_digits=list(
|
||||
"one",
|
||||
"two",
|
||||
"three",
|
||||
"four",
|
||||
"five",
|
||||
"six",
|
||||
"seven",
|
||||
"eight",
|
||||
"nine",
|
||||
"ten",
|
||||
"eleven",
|
||||
"twelve",
|
||||
"thirteen",
|
||||
"fourteen",
|
||||
"fifteen",
|
||||
"sixteen",
|
||||
"seventeen",
|
||||
"eighteen",
|
||||
"nineteen",
|
||||
)
|
||||
|
||||
var/list/number_tens=list(
|
||||
null, // 0 :V
|
||||
null, // teens, special case
|
||||
"twenty",
|
||||
"thirty",
|
||||
"forty",
|
||||
"fifty",
|
||||
"sixty",
|
||||
"seventy",
|
||||
"eighty",
|
||||
"ninety"
|
||||
)
|
||||
|
||||
var/list/number_units=list(
|
||||
null, // Don't yell units
|
||||
"thousand",
|
||||
"million",
|
||||
"billion"
|
||||
)
|
||||
|
||||
/proc/num2words(var/number, var/zero="zero", var/minus="minus", var/hundred="hundred", var/list/digits=number_digits, var/list/tens=number_tens, var/list/units=number_units, var/recursion=0)
|
||||
if(!isnum(number))
|
||||
warning("num2words fed a non-number: [number]")
|
||||
return list()
|
||||
number=round(number)
|
||||
//testing("num2words [recursion] ([number])")
|
||||
if(number == 0)
|
||||
return list(zero)
|
||||
|
||||
if(number < 0)
|
||||
return list(minus) + num2words(abs(number), zero, minus, hundred, digits, tens, units, recursion+1)
|
||||
|
||||
var/list/out=list()
|
||||
if(number < 1000)
|
||||
var/hundreds = round(number/100)
|
||||
//testing(" ([recursion]) hundreds=[hundreds]")
|
||||
if(hundreds)
|
||||
out += num2words(hundreds, zero, minus, hundred, digits, tens, units, recursion+1) + list(hundred)
|
||||
number %= 100
|
||||
|
||||
if(number < 100)
|
||||
// Teens
|
||||
if(number <= 19)
|
||||
out.Add(digits[number])
|
||||
else
|
||||
var/tens_place = tens[round(number/10)+1]
|
||||
//testing(" ([recursion]) tens_place=[round(number/10)+1] = [tens_place]")
|
||||
if(tens_place!=null)
|
||||
out.Add(tens_place)
|
||||
number = number%10
|
||||
//testing(" ([recursion]) number%10+1 = [number+1] = [digits[number+1]]")
|
||||
if(number>0)
|
||||
out.Add(digits[number])
|
||||
else
|
||||
var/i=1
|
||||
while(round(number) > 0)
|
||||
var/unit_number = number%1000
|
||||
//testing(" ([recursion]) [number]%1000 = [unit_number] ([i])")
|
||||
if(unit_number > 0)
|
||||
if(units[i])
|
||||
//testing(" ([recursion]) units = [units[i]]")
|
||||
out = list(units[i]) + out
|
||||
out = num2words(unit_number, zero, minus, hundred, digits, tens, units, recursion+1) + out
|
||||
number /= 1000
|
||||
i++
|
||||
//testing(" ([recursion]) out=list("+list2text(out,", ")+")")
|
||||
return out
|
||||
|
||||
///mob/verb/test_num2words(var/number as num)
|
||||
*/
|
||||
/*
|
||||
* Text sanitization
|
||||
*/
|
||||
|
||||
//Simply removes < and > and limits the length of the message
|
||||
/proc/strip_html_simple(var/t,var/limit=MAX_MESSAGE_LEN)
|
||||
var/list/strip_chars = list("<",">")
|
||||
t = copytext(t,1,limit)
|
||||
for(var/char in strip_chars)
|
||||
var/index = findtext(t, char)
|
||||
while(index)
|
||||
t = copytext(t, 1, index) + copytext(t, index+1)
|
||||
index = findtext(t, char)
|
||||
return t
|
||||
|
||||
/proc/strip_html_properly(input = "")
|
||||
// these store the position of < and > respectively
|
||||
var/opentag = 0
|
||||
var/closetag = 0
|
||||
|
||||
while (input)
|
||||
opentag = rfindtext(input, "<")
|
||||
closetag = findtext(input, ">", opentag + 1)
|
||||
|
||||
if (!opentag || !closetag)
|
||||
break
|
||||
|
||||
input = copytext(input, 1, opentag) + copytext(input, closetag + 1)
|
||||
|
||||
return input
|
||||
|
||||
/proc/rfindtext(Haystack, Needle, Start = 1, End = 0)
|
||||
var/i = findtext(Haystack, Needle, Start, End)
|
||||
|
||||
while (i)
|
||||
. = i
|
||||
i = findtext(Haystack, Needle, i + 1, End)
|
||||
|
||||
//Removes a few problematic characters
|
||||
/proc/sanitize_simple(var/t,var/list/repl_chars = list("\n"="#","\t"="#","<22>"="<22>"))
|
||||
for(var/char in repl_chars)
|
||||
var/index = findtext(t, char)
|
||||
while(index)
|
||||
t = copytext(t, 1, index) + repl_chars[char] + copytext(t, index+1)
|
||||
index = findtext(t, char)
|
||||
return t
|
||||
|
||||
//Runs byond's sanitization proc along-side sanitize_simple
|
||||
/proc/sanitize(var/t,var/list/repl_chars = null)
|
||||
return html_encode(sanitize_simple(t,repl_chars))
|
||||
|
||||
//Runs sanitize and strip_html_simple
|
||||
//I believe strip_html_simple() is required to run first to prevent '<' from displaying as '<' after sanitize() calls byond's html_encode()
|
||||
/proc/strip_html(var/t,var/limit=MAX_MESSAGE_LEN)
|
||||
return copytext((sanitize(strip_html_simple(t))),1,limit)
|
||||
|
||||
//Runs byond's sanitization proc along-side strip_html_simple
|
||||
//I believe strip_html_simple() is required to run first to prevent '<' from displaying as '<' that html_encode() would cause
|
||||
/proc/adminscrub(var/t,var/limit=MAX_MESSAGE_LEN)
|
||||
return copytext((html_encode(strip_html_simple(t))),1,limit)
|
||||
|
||||
/proc/reverse_text(txt)
|
||||
var/i = length(txt)+1
|
||||
. = ""
|
||||
while(--i)
|
||||
. += copytext(txt,i,i+1)
|
||||
|
||||
/*
|
||||
* returns null if there is any bad text in the string
|
||||
*/
|
||||
/proc/reject_bad_text(const/text, var/max_length = 512)
|
||||
var/text_length = length(text)
|
||||
|
||||
if(text_length > max_length)
|
||||
return // message too long
|
||||
|
||||
var/non_whitespace = FALSE
|
||||
|
||||
for(var/i = 1 to text_length)
|
||||
switch(text2ascii(text, i))
|
||||
if(62, 60, 92, 47)
|
||||
return // rejects the text if it contains these bad characters: <, >, \ or /
|
||||
if(127 to 255)
|
||||
return // rejects weird letters like <20>
|
||||
if(0 to 31)
|
||||
return // more weird stuff
|
||||
if(32)
|
||||
continue //whitespace
|
||||
else
|
||||
non_whitespace = TRUE
|
||||
|
||||
if(non_whitespace)
|
||||
return text // only accepts the text if it has some non-spaces
|
||||
|
||||
// Used to get a sanitized input.
|
||||
/proc/stripped_input(var/mob/user, var/message = "", var/title = "", var/default = "", var/max_length=MAX_MESSAGE_LEN)
|
||||
var/name = input(user, message, title, default)
|
||||
return strip_html_simple(name, max_length)
|
||||
|
||||
//Filters out undesirable characters from names
|
||||
/proc/reject_bad_name(var/t_in, var/allow_numbers=0, var/max_length=MAX_NAME_LEN)
|
||||
if(!t_in || length(t_in) > max_length)
|
||||
return //Rejects the input if it is null or if it is longer then the max length allowed
|
||||
|
||||
var/number_of_alphanumeric = 0
|
||||
var/last_char_group = 0
|
||||
var/t_out = ""
|
||||
|
||||
for(var/i=1, i<=length(t_in), i++)
|
||||
var/ascii_char = text2ascii(t_in,i)
|
||||
switch(ascii_char)
|
||||
// A .. Z
|
||||
if(65 to 90) //Uppercase Letters
|
||||
t_out += ascii2text(ascii_char)
|
||||
number_of_alphanumeric++
|
||||
last_char_group = 4
|
||||
|
||||
// a .. z
|
||||
if(97 to 122) //Lowercase Letters
|
||||
if(last_char_group<2) t_out += ascii2text(ascii_char-32) //Force uppercase first character
|
||||
else t_out += ascii2text(ascii_char)
|
||||
number_of_alphanumeric++
|
||||
last_char_group = 4
|
||||
|
||||
// 0 .. 9
|
||||
if(48 to 57) //Numbers
|
||||
if(!last_char_group) continue //suppress at start of string
|
||||
if(!allow_numbers) continue
|
||||
t_out += ascii2text(ascii_char)
|
||||
number_of_alphanumeric++
|
||||
last_char_group = 3
|
||||
|
||||
// ' - .
|
||||
if(39,45,46) //Common name punctuation
|
||||
if(!last_char_group) continue
|
||||
t_out += ascii2text(ascii_char)
|
||||
last_char_group = 2
|
||||
|
||||
// ~ | @ : # $ % & * +
|
||||
if(126,124,64,58,35,36,37,38,42,43) //Other symbols that we'll allow (mainly for AI)
|
||||
if(!last_char_group) continue //suppress at start of string
|
||||
if(!allow_numbers) continue
|
||||
t_out += ascii2text(ascii_char)
|
||||
last_char_group = 2
|
||||
|
||||
//Space
|
||||
if(32)
|
||||
if(last_char_group <= 1) continue //suppress double-spaces and spaces at start of string
|
||||
t_out += ascii2text(ascii_char)
|
||||
last_char_group = 1
|
||||
else
|
||||
return
|
||||
|
||||
if(number_of_alphanumeric < 2) return //protects against tiny names like "A" and also names like "' ' ' ' ' ' ' '"
|
||||
|
||||
if(last_char_group == 1)
|
||||
t_out = copytext(t_out,1,length(t_out)) //removes the last character (in this case a space)
|
||||
|
||||
for(var/bad_name in list("space","floor","wall","r-wall","monkey","unknown","inactive ai","plating")) //prevents these common metagamey names
|
||||
if(cmptext(t_out,bad_name)) return //(not case sensitive)
|
||||
|
||||
return t_out
|
||||
|
||||
//checks text for html tags
|
||||
//if tag is not in whitelist (var/list/paper_tag_whitelist in global.dm)
|
||||
//relpaces < with <
|
||||
proc/checkhtml(var/t)
|
||||
t = sanitize_simple(t, list("&#"="."))
|
||||
var/p = findtext(t,"<",1)
|
||||
while (p) //going through all the tags
|
||||
var/start = p++
|
||||
var/tag = copytext(t,p, p+1)
|
||||
if (tag != "/")
|
||||
while (reject_bad_text(copytext(t, p, p+1), 1))
|
||||
tag = copytext(t,start, p)
|
||||
p++
|
||||
tag = copytext(t,start+1, p)
|
||||
if (!(tag in paper_tag_whitelist)) //if it's unkown tag, disarming it
|
||||
t = copytext(t,1,start-1) + "<" + copytext(t,start+1)
|
||||
p = findtext(t,"<",p)
|
||||
return t
|
||||
/*
|
||||
* Text searches
|
||||
*/
|
||||
|
||||
//Checks the beginning of a string for a specified sub-string
|
||||
//Returns the position of the substring or 0 if it was not found
|
||||
/proc/dd_hasprefix(text, prefix)
|
||||
var/start = 1
|
||||
var/end = length(prefix) + 1
|
||||
return findtext(text, prefix, start, end)
|
||||
|
||||
//Checks the beginning of a string for a specified sub-string. This proc is case sensitive
|
||||
//Returns the position of the substring or 0 if it was not found
|
||||
/proc/dd_hasprefix_case(text, prefix)
|
||||
var/start = 1
|
||||
var/end = length(prefix) + 1
|
||||
return findtextEx(text, prefix, start, end)
|
||||
|
||||
//Checks the end of a string for a specified substring.
|
||||
//Returns the position of the substring or 0 if it was not found
|
||||
/proc/dd_hassuffix(text, suffix)
|
||||
var/start = length(text) - length(suffix)
|
||||
if(start)
|
||||
return findtext(text, suffix, start, null)
|
||||
return
|
||||
|
||||
//Checks the end of a string for a specified substring. This proc is case sensitive
|
||||
//Returns the position of the substring or 0 if it was not found
|
||||
/proc/dd_hassuffix_case(text, suffix)
|
||||
var/start = length(text) - length(suffix)
|
||||
if(start)
|
||||
return findtextEx(text, suffix, start, null)
|
||||
|
||||
/*
|
||||
* Text modification
|
||||
*/
|
||||
/proc/replacetext(text, find, replacement)
|
||||
return list2text(text2list(text, find), replacement)
|
||||
|
||||
/proc/replacetextEx(text, find, replacement)
|
||||
return list2text(text2listEx(text, find), replacement)
|
||||
|
||||
//Adds 'u' number of zeros ahead of the text 't'
|
||||
/proc/add_zero(t, u)
|
||||
while (length(t) < u)
|
||||
t = "0[t]"
|
||||
return t
|
||||
|
||||
//Adds 'u' number of spaces ahead of the text 't'
|
||||
/proc/add_lspace(t, u)
|
||||
while(length(t) < u)
|
||||
t = " [t]"
|
||||
return t
|
||||
|
||||
//Adds 'u' number of spaces behind the text 't'
|
||||
/proc/add_tspace(t, u)
|
||||
while(length(t) < u)
|
||||
t = "[t] "
|
||||
return t
|
||||
|
||||
//Returns a string with reserved characters and spaces before the first letter removed
|
||||
/proc/trim_left(text)
|
||||
for (var/i = 1 to length(text))
|
||||
if (text2ascii(text, i) > 32)
|
||||
return copytext(text, i)
|
||||
return ""
|
||||
|
||||
//Returns a string with reserved characters and spaces after the last letter removed
|
||||
/proc/trim_right(text)
|
||||
for (var/i = length(text), i > 0, i--)
|
||||
if (text2ascii(text, i) > 32)
|
||||
return copytext(text, 1, i + 1)
|
||||
|
||||
return ""
|
||||
|
||||
//Returns a string with reserved characters and spaces before the first word and after the last word removed.
|
||||
/proc/trim(text)
|
||||
return trim_left(trim_right(text))
|
||||
|
||||
//Returns a string with the first element of the string capitalized.
|
||||
/proc/capitalize(var/t as text)
|
||||
return uppertext(copytext(t, 1, 2)) + copytext(t, 2)
|
||||
|
||||
//Centers text by adding spaces to either side of the string.
|
||||
/proc/dd_centertext(message, length)
|
||||
var/new_message = message
|
||||
var/size = length(message)
|
||||
var/delta = length - size
|
||||
if(size == length)
|
||||
return new_message
|
||||
if(size > length)
|
||||
return copytext(new_message, 1, length + 1)
|
||||
if(delta == 1)
|
||||
return new_message + " "
|
||||
if(delta % 2)
|
||||
new_message = " " + new_message
|
||||
delta--
|
||||
var/spaces = add_lspace("",delta/2-1)
|
||||
return spaces + new_message + spaces
|
||||
|
||||
//Limits the length of the text. Note: MAX_MESSAGE_LEN and MAX_NAME_LEN are widely used for this purpose
|
||||
/proc/dd_limittext(message, length)
|
||||
var/size = length(message)
|
||||
if(size <= length)
|
||||
return message
|
||||
return copytext(message, 1, length + 1)
|
||||
|
||||
/proc/stringmerge(var/text,var/compare,replace = "*")
|
||||
//This proc fills in all spaces with the "replace" var (* by default) with whatever
|
||||
//is in the other string at the same spot (assuming it is not a replace char).
|
||||
//This is used for fingerprints
|
||||
var/newtext = text
|
||||
if(length(text) != length(compare))
|
||||
return 0
|
||||
for(var/i = 1, i < length(text), i++)
|
||||
var/a = copytext(text,i,i+1)
|
||||
var/b = copytext(compare,i,i+1)
|
||||
//if it isn't both the same letter, or if they are both the replacement character
|
||||
//(no way to know what it was supposed to be)
|
||||
if(a != b)
|
||||
if(a == replace) //if A is the replacement char
|
||||
newtext = copytext(newtext,1,i) + b + copytext(newtext, i+1)
|
||||
else if(b == replace) //if B is the replacement char
|
||||
newtext = copytext(newtext,1,i) + a + copytext(newtext, i+1)
|
||||
else //The lists disagree, Uh-oh!
|
||||
return 0
|
||||
return newtext
|
||||
|
||||
/proc/stringpercent(var/text,character = "*")
|
||||
//This proc returns the number of chars of the string that is the character
|
||||
//This is used for detective work to determine fingerprint completion.
|
||||
if(!text || !character)
|
||||
return 0
|
||||
var/count = 0
|
||||
for(var/i = 1, i <= length(text), i++)
|
||||
var/a = copytext(text,i,i+1)
|
||||
if(a == character)
|
||||
count++
|
||||
return count
|
||||
|
||||
/**
|
||||
* Format number with thousands seperators.
|
||||
* @param number Number to format.
|
||||
* @param sep seperator to use
|
||||
*/
|
||||
/proc/format_num(var/number, var/sep=",")
|
||||
var/c="" // Current char
|
||||
var/list/parts = text2list("[number]",".")
|
||||
var/origtext = "[parts[1]]"
|
||||
var/len = length(origtext)
|
||||
var/offset = len % 3
|
||||
for(var/i=1;i<=len;i++)
|
||||
c = copytext(origtext,i,i+1)
|
||||
. += c
|
||||
if((i%3)==offset && i!=len)
|
||||
. += sep
|
||||
if(parts.len==2)
|
||||
. += ".[parts[2]]"
|
||||
|
||||
var/global/list/watt_suffixes = list("W", "KW", "MW", "GW", "TW", "PW", "EW", "ZW", "YW")
|
||||
/proc/format_watts(var/number)
|
||||
if(number<0) return "-[format_watts(number)]"
|
||||
if(number==0) return "0 W"
|
||||
|
||||
var/i=1
|
||||
while (round(number/1000) >= 1)
|
||||
number/=1000
|
||||
i++
|
||||
return "[format_num(number)] [watt_suffixes[i]]"
|
||||
|
||||
|
||||
// Custom algorithm since stackoverflow is full of complete garbage and even the MS algorithm sucks.
|
||||
// Uses recursion, in places.
|
||||
// (c)2015 Rob "N3X15" Nelson <nexisentertainment@gmail.com>
|
||||
// Available under the MIT license.
|
||||
|
||||
var/list/number_digits=list(
|
||||
"one",
|
||||
"two",
|
||||
"three",
|
||||
"four",
|
||||
"five",
|
||||
"six",
|
||||
"seven",
|
||||
"eight",
|
||||
"nine",
|
||||
"ten",
|
||||
"eleven",
|
||||
"twelve",
|
||||
"thirteen",
|
||||
"fourteen",
|
||||
"fifteen",
|
||||
"sixteen",
|
||||
"seventeen",
|
||||
"eighteen",
|
||||
"nineteen",
|
||||
)
|
||||
|
||||
var/list/number_tens=list(
|
||||
null, // 0 :V
|
||||
null, // teens, special case
|
||||
"twenty",
|
||||
"thirty",
|
||||
"forty",
|
||||
"fifty",
|
||||
"sixty",
|
||||
"seventy",
|
||||
"eighty",
|
||||
"ninety"
|
||||
)
|
||||
|
||||
var/list/number_units=list(
|
||||
null, // Don't yell units
|
||||
"thousand",
|
||||
"million",
|
||||
"billion"
|
||||
)
|
||||
|
||||
/proc/num2words(var/number, var/zero="zero", var/minus="minus", var/hundred="hundred", var/list/digits=number_digits, var/list/tens=number_tens, var/list/units=number_units, var/recursion=0)
|
||||
if(!isnum(number))
|
||||
warning("num2words fed a non-number: [number]")
|
||||
return list()
|
||||
number=round(number)
|
||||
//testing("num2words [recursion] ([number])")
|
||||
if(number == 0)
|
||||
return list(zero)
|
||||
|
||||
if(number < 0)
|
||||
return list(minus) + num2words(abs(number), zero, minus, hundred, digits, tens, units, recursion+1)
|
||||
|
||||
var/list/out=list()
|
||||
if(number < 1000)
|
||||
var/hundreds = round(number/100)
|
||||
//testing(" ([recursion]) hundreds=[hundreds]")
|
||||
if(hundreds)
|
||||
out += num2words(hundreds, zero, minus, hundred, digits, tens, units, recursion+1) + list(hundred)
|
||||
number %= 100
|
||||
|
||||
if(number < 100)
|
||||
// Teens
|
||||
if(number <= 19)
|
||||
out.Add(digits[number])
|
||||
else
|
||||
var/tens_place = tens[round(number/10)+1]
|
||||
//testing(" ([recursion]) tens_place=[round(number/10)+1] = [tens_place]")
|
||||
if(tens_place!=null)
|
||||
out.Add(tens_place)
|
||||
number = number%10
|
||||
//testing(" ([recursion]) number%10+1 = [number+1] = [digits[number+1]]")
|
||||
if(number>0)
|
||||
out.Add(digits[number])
|
||||
else
|
||||
var/i=1
|
||||
while(round(number) > 0)
|
||||
var/unit_number = number%1000
|
||||
//testing(" ([recursion]) [number]%1000 = [unit_number] ([i])")
|
||||
if(unit_number > 0)
|
||||
if(units[i])
|
||||
//testing(" ([recursion]) units = [units[i]]")
|
||||
out = list(units[i]) + out
|
||||
out = num2words(unit_number, zero, minus, hundred, digits, tens, units, recursion+1) + out
|
||||
number /= 1000
|
||||
i++
|
||||
//testing(" ([recursion]) out=list("+list2text(out,", ")+")")
|
||||
return out
|
||||
|
||||
///mob/verb/test_num2words(var/number as num)
|
||||
// to_chat(usr, "\"[list2text(num2words(number), " ")]\"")
|
||||
|
||||
@@ -1,73 +1,73 @@
|
||||
// So you can be all 10 SECONDS
|
||||
#define SECONDS * 10
|
||||
#define MINUTES * 600
|
||||
#define HOURS * 36000
|
||||
|
||||
//Returns the world time in english
|
||||
/proc/worldtime2text(timestamp = world.time)
|
||||
return "[(round(timestamp / 36000) + 12) % 24]:[(timestamp / 600 % 60) < 10 ? add_zero(timestamp / 600 % 60, 1) : timestamp / 600 % 60]"
|
||||
|
||||
|
||||
/proc/formatTimeDuration(var/deciseconds)
|
||||
var/m = round(deciseconds / 600)
|
||||
var/s = (deciseconds % 600)/10
|
||||
var/h = round(m / 60)
|
||||
m = m % 60
|
||||
if(h>0)
|
||||
. += "[h]:"
|
||||
if(h>0 || m > 0)
|
||||
. += "[(m<10)?"0":""][m]:"
|
||||
. += "[(s<10)?"0":""][s]"
|
||||
|
||||
/proc/altFormatTimeDuration(var/deciseconds)
|
||||
var/m = round(deciseconds / 600)
|
||||
var/s = (deciseconds % 600)/10
|
||||
var/h = round(m / 60)
|
||||
m = m % 60
|
||||
if(h > 0)
|
||||
. += "[h]h "
|
||||
if(m > 0)
|
||||
. += "[m]m "
|
||||
. += "[s]s"
|
||||
|
||||
/proc/time_stamp()
|
||||
return time2text(world.timeofday, "hh:mm:ss")
|
||||
|
||||
/* Preserving this so future generations can see how fucking retarded some people are
|
||||
/proc/time_stamp()
|
||||
var/hh = text2num(time2text(world.timeofday, "hh")) // Set the hour
|
||||
var/mm = text2num(time2text(world.timeofday, "mm")) // Set the minute
|
||||
var/ss = text2num(time2text(world.timeofday, "ss")) // Set the second
|
||||
var/ph
|
||||
var/pm
|
||||
var/ps
|
||||
if(hh < 10) ph = "0"
|
||||
if(mm < 10) pm = "0"
|
||||
if(ss < 10) ps = "0"
|
||||
return"[ph][hh]:[pm][mm]:[ps][ss]"
|
||||
*/
|
||||
|
||||
/* Returns 1 if it is the selected month and day */
|
||||
/proc/isDay(var/month, var/day)
|
||||
if(isnum(month) && isnum(day))
|
||||
var/MM = text2num(time2text(world.timeofday, "MM")) // get the current month
|
||||
var/DD = text2num(time2text(world.timeofday, "DD")) // get the current day
|
||||
if(month == MM && day == DD)
|
||||
return 1
|
||||
|
||||
// Uncomment this out when debugging!
|
||||
//else
|
||||
//return 1
|
||||
|
||||
/**
|
||||
* Returns "watch handle" (really just a timestamp :V)
|
||||
*/
|
||||
/proc/start_watch()
|
||||
return world.timeofday
|
||||
|
||||
/**
|
||||
* Returns number of seconds elapsed.
|
||||
* @param wh number The "Watch Handle" from start_watch(). (timestamp)
|
||||
*/
|
||||
/proc/stop_watch(wh)
|
||||
// So you can be all 10 SECONDS
|
||||
#define SECONDS * 10
|
||||
#define MINUTES * 600
|
||||
#define HOURS * 36000
|
||||
|
||||
//Returns the world time in english
|
||||
/proc/worldtime2text(timestamp = world.time)
|
||||
return "[(round(timestamp / 36000) + 12) % 24]:[(timestamp / 600 % 60) < 10 ? add_zero(timestamp / 600 % 60, 1) : timestamp / 600 % 60]"
|
||||
|
||||
|
||||
/proc/formatTimeDuration(var/deciseconds)
|
||||
var/m = round(deciseconds / 600)
|
||||
var/s = (deciseconds % 600)/10
|
||||
var/h = round(m / 60)
|
||||
m = m % 60
|
||||
if(h>0)
|
||||
. += "[h]:"
|
||||
if(h>0 || m > 0)
|
||||
. += "[(m<10)?"0":""][m]:"
|
||||
. += "[(s<10)?"0":""][s]"
|
||||
|
||||
/proc/altFormatTimeDuration(var/deciseconds)
|
||||
var/m = round(deciseconds / 600)
|
||||
var/s = (deciseconds % 600)/10
|
||||
var/h = round(m / 60)
|
||||
m = m % 60
|
||||
if(h > 0)
|
||||
. += "[h]h "
|
||||
if(m > 0)
|
||||
. += "[m]m "
|
||||
. += "[s]s"
|
||||
|
||||
/proc/time_stamp()
|
||||
return time2text(world.timeofday, "hh:mm:ss")
|
||||
|
||||
/* Preserving this so future generations can see how fucking retarded some people are
|
||||
/proc/time_stamp()
|
||||
var/hh = text2num(time2text(world.timeofday, "hh")) // Set the hour
|
||||
var/mm = text2num(time2text(world.timeofday, "mm")) // Set the minute
|
||||
var/ss = text2num(time2text(world.timeofday, "ss")) // Set the second
|
||||
var/ph
|
||||
var/pm
|
||||
var/ps
|
||||
if(hh < 10) ph = "0"
|
||||
if(mm < 10) pm = "0"
|
||||
if(ss < 10) ps = "0"
|
||||
return"[ph][hh]:[pm][mm]:[ps][ss]"
|
||||
*/
|
||||
|
||||
/* Returns 1 if it is the selected month and day */
|
||||
/proc/isDay(var/month, var/day)
|
||||
if(isnum(month) && isnum(day))
|
||||
var/MM = text2num(time2text(world.timeofday, "MM")) // get the current month
|
||||
var/DD = text2num(time2text(world.timeofday, "DD")) // get the current day
|
||||
if(month == MM && day == DD)
|
||||
return 1
|
||||
|
||||
// Uncomment this out when debugging!
|
||||
//else
|
||||
//return 1
|
||||
|
||||
/**
|
||||
* Returns "watch handle" (really just a timestamp :V)
|
||||
*/
|
||||
/proc/start_watch()
|
||||
return world.timeofday
|
||||
|
||||
/**
|
||||
* Returns number of seconds elapsed.
|
||||
* @param wh number The "Watch Handle" from start_watch(). (timestamp)
|
||||
*/
|
||||
/proc/stop_watch(wh)
|
||||
return round(0.1*(world.timeofday-wh),0.1)
|
||||
Reference in New Issue
Block a user