This commit is contained in:
LetterJay
2017-09-30 23:26:58 -05:00
137 changed files with 5809 additions and 2605 deletions
+10
View File
@@ -0,0 +1,10 @@
//config files
#define CONFIG_DEF(X) /datum/config_entry/##X { resident_file = CURRENT_RESIDENT_FILE }; /datum/config_entry/##X
#define CONFIG_GET(X) global.config.Get(/datum/config_entry/##X)
#define CONFIG_SET(X, Y) global.config.Set(/datum/config_entry/##X, ##Y)
#define CONFIG_MAPS_FILE "maps.txt"
//flags
#define CONFIG_ENTRY_LOCKED 1 //can't edit
#define CONFIG_ENTRY_HIDDEN 2 //can't see value
+21 -17
View File
@@ -26,74 +26,74 @@
/proc/log_admin(text)
GLOB.admin_log.Add(text)
if (config.log_admin)
if (CONFIG_GET(flag/log_admin))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]ADMIN: [text]")
//Items using this proc are stripped from public logs - use with caution
/proc/log_admin_private(text)
GLOB.admin_log.Add(text)
if (config.log_admin)
if (CONFIG_GET(flag/log_admin))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]ADMINPRIVATE: [text]")
/proc/log_adminsay(text)
if (config.log_adminchat)
if (CONFIG_GET(flag/log_adminchat))
log_admin_private("ASAY: [text]")
/proc/log_dsay(text)
if (config.log_adminchat)
if (CONFIG_GET(flag/log_adminchat))
log_admin("DSAY: [text]")
/proc/log_game(text)
if (config.log_game)
if (CONFIG_GET(flag/log_game))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]GAME: [text]")
/proc/log_vote(text)
if (config.log_vote)
if (CONFIG_GET(flag/log_vote))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]VOTE: [text]")
/proc/log_access(text)
if (config.log_access)
if (CONFIG_GET(flag/log_access))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]ACCESS: [text]")
/proc/log_say(text)
if (config.log_say)
if (CONFIG_GET(flag/log_say))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]SAY: [text]")
/proc/log_prayer(text)
if (config.log_prayer)
if (CONFIG_GET(flag/log_prayer))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]PRAY: [text]")
/proc/log_law(text)
if (config.log_law)
if (CONFIG_GET(flag/log_law))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]LAW: [text]")
/proc/log_ooc(text)
if (config.log_ooc)
if (CONFIG_GET(flag/log_ooc))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]OOC: [text]")
/proc/log_whisper(text)
if (config.log_whisper)
if (CONFIG_GET(flag/log_whisper))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]WHISPER: [text]")
/proc/log_emote(text)
if (config.log_emote)
if (CONFIG_GET(flag/log_emote))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]EMOTE: [text]")
/proc/log_attack(text)
if (config.log_attack)
if (CONFIG_GET(flag/log_attack))
WRITE_FILE(GLOB.world_attack_log, "\[[time_stamp()]]ATTACK: [text]")
/proc/log_pda(text)
if (config.log_pda)
if (CONFIG_GET(flag/log_pda))
WRITE_FILE(GLOB.world_pda_log, "\[[time_stamp()]]PDA: [text]")
/proc/log_comment(text)
if (config.log_pda)
if (CONFIG_GET(flag/log_pda))
//reusing the PDA option because I really don't think news comments are worth a config option
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]COMMENT: [text]")
/proc/log_chat(text)
if (config.log_pda)
if (CONFIG_GET(flag/log_pda))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]CHAT: [text]")
/proc/log_qdel(text)
@@ -102,6 +102,10 @@
/proc/log_sql(text)
WRITE_FILE(GLOB.sql_error_log, "\[[time_stamp()]]SQL: [text]")
/proc/log_config(text)
WRITE_FILE(GLOB.config_error_log, text)
SEND_TEXT(world.log, text)
//This replaces world.log so it displays both in DD and the file
/proc/log_world(text)
WRITE_FILE(GLOB.world_runtime_log, text)
+3 -2
View File
@@ -314,10 +314,11 @@
// Will return a list of active candidates. It increases the buffer 5 times until it finds a candidate which is active within the buffer.
/proc/get_candidates(be_special_type, afk_bracket = config.inactivity_period, jobbanType)
/proc/get_candidates(be_special_type, afk_bracket = CONFIG_GET(number/inactivity_period), jobbanType)
var/list/candidates = list()
// Keep looping until we find a non-afk candidate within the time bracket (we limit the bracket to 10 minutes (6000))
while(!candidates.len && afk_bracket < config.afk_period)
var/afk_period = CONFIG_GET(number/afk_period)
while(!candidates.len && afk_bracket < afk_period)
for(var/mob/dead/observer/G in GLOB.player_list)
if(G.client != null)
if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD))
+115 -116
View File
@@ -1,116 +1,115 @@
//////////////////////////
/////Initial Building/////
//////////////////////////
/proc/make_datum_references_lists()
//hair
init_sprite_accessory_subtypes(/datum/sprite_accessory/hair, GLOB.hair_styles_list, GLOB.hair_styles_male_list, GLOB.hair_styles_female_list)
//facial hair
init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_hair, GLOB.facial_hair_styles_list, GLOB.facial_hair_styles_male_list, GLOB.facial_hair_styles_female_list)
//underwear
init_sprite_accessory_subtypes(/datum/sprite_accessory/underwear, GLOB.underwear_list, GLOB.underwear_m, GLOB.underwear_f)
//undershirt
init_sprite_accessory_subtypes(/datum/sprite_accessory/undershirt, GLOB.undershirt_list, GLOB.undershirt_m, GLOB.undershirt_f)
//socks
init_sprite_accessory_subtypes(/datum/sprite_accessory/socks, GLOB.socks_list)
//lizard bodyparts (blizzard intensifies)
init_sprite_accessory_subtypes(/datum/sprite_accessory/body_markings, GLOB.body_markings_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/lizard, GLOB.tails_list_lizard)
init_sprite_accessory_subtypes(/datum/sprite_accessory/tails_animated/lizard, GLOB.animated_tails_list_lizard)
init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/human, GLOB.tails_list_human)
init_sprite_accessory_subtypes(/datum/sprite_accessory/tails_animated/human, GLOB.animated_tails_list_human)
init_sprite_accessory_subtypes(/datum/sprite_accessory/snouts, GLOB.snouts_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/horns,GLOB.horns_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/ears, GLOB.ears_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, GLOB.wings_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings_open, GLOB.wings_open_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/frills, GLOB.frills_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/spines, GLOB.spines_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/spines_animated, GLOB.animated_spines_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/legs, GLOB.legs_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, GLOB.r_wings_list,roundstart = TRUE)
//citadel code
//mammal bodyparts (fucking furries)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_body_markings, GLOB.mam_body_markings_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails, GLOB.mam_tails_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_ears, GLOB.mam_ears_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails_animated, GLOB.mam_tails_animated_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/taur, GLOB.taur_list)
//avian bodyparts (i swear this isn't starbound)
// init_sprite_accessory_subtypes(/datum/sprite_accessory/beaks/avian, GLOB.avian_beaks_list)
// init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/avian, GLOB.avian_tails_list)
// init_sprite_accessory_subtypes(/datum/sprite_accessory/avian_wings, GLOB.avian_wings_list)
// init_sprite_accessory_subtypes(/datum/sprite_accessory/avian_open_wings, GLOB.avian_open_wings_list)
//xeno parts (hiss?)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_head, GLOB.xeno_head_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_tail, GLOB.xeno_tail_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_dorsal, GLOB.xeno_dorsal_list)
//genitals
init_sprite_accessory_subtypes(/datum/sprite_accessory/penis, GLOB.cock_shapes_list)
for(var/K in GLOB.cock_shapes_list)
var/datum/sprite_accessory/penis/value = GLOB.cock_shapes_list[K]
GLOB.cock_shapes_icons[K] = value.icon_state
init_sprite_accessory_subtypes(/datum/sprite_accessory/vagina, GLOB.vagina_shapes_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/breasts, GLOB.breasts_shapes_list)
GLOB.breasts_size_list = list("a","b","c","d","e") //We need the list to choose from initialized, but it's no longer a sprite_accessory thing.
//Species
for(var/spath in subtypesof(/datum/species))
var/datum/species/S = new spath()
if(S.roundstart)
GLOB.roundstart_species[S.id] = S.type
GLOB.species_list[S.id] = S.type
//Surgeries
for(var/path in subtypesof(/datum/surgery))
GLOB.surgeries_list += new path()
//Materials
for(var/path in subtypesof(/datum/material))
var/datum/material/D = new path()
GLOB.materials_list[D.id] = D
//Techs
for(var/path in subtypesof(/datum/tech))
var/datum/tech/D = new path()
GLOB.tech_list[D.id] = D
//Emotes
for(var/path in subtypesof(/datum/emote))
var/datum/emote/E = new path()
E.emote_list[E.key] = E
init_subtypes(/datum/crafting_recipe, GLOB.crafting_recipes)
/* // 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, .)
*/
//creates every subtype of prototype (excluding prototype) and adds it to list L.
//if no list/L is provided, one is created.
/proc/init_subtypes(prototype, list/L)
if(!istype(L))
L = list()
for(var/path in subtypesof(prototype))
L += new path()
return L
//returns a list of paths to every subtype of prototype (excluding prototype)
//if no list/L is provided, one is created.
/proc/init_paths(prototype, list/L)
if(!istype(L))
L = list()
for(var/path in subtypesof(prototype))
L+= path
return L
//////////////////////////
/////Initial Building/////
//////////////////////////
/proc/make_datum_references_lists()
//hair
init_sprite_accessory_subtypes(/datum/sprite_accessory/hair, GLOB.hair_styles_list, GLOB.hair_styles_male_list, GLOB.hair_styles_female_list)
//facial hair
init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_hair, GLOB.facial_hair_styles_list, GLOB.facial_hair_styles_male_list, GLOB.facial_hair_styles_female_list)
//underwear
init_sprite_accessory_subtypes(/datum/sprite_accessory/underwear, GLOB.underwear_list, GLOB.underwear_m, GLOB.underwear_f)
//undershirt
init_sprite_accessory_subtypes(/datum/sprite_accessory/undershirt, GLOB.undershirt_list, GLOB.undershirt_m, GLOB.undershirt_f)
//socks
init_sprite_accessory_subtypes(/datum/sprite_accessory/socks, GLOB.socks_list)
//lizard bodyparts (blizzard intensifies)
init_sprite_accessory_subtypes(/datum/sprite_accessory/body_markings, GLOB.body_markings_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/lizard, GLOB.tails_list_lizard)
init_sprite_accessory_subtypes(/datum/sprite_accessory/tails_animated/lizard, GLOB.animated_tails_list_lizard)
init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/human, GLOB.tails_list_human)
init_sprite_accessory_subtypes(/datum/sprite_accessory/tails_animated/human, GLOB.animated_tails_list_human)
init_sprite_accessory_subtypes(/datum/sprite_accessory/snouts, GLOB.snouts_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/horns,GLOB.horns_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/ears, GLOB.ears_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, GLOB.wings_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings_open, GLOB.wings_open_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/frills, GLOB.frills_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/spines, GLOB.spines_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/spines_animated, GLOB.animated_spines_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/legs, GLOB.legs_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, GLOB.r_wings_list,roundstart = TRUE)
//citadel code
//mammal bodyparts (fucking furries)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_body_markings, GLOB.mam_body_markings_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails, GLOB.mam_tails_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_ears, GLOB.mam_ears_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails_animated, GLOB.mam_tails_animated_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/taur, GLOB.taur_list)
//avian bodyparts (i swear this isn't starbound)
// init_sprite_accessory_subtypes(/datum/sprite_accessory/beaks/avian, GLOB.avian_beaks_list)
// init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/avian, GLOB.avian_tails_list)
// init_sprite_accessory_subtypes(/datum/sprite_accessory/avian_wings, GLOB.avian_wings_list)
// init_sprite_accessory_subtypes(/datum/sprite_accessory/avian_open_wings, GLOB.avian_open_wings_list)
//xeno parts (hiss?)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_head, GLOB.xeno_head_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_tail, GLOB.xeno_tail_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_dorsal, GLOB.xeno_dorsal_list)
//genitals
init_sprite_accessory_subtypes(/datum/sprite_accessory/penis, GLOB.cock_shapes_list)
for(var/K in GLOB.cock_shapes_list)
var/datum/sprite_accessory/penis/value = GLOB.cock_shapes_list[K]
GLOB.cock_shapes_icons[K] = value.icon_state
init_sprite_accessory_subtypes(/datum/sprite_accessory/vagina, GLOB.vagina_shapes_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/breasts, GLOB.breasts_shapes_list)
GLOB.breasts_size_list = list("a","b","c","d","e") //We need the list to choose from initialized, but it's no longer a sprite_accessory thing.
//Species
for(var/spath in subtypesof(/datum/species))
var/datum/species/S = new spath()
GLOB.species_list[S.id] = spath
//Surgeries
for(var/path in subtypesof(/datum/surgery))
GLOB.surgeries_list += new path()
//Materials
for(var/path in subtypesof(/datum/material))
var/datum/material/D = new path()
GLOB.materials_list[D.id] = D
//Techs
for(var/path in subtypesof(/datum/tech))
var/datum/tech/D = new path()
GLOB.tech_list[D.id] = D
//Emotes
for(var/path in subtypesof(/datum/emote))
var/datum/emote/E = new path()
E.emote_list[E.key] = E
init_subtypes(/datum/crafting_recipe, GLOB.crafting_recipes)
/* // 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, .)
*/
//creates every subtype of prototype (excluding prototype) and adds it to list L.
//if no list/L is provided, one is created.
/proc/init_subtypes(prototype, list/L)
if(!istype(L))
L = list()
for(var/path in subtypesof(prototype))
L += new path()
return L
//returns a list of paths to every subtype of prototype (excluding prototype)
//if no list/L is provided, one is created.
/proc/init_paths(prototype, list/L)
if(!istype(L))
L = list()
for(var/path in subtypesof(prototype))
L+= path
return L
-1
View File
@@ -220,7 +220,6 @@ GLOBAL_LIST_INIT(skin_tones, list(
))
GLOBAL_LIST_EMPTY(species_list)
GLOBAL_LIST_EMPTY(roundstart_species)
/proc/age2agedescription(age)
switch(age)
+248 -246
View File
@@ -1,246 +1,248 @@
#define ION_FILE "ion_laws.json"
/proc/lizard_name(gender)
if(gender == MALE)
return "[pick(GLOB.lizard_names_male)]-[pick(GLOB.lizard_names_male)]"
else
return "[pick(GLOB.lizard_names_female)]-[pick(GLOB.lizard_names_female)]"
/proc/plasmaman_name()
return "[pick(GLOB.plasmaman_names)] \Roman[rand(1,99)]"
/proc/church_name()
var/static/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")
name += " of [religion_name()]"
return name
GLOBAL_VAR(command_name)
/proc/command_name()
if (GLOB.command_name)
return GLOB.command_name
var/name = "Central Command"
GLOB.command_name = name
return name
/proc/change_command_name(name)
GLOB.command_name = name
return name
/proc/religion_name()
var/static/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(!GLOB.station_name)
var/newname
if(config && config.station_name)
newname = config.station_name
else
newname = new_station_name()
set_station_name(newname)
return GLOB.station_name
/proc/set_station_name(newname)
GLOB.station_name = newname
if(config && config.server_name)
world.name = "[config.server_name][config.server_name==GLOB.station_name ? "" : ": [GLOB.station_name]"]"
else
world.name = GLOB.station_name
/proc/new_station_name()
var/random = rand(1,5)
var/name = ""
var/new_station_name = ""
//Rare: Pre-Prefix
if (prob(10))
name = pick(GLOB.station_prefixes)
new_station_name = name + " "
name = ""
// Prefix
for(var/holiday_name in SSevents.holidays)
if(holiday_name == "Friday the 13th")
random = 13
var/datum/holiday/holiday = SSevents.holidays[holiday_name]
name = holiday.getStationPrefix()
//get normal name
if(!name)
name = pick(GLOB.station_names)
if(name)
new_station_name += name + " "
// Suffix
name = pick(GLOB.station_suffixes)
new_station_name += name + " "
// ID Number
switch(random)
if(1)
new_station_name += "[rand(1, 99)]"
if(2)
new_station_name += pick(GLOB.greek_letters)
if(3)
new_station_name += "\Roman[rand(1,99)]"
if(4)
new_station_name += pick(GLOB.phonetic_alphabet)
if(5)
new_station_name += pick(GLOB.numbers_as_words)
if(13)
new_station_name += pick("13","XIII","Thirteen")
return new_station_name
/proc/syndicate_name()
var/static/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.
GLOBAL_VAR(syndicate_code_phrase) //Code phrase for traitors.
GLOBAL_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(return_list=FALSE)//Proc is used for phrase and response in master_controller.dm
if(!return_list)
. = ""
else
. = list()
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/list/safety = list(1,2,3)//Tells the proc which options to remove later on.
var/nouns = strings(ION_FILE, "ionabstract")
var/objects = strings(ION_FILE, "ionobjects")
var/adjectives = strings(ION_FILE, "ionadjectives")
var/threats = strings(ION_FILE, "ionthreats")
var/foods = strings(ION_FILE, "ionfood")
var/drinks = strings(ION_FILE, "iondrinks")
var/list/locations = GLOB.teleportlocs.len ? GLOB.teleportlocs : drinks //if null, defaults to drinks instead.
var/list/names = list()
for(var/datum/data/record/t in GLOB.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))
. += pick(names)
else
if(prob(10))
. += pick(lizard_name(MALE),lizard_name(FEMALE))
else
var/new_name = pick(pick(GLOB.first_names_male,GLOB.first_names_female))
new_name += " "
new_name += pick(GLOB.last_names)
. += new_name
if(2)
. += pick(get_all_jobs())//Returns a job.
safety -= 1
if(2)
switch(rand(1,3))//Food, drinks, or things. Only selectable once.
if(1)
. += lowertext(pick(drinks))
if(2)
. += lowertext(pick(foods))
if(3)
. += lowertext(pick(locations))
safety -= 2
if(3)
switch(rand(1,4))//Abstract nouns, objects, adjectives, threats. Can be selected more than once.
if(1)
. += lowertext(pick(nouns))
if(2)
. += lowertext(pick(objects))
if(3)
. += lowertext(pick(adjectives))
if(4)
. += lowertext(pick(threats))
if(!return_list)
if(words==1)
. += "."
else
. += ", "
#define ION_FILE "ion_laws.json"
/proc/lizard_name(gender)
if(gender == MALE)
return "[pick(GLOB.lizard_names_male)]-[pick(GLOB.lizard_names_male)]"
else
return "[pick(GLOB.lizard_names_female)]-[pick(GLOB.lizard_names_female)]"
/proc/plasmaman_name()
return "[pick(GLOB.plasmaman_names)] \Roman[rand(1,99)]"
/proc/church_name()
var/static/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")
name += " of [religion_name()]"
return name
GLOBAL_VAR(command_name)
/proc/command_name()
if (GLOB.command_name)
return GLOB.command_name
var/name = "Central Command"
GLOB.command_name = name
return name
/proc/change_command_name(name)
GLOB.command_name = name
return name
/proc/religion_name()
var/static/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(!GLOB.station_name)
var/newname
var/config_station_name = CONFIG_GET(string/stationname)
if(config_station_name)
newname = config_station_name
else
newname = new_station_name()
set_station_name(newname)
return GLOB.station_name
/proc/set_station_name(newname)
GLOB.station_name = newname
var/config_server_name = CONFIG_GET(string/servername)
if(config_server_name)
world.name = "[config_server_name][config_server_name == GLOB.station_name ? "" : ": [GLOB.station_name]"]"
else
world.name = GLOB.station_name
/proc/new_station_name()
var/random = rand(1,5)
var/name = ""
var/new_station_name = ""
//Rare: Pre-Prefix
if (prob(10))
name = pick(GLOB.station_prefixes)
new_station_name = name + " "
name = ""
// Prefix
for(var/holiday_name in SSevents.holidays)
if(holiday_name == "Friday the 13th")
random = 13
var/datum/holiday/holiday = SSevents.holidays[holiday_name]
name = holiday.getStationPrefix()
//get normal name
if(!name)
name = pick(GLOB.station_names)
if(name)
new_station_name += name + " "
// Suffix
name = pick(GLOB.station_suffixes)
new_station_name += name + " "
// ID Number
switch(random)
if(1)
new_station_name += "[rand(1, 99)]"
if(2)
new_station_name += pick(GLOB.greek_letters)
if(3)
new_station_name += "\Roman[rand(1,99)]"
if(4)
new_station_name += pick(GLOB.phonetic_alphabet)
if(5)
new_station_name += pick(GLOB.numbers_as_words)
if(13)
new_station_name += pick("13","XIII","Thirteen")
return new_station_name
/proc/syndicate_name()
var/static/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.
GLOBAL_VAR(syndicate_code_phrase) //Code phrase for traitors.
GLOBAL_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(return_list=FALSE)//Proc is used for phrase and response in master_controller.dm
if(!return_list)
. = ""
else
. = list()
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/list/safety = list(1,2,3)//Tells the proc which options to remove later on.
var/nouns = strings(ION_FILE, "ionabstract")
var/objects = strings(ION_FILE, "ionobjects")
var/adjectives = strings(ION_FILE, "ionadjectives")
var/threats = strings(ION_FILE, "ionthreats")
var/foods = strings(ION_FILE, "ionfood")
var/drinks = strings(ION_FILE, "iondrinks")
var/list/locations = GLOB.teleportlocs.len ? GLOB.teleportlocs : drinks //if null, defaults to drinks instead.
var/list/names = list()
for(var/datum/data/record/t in GLOB.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))
. += pick(names)
else
if(prob(10))
. += pick(lizard_name(MALE),lizard_name(FEMALE))
else
var/new_name = pick(pick(GLOB.first_names_male,GLOB.first_names_female))
new_name += " "
new_name += pick(GLOB.last_names)
. += new_name
if(2)
. += pick(get_all_jobs())//Returns a job.
safety -= 1
if(2)
switch(rand(1,3))//Food, drinks, or things. Only selectable once.
if(1)
. += lowertext(pick(drinks))
if(2)
. += lowertext(pick(foods))
if(3)
. += lowertext(pick(locations))
safety -= 2
if(3)
switch(rand(1,4))//Abstract nouns, objects, adjectives, threats. Can be selected more than once.
if(1)
. += lowertext(pick(nouns))
if(2)
. += lowertext(pick(objects))
if(3)
. += lowertext(pick(adjectives))
if(4)
. += lowertext(pick(threats))
if(!return_list)
if(words==1)
. += "."
else
. += ", "
+2 -2
View File
@@ -19,7 +19,7 @@
return copytext(sqltext, 2, lentext(sqltext));//Quote() adds quotes around input, we already do that
/proc/format_table_name(table as text)
return global.sqlfdbktableprefix + table
return CONFIG_GET(string/feedback_tableprefix) + table
/*
* Text sanitization
@@ -594,7 +594,7 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
//in the json file and have it be reflected in the in game item/mob it came from.
//(That's what things like savefiles are for) Note that this list is not shuffled.
/proc/twitterize(list/proposed, filename, cullshort = 1, storemax = 1000)
if(!islist(proposed) || !filename || !config.log_twitter)
if(!islist(proposed) || !filename || !CONFIG_GET(flag/log_twitter))
return
//Regular expressions are, as usual, absolute magic
+21
View File
@@ -554,3 +554,24 @@
else
return /datum
return text2path(copytext(string_type, 1, last_slash))
//returns a string the last bit of a type, without the preceeding '/'
/proc/type2top(the_type)
//handle the builtins manually
if(!ispath(the_type))
return
switch(the_type)
if(/datum)
return "datum"
if(/atom)
return "atom"
if(/obj)
return "obj"
if(/mob)
return "mob"
if(/area)
return "area"
if(/turf)
return "turf"
else //regex everything else (works for /proc too)
return lowertext(replacetext("[the_type]", "[type2parent(the_type)]/", ""))
+1 -1
View File
@@ -1266,7 +1266,7 @@ proc/pick_closest_path(value, list/matches = get_fancy_list_of_atom_types())
#define QDEL_LIST(L) if(L) { for(var/I in L) qdel(I); L.Cut(); }
#define QDEL_LIST_IN(L, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/______qdel_list_wrapper, L), time, TIMER_STOPPABLE)
#define QDEL_LIST_ASSOC(L) if(L) { for(var/I in L) { qdel(L[I]); qdel(I); } L.Cut(); }
#define QDEL_LIST_ASSOC_VAL(L) if(L) { for(var/I in L) qel(L[I]); L.Cut(); }
#define QDEL_LIST_ASSOC_VAL(L) if(L) { for(var/I in L) qdel(L[I]); L.Cut(); }
/proc/______qdel_list_wrapper(list/L) //the underscores are to encourage people not to use this directly.
QDEL_LIST(L)
+7 -3
View File
@@ -1,4 +1,4 @@
GLOBAL_REAL(config, /datum/configuration)
GLOBAL_REAL(config, /datum/controller/configuration)
GLOBAL_DATUM_INIT(revdata, /datum/getrev, new)
@@ -11,9 +11,7 @@ GLOBAL_VAR_INIT(hub_visibility, FALSE)
GLOBAL_VAR_INIT(ooc_allowed, TRUE) // used with admin verbs to disable ooc - not a config option apparently
GLOBAL_VAR_INIT(dooc_allowed, TRUE)
GLOBAL_VAR_INIT(abandon_allowed, TRUE)
GLOBAL_VAR_INIT(enter_allowed, TRUE)
GLOBAL_VAR_INIT(guests_allowed, TRUE)
GLOBAL_VAR_INIT(shuttle_frozen, FALSE)
GLOBAL_VAR_INIT(shuttle_left, FALSE)
GLOBAL_VAR_INIT(tinted_weldhelh, TRUE)
@@ -25,10 +23,16 @@ GLOBAL_VAR_INIT(Debug, FALSE) // global debug switch
GLOBAL_VAR_INIT(Debug2, FALSE)
//This was a define, but I changed it to a variable so it can be changed in-game.(kept the all-caps definition because... code...) -Errorage
//Protecting these because the proper way to edit them is with the config/secrets
GLOBAL_VAR_INIT(MAX_EX_DEVESTATION_RANGE, 3)
GLOBAL_PROTECT(MAX_EX_DEVESTATION_RANGE)
GLOBAL_VAR_INIT(MAX_EX_HEAVY_RANGE, 7)
GLOBAL_PROTECT(MAX_EX_HEAVY_RANGE)
GLOBAL_VAR_INIT(MAX_EX_LIGHT_RANGE, 14)
GLOBAL_PROTECT(MAX_EX_LIGHT_RANGE)
GLOBAL_VAR_INIT(MAX_EX_FLASH_RANGE, 14)
GLOBAL_PROTECT(MAX_EX_FLASH_RANGE)
GLOBAL_VAR_INIT(MAX_EX_FLAME_RANGE, 14)
GLOBAL_PROTECT(MAX_EX_FLAME_RANGE)
GLOBAL_VAR_INIT(DYN_EX_SCALE, 0.5)
-16
View File
@@ -1,16 +0,0 @@
//Server API key
GLOBAL_REAL_VAR(comms_key) = "default_pwd"
GLOBAL_REAL_VAR(comms_allowed) = FALSE //By default, the server does not allow messages to be sent to it, unless the key is strong enough (this is to prevent misconfigured servers from becoming vulnerable)
GLOBAL_REAL_VAR(medal_hub)
GLOBAL_REAL_VAR(medal_pass) = " "
GLOBAL_REAL_VAR(medals_enabled) = TRUE //will be auto set to false if the game fails contacting the medal hub to prevent unneeded calls.
// MySQL configuration
GLOBAL_REAL_VAR(sqladdress) = "localhost"
GLOBAL_REAL_VAR(sqlport) = "3306"
GLOBAL_REAL_VAR(sqlfdbkdb) = "test"
GLOBAL_REAL_VAR(sqlfdbklogin) = "root"
GLOBAL_REAL_VAR(sqlfdbkpass) = ""
GLOBAL_REAL_VAR(sqlfdbktableprefix) = ""
@@ -51,13 +51,7 @@
return FALSE
return ..()
/datum/config_entry/proc/VASProcCallGuard(str_val)
. = !(IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "ValidateAndSet" && GLOB.LastAdminCalledTargetRef == "\ref[src]")
if(!.)
log_admin_private("Config set of [type] to [str_val] attempted by [key_name(usr)]")
/datum/config_entry/proc/ValidateAndSet(str_val)
VASProcCallGuard(str_val)
CRASH("Invalid config entry type!")
/datum/config_entry/proc/ValidateKeyedList(str_val, list_mode, splitter)
@@ -98,8 +92,6 @@
return var_name != "auto_trim" && ..()
/datum/config_entry/string/ValidateAndSet(str_val)
if(!VASProcCallGuard(str_val))
return FALSE
value = auto_trim ? trim(str_val) : str_val
return TRUE
@@ -111,8 +103,6 @@
var/min_val = -INFINITY
/datum/config_entry/number/ValidateAndSet(str_val)
if(!VASProcCallGuard(str_val))
return FALSE
var/temp = text2num(trim(str_val))
if(!isnull(temp))
value = Clamp(integer ? round(temp) : temp, min_val, max_val)
@@ -130,8 +120,6 @@
abstract_type = /datum/config_entry/flag
/datum/config_entry/flag/ValidateAndSet(str_val)
if(!VASProcCallGuard(str_val))
return FALSE
value = text2num(trim(str_val)) != 0
return TRUE
@@ -140,8 +128,6 @@
value = list()
/datum/config_entry/number_list/ValidateAndSet(str_val)
if(!VASProcCallGuard(str_val))
return FALSE
str_val = trim(str_val)
var/list/new_list = list()
var/list/values = splittext(str_val," ")
@@ -161,8 +147,6 @@
dupes_allowed = TRUE
/datum/config_entry/keyed_flag_list/ValidateAndSet(str_val)
if(!VASProcCallGuard(str_val))
return FALSE
return ValidateKeyedList(str_val, LIST_MODE_FLAG, " ")
/datum/config_entry/keyed_number_list
@@ -175,8 +159,6 @@
return var_name != "splitter" && ..()
/datum/config_entry/keyed_number_list/ValidateAndSet(str_val)
if(!VASProcCallGuard(str_val))
return FALSE
return ValidateKeyedList(str_val, LIST_MODE_NUM, splitter)
/datum/config_entry/keyed_string_list
@@ -189,8 +171,6 @@
return var_name != "splitter" && ..()
/datum/config_entry/keyed_string_list/ValidateAndSet(str_val)
if(!VASProcCallGuard(str_val))
return FALSE
return ValidateKeyedList(str_val, LIST_MODE_TEXT, splitter)
#undef LIST_MODE_NUM
@@ -0,0 +1,22 @@
#define CURRENT_RESIDENT_FILE "comms.txt"
CONFIG_DEF(string/comms_key)
protection = CONFIG_ENTRY_HIDDEN
/datum/config_entry/string/comms_key/ValidateAndSet(str_val)
return str_val != "default_pwd" && length(str_val) > 6 && ..()
CONFIG_DEF(string/cross_server_address)
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/string/cross_server_address/ValidateAndSet(str_val)
return str_val != "byond:\\address:port" && ..()
CONFIG_DEF(string/cross_comms_name)
GLOBAL_VAR_INIT(medals_enabled, TRUE) //will be auto set to false if the game fails contacting the medal hub to prevent unneeded calls.
CONFIG_DEF(string/medal_hub_address)
CONFIG_DEF(string/medal_hub_password)
protection = CONFIG_ENTRY_HIDDEN
@@ -0,0 +1,387 @@
#define CURRENT_RESIDENT_FILE "config.txt"
CONFIG_DEF(flag/autoadmin) // if autoadmin is enabled
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/autoadmin_rank) // the rank for autoadmins
value = "Game Master"
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/servername) // server name (the name of the game window)
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/serversqlname) // short form server name used for the DB
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/stationname) // station name (the name of the station in-game)
CONFIG_DEF(number/lobby_countdown) // In between round countdown.
value = 120
min_val = 0
CONFIG_DEF(number/round_end_countdown) // Post round murder death kill countdown
value = 25
min_val = 0
CONFIG_DEF(flag/hub) // if the game appears on the hub or not
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_ooc) // log OOC channel
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_access) // log login/logout
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_say) // log client say
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_admin) // log admin actions
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_prayer) // log prayers
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_law) // log lawchanges
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_game) // log game events
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_vote) // log voting
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_whisper) // log client whisper
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_attack) // log attack messages
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_emote) // log emotes
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_adminchat) // log admin chat messages
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_pda) // log pda messages
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_twitter) // log certain expliotable parrots and other such fun things in a JSON file of twitter valid phrases.
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_world_topic) // log all world.Topic() calls
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/allow_admin_ooccolor) // Allows admins with relevant permissions to have their own ooc colour
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/allow_vote_restart) // allow votes to restart
CONFIG_DEF(flag/allow_vote_mode) // allow votes to change mode
CONFIG_DEF(number/vote_delay) // minimum time between voting sessions (deciseconds, 10 minute default)
value = 6000
min_val = 0
CONFIG_DEF(number/vote_period) // length of voting period (deciseconds, default 1 minute)
value = 600
min_val = 0
CONFIG_DEF(flag/default_no_vote) // vote does not default to nochange/norestart
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/no_dead_vote) // dead people can't vote
CONFIG_DEF(flag/allow_metadata) // Metadata is supported.
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/popup_admin_pm) // adminPMs to non-admins show in a pop-up 'reply' window when set
CONFIG_DEF(number/fps)
value = 20
min_val = 1
max_val = 100 //byond will start crapping out at 50, so this is just ridic
var/sync_validate = FALSE
/datum/config_entry/number/fps/ValidateAndSet(str_val)
. = ..()
if(.)
sync_validate = TRUE
var/datum/config_entry/number/ticklag/TL = config.entries_by_type[/datum/config_entry/number/ticklag]
if(!TL.sync_validate)
TL.ValidateAndSet(10 / value)
sync_validate = FALSE
CONFIG_DEF(number/ticklag)
integer = FALSE
var/sync_validate = FALSE
/datum/config_entry/number/ticklag/New() //ticklag weirdly just mirrors fps
var/datum/config_entry/CE = /datum/config_entry/number/fps
value = 10 / initial(CE.value)
..()
/datum/config_entry/number/ticklag/ValidateAndSet(str_val)
. = text2num(str_val) > 0 && ..()
if(.)
sync_validate = TRUE
var/datum/config_entry/number/fps/FPS = config.entries_by_type[/datum/config_entry/number/fps]
if(!FPS.sync_validate)
FPS.ValidateAndSet(10 / value)
sync_validate = FALSE
CONFIG_DEF(flag/allow_holidays)
CONFIG_DEF(number/tick_limit_mc_init) //SSinitialization throttling
value = TICK_LIMIT_MC_INIT_DEFAULT
min_val = 0 //oranges warned us
integer = FALSE
CONFIG_DEF(flag/admin_legacy_system) //Defines whether the server uses the legacy admin system with admins.txt or the SQL system
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/hostedby)
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/norespawn)
CONFIG_DEF(flag/guest_jobban)
CONFIG_DEF(flag/usewhitelist)
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/ban_legacy_system) //Defines whether the server uses the legacy banning system with the files in /data or the SQL system.
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/use_age_restriction_for_jobs) //Do jobs use account age restrictions? --requires database
CONFIG_DEF(flag/use_account_age_for_jobs) //Uses the time they made the account for the job restriction stuff. New player joining alerts should be unaffected.
CONFIG_DEF(flag/use_exp_tracking)
CONFIG_DEF(flag/use_exp_restrictions_heads)
CONFIG_DEF(number/use_exp_restrictions_heads_hours)
value = 0
min_val = 0
CONFIG_DEF(flag/use_exp_restrictions_heads_department)
CONFIG_DEF(flag/use_exp_restrictions_other)
CONFIG_DEF(flag/use_exp_restrictions_admin_bypass)
CONFIG_DEF(string/server)
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/banappeals)
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/wikiurl)
protection = CONFIG_ENTRY_LOCKED
value = "http://www.tgstation13.org/wiki"
CONFIG_DEF(string/forumurl)
protection = CONFIG_ENTRY_LOCKED
value = "http://tgstation13.org/phpBB/index.php"
CONFIG_DEF(string/rulesurl)
protection = CONFIG_ENTRY_LOCKED
value = "http://www.tgstation13.org/wiki/Rules"
CONFIG_DEF(string/githuburl)
protection = CONFIG_ENTRY_LOCKED
value = "https://www.github.com/tgstation/-tg-station"
CONFIG_DEF(number/githubrepoid)
protection = CONFIG_ENTRY_LOCKED
value = null
min_val = 0
CONFIG_DEF(flag/guest_ban)
CONFIG_DEF(number/id_console_jobslot_delay)
value = 30
min_val = 0
CONFIG_DEF(number/inactivity_period) //time in ds until a player is considered inactive)
value = 3000
min_val = 0
/datum/config_entry/number/inactivity_period/ValidateAndSet(str_val)
. = ..()
if(.)
value *= 10 //documented as seconds in config.txt
CONFIG_DEF(number/afk_period) //time in ds until a player is considered inactive)
value = 3000
min_val = 0
/datum/config_entry/number/afk_period/ValidateAndSet(str_val)
. = ..()
if(.)
value *= 10 //documented as seconds in config.txt
CONFIG_DEF(flag/kick_inactive) //force disconnect for inactive players
CONFIG_DEF(flag/load_jobs_from_txt)
CONFIG_DEF(flag/forbid_singulo_possession)
CONFIG_DEF(flag/useircbot) //tgs2 support
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/automute_on) //enables automuting/spam prevention
CONFIG_DEF(string/panic_server_name)
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/string/panic_server_name/ValidateAndSet(str_val)
return str_val != "\[Put the name here\]" && ..()
CONFIG_DEF(string/panic_address) //Reconnect a player this linked server if this server isn't accepting new players
/datum/config_entry/string/panic_address/ValidateAndSet(str_val)
return str_val != "byond://address:port" && ..()
CONFIG_DEF(string/invoke_youtubedl)
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
CONFIG_DEF(flag/show_irc_name)
CONFIG_DEF(flag/see_own_notes) //Can players see their own admin notes (read-only)?
CONFIG_DEF(number/note_fresh_days)
value = null
min_val = 0
integer = FALSE
CONFIG_DEF(number/note_stale_days)
value = null
min_val = 0
integer = FALSE
CONFIG_DEF(flag/maprotation)
CONFIG_DEF(number/maprotatechancedelta)
value = 0.75
min_val = 0
max_val = 1
integer = FALSE
CONFIG_DEF(number/soft_popcap)
value = null
min_val = 0
CONFIG_DEF(number/hard_popcap)
value = null
min_val = 0
CONFIG_DEF(number/extreme_popcap)
value = null
min_val = 0
CONFIG_DEF(string/soft_popcap_message)
value = "Be warned that the server is currently serving a high number of users, consider using alternative game servers."
CONFIG_DEF(string/hard_popcap_message)
value = "The server is currently serving a high number of users, You cannot currently join. You may wait for the number of living crew to decline, observe, or find alternative servers."
CONFIG_DEF(string/extreme_popcap_message)
value = "The server is currently serving a high number of users, find alternative servers."
CONFIG_DEF(flag/panic_bunker) // prevents people the server hasn't seen before from connecting
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(number/notify_new_player_age) // how long do we notify admins of a new player
min_val = -1
CONFIG_DEF(number/notify_new_player_account_age) // how long do we notify admins of a new byond account
min_val = 0
CONFIG_DEF(flag/irc_first_connection_alert) // do we notify the irc channel when somebody is connecting for the first time?
CONFIG_DEF(flag/check_randomizer)
CONFIG_DEF(string/ipintel_email)
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
/datum/config_entry/string/ipintel_email/ValidateAndSet(str_val)
return str_val != "ch@nge.me" && ..()
CONFIG_DEF(number/ipintel_rating_bad)
value = 1
integer = FALSE
min_val = 0
max_val = 1
CONFIG_DEF(number/ipintel_save_good)
protection = CONFIG_ENTRY_LOCKED
value = 12
min_val = 0
CONFIG_DEF(number/ipintel_save_bad)
protection = CONFIG_ENTRY_LOCKED
value = 1
min_val = 0
CONFIG_DEF(string/ipintel_domain)
protection = CONFIG_ENTRY_LOCKED
value = "check.getipintel.net"
CONFIG_DEF(flag/aggressive_changelog)
CONFIG_DEF(flag/autoconvert_notes) //if all connecting player's notes should attempt to be converted to the database
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/allow_webclient)
CONFIG_DEF(flag/webclient_only_byond_members)
CONFIG_DEF(flag/announce_admin_logout)
CONFIG_DEF(flag/announce_admin_login)
CONFIG_DEF(flag/allow_map_voting)
CONFIG_DEF(flag/generate_minimaps)
CONFIG_DEF(number/client_warn_version)
value = null
min_val = 500
max_val = DM_VERSION - 1
CONFIG_DEF(string/client_warn_message)
value = "Your version of byond may have issues or be blocked from accessing this server in the future."
CONFIG_DEF(number/client_error_version)
value = null
min_val = 500
max_val = DM_VERSION - 1
CONFIG_DEF(string/client_error_message)
value = "Your version of byond is too old, may have issues, and is blocked from accessing this server."
CONFIG_DEF(number/minute_topic_limit)
value = null
min_val = 0
CONFIG_DEF(number/second_topic_limit)
value = null
min_val = 0
CONFIG_DEF(number/error_cooldown) // The "cooldown" time for each occurrence of a unique error)
value = 600
min_val = 0
CONFIG_DEF(number/error_limit) // How many occurrences before the next will silence them
value = 50
CONFIG_DEF(number/error_silence_time) // How long a unique error will be silenced for
value = 6000
CONFIG_DEF(number/error_msg_delay) // How long to wait between messaging admins about occurrences of a unique error
value = 50
CONFIG_DEF(flag/irc_announce_new_game)
CONFIG_DEF(flag/debug_admin_hrefs)
@@ -0,0 +1,28 @@
#define CURRENT_RESIDENT_FILE "dbconfig.txt"
CONFIG_DEF(flag/sql_enabled) // for sql switching
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/address)
value = "localhost"
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
CONFIG_DEF(number/port)
value = 3306
min_val = 0
max_val = 65535
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
CONFIG_DEF(string/feedback_database)
value = "test"
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
CONFIG_DEF(string/feedback_login)
value = "root"
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
CONFIG_DEF(string/feedback_password)
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
CONFIG_DEF(string/feedback_tableprefix)
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
@@ -0,0 +1,266 @@
#define CURRENT_RESIDENT_FILE "game_options.txt"
CONFIG_DEF(number_list/repeated_mode_adjust)
CONFIG_DEF(keyed_number_list/probability)
/datum/config_entry/keyed_number_list/probability/ValidateKeyName(key_name)
return key_name in config.modes
CONFIG_DEF(keyed_number_list/max_pop)
/datum/config_entry/keyed_number_list/max_pop/ValidateKeyName(key_name)
return key_name in config.modes
CONFIG_DEF(keyed_number_list/min_pop)
/datum/config_entry/keyed_number_list/min_pop/ValidateKeyName(key_name)
return key_name in config.modes
CONFIG_DEF(keyed_flag_list/continuous) // which roundtypes continue if all antagonists die
/datum/config_entry/keyed_flag_list/continuous/ValidateKeyName(key_name)
return key_name in config.modes
CONFIG_DEF(keyed_flag_list/midround_antag) // which roundtypes use the midround antagonist system
/datum/config_entry/keyed_flag_list/midround_antag/ValidateKeyName(key_name)
return key_name in config.modes
CONFIG_DEF(keyed_string_list/policy)
CONFIG_DEF(number/damage_multiplier)
value = 1
integer = FALSE
CONFIG_DEF(number/minimal_access_threshold) //If the number of players is larger than this threshold, minimal access will be turned on.
min_val = 0
CONFIG_DEF(flag/jobs_have_minimal_access) //determines whether jobs use minimal access or expanded access.
CONFIG_DEF(flag/assistants_have_maint_access)
CONFIG_DEF(flag/security_has_maint_access)
CONFIG_DEF(flag/everyone_has_maint_access)
CONFIG_DEF(flag/sec_start_brig) //makes sec start in brig instead of dept sec posts
CONFIG_DEF(flag/force_random_names)
CONFIG_DEF(flag/humans_need_surnames)
CONFIG_DEF(flag/allow_ai) // allow ai job
CONFIG_DEF(flag/disable_secborg) // disallow secborg module to be chosen.
CONFIG_DEF(flag/disable_peaceborg)
CONFIG_DEF(number/traitor_scaling_coeff) //how much does the amount of players get divided by to determine traitors
value = 6
min_val = 1
CONFIG_DEF(number/brother_scaling_coeff) //how many players per brother team
value = 25
min_val = 1
CONFIG_DEF(number/changeling_scaling_coeff) //how much does the amount of players get divided by to determine changelings
value = 6
min_val = 1
CONFIG_DEF(number/security_scaling_coeff) //how much does the amount of players get divided by to determine open security officer positions
value = 8
min_val = 1
CONFIG_DEF(number/abductor_scaling_coeff) //how many players per abductor team
value = 15
min_val = 1
CONFIG_DEF(number/traitor_objectives_amount)
value = 2
min_val = 0
CONFIG_DEF(number/brother_objectives_amount)
value = 2
min_val = 0
CONFIG_DEF(flag/reactionary_explosions) //If we use reactionary explosions, explosions that react to walls and doors
CONFIG_DEF(flag/protect_roles_from_antagonist) //If security and such can be traitor/cult/other
CONFIG_DEF(flag/protect_assistant_from_antagonist) //If assistants can be traitor/cult/other
CONFIG_DEF(flag/enforce_human_authority) //If non-human species are barred from joining as a head of staff
CONFIG_DEF(flag/allow_latejoin_antagonists) // If late-joining players can be traitor/changeling
CONFIG_DEF(number/midround_antag_time_check) // How late (in minutes) you want the midround antag system to stay on, setting this to 0 will disable the system
value = 60
min_val = 0
CONFIG_DEF(number/midround_antag_life_check) // A ratio of how many people need to be alive in order for the round not to immediately end in midround antagonist
value = 0.7
integer = FALSE
min_val = 0
max_val = 1
CONFIG_DEF(number/shuttle_refuel_delay)
value = 12000
min_val = 0
CONFIG_DEF(flag/show_game_type_odds) //if set this allows players to see the odds of each roundtype on the get revision screen
CONFIG_DEF(flag/join_with_mutant_race) //players can choose their mutant race before joining the game
CONFIG_DEF(keyed_flag_list/roundstart_races) //races you can play as from the get go. If left undefined the game's roundstart var for species is used
var/first_edit = TRUE
/datum/config_entry/keyed_flag_list/roundstart_races/New()
for(var/I in subtypesof(/datum/species))
var/datum/species/S = I
if(initial(S.roundstart))
value[initial(S.id)] = TRUE
..()
/datum/config_entry/keyed_flag_list/roundstart_races/ValidateAndSet(str_val)
var/list/old_val
if(first_edit)
old_val = value
old_val = old_val.Copy()
. = ..()
if(first_edit)
if(!.)
value = old_val
else
first_edit = FALSE
CONFIG_DEF(flag/join_with_mutant_humans) //players can pick mutant bodyparts for humans before joining the game
CONFIG_DEF(flag/no_summon_guns) //No
CONFIG_DEF(flag/no_summon_magic) //Fun
CONFIG_DEF(flag/no_summon_events) //Allowed
CONFIG_DEF(flag/no_intercept_report) //Whether or not to send a communications intercept report roundstart. This may be overriden by gamemodes.
CONFIG_DEF(number/arrivals_shuttle_dock_window) //Time from when a player late joins on the arrivals shuttle to when the shuttle docks on the station
value = 55
min_val = 30
CONFIG_DEF(flag/arrivals_shuttle_require_undocked) //Require the arrivals shuttle to be undocked before latejoiners can join
CONFIG_DEF(flag/arrivals_shuttle_require_safe_latejoin) //Require the arrivals shuttle to be operational in order for latejoiners to join
CONFIG_DEF(string/alert_green)
value = "All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced."
CONFIG_DEF(string/alert_blue_upto)
value = "The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible, random searches are permitted."
CONFIG_DEF(string/alert_blue_downto)
value = "The immediate threat has passed. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still allowed."
CONFIG_DEF(string/alert_red_upto)
value = "There is an immediate serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised."
CONFIG_DEF(string/alert_red_downto)
value = "The station's destruction has been averted. There is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised."
CONFIG_DEF(string/alert_delta)
value = "Destruction of the station is imminent. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill."
CONFIG_DEF(flag/revival_pod_plants)
CONFIG_DEF(flag/revival_cloning)
CONFIG_DEF(number/revival_brain_life)
value = -1
min_val = -1
CONFIG_DEF(flag/rename_cyborg)
CONFIG_DEF(flag/ooc_during_round)
CONFIG_DEF(flag/emojis)
CONFIG_DEF(number/run_delay) //Used for modifying movement speed for mobs.
CONFIG_DEF(number/walk_delay)
CONFIG_DEF(number/human_delay) //Mob specific modifiers. NOTE: These will affect different mob types in different ways
CONFIG_DEF(number/robot_delay)
CONFIG_DEF(number/monkey_delay)
CONFIG_DEF(number/alien_delay)
CONFIG_DEF(number/slime_delay)
CONFIG_DEF(number/animal_delay)
CONFIG_DEF(number/gateway_delay) //How long the gateway takes before it activates. Default is half an hour.
value = 18000
min_val = 0
CONFIG_DEF(flag/ghost_interaction)
CONFIG_DEF(flag/silent_ai)
CONFIG_DEF(flag/silent_borg)
CONFIG_DEF(flag/sandbox_autoclose) // close the sandbox panel after spawning an item, potentially reducing griff
CONFIG_DEF(number/default_laws) //Controls what laws the AI spawns with.
value = 0
min_val = 0
max_val = 3
CONFIG_DEF(number/silicon_max_law_amount)
value = 12
min_val = 0
CONFIG_DEF(keyed_flag_list/random_laws)
CONFIG_DEF(keyed_number_list/law_weight)
splitter = ","
CONFIG_DEF(number/assistant_cap)
value = -1
min_val = -1
CONFIG_DEF(flag/starlight)
CONFIG_DEF(flag/grey_assistants)
CONFIG_DEF(number/lavaland_budget)
value = 60
min_val = 0
CONFIG_DEF(number/space_budget)
value = 16
min_val = 0
CONFIG_DEF(flag/allow_random_events) // Enables random events mid-round when set
CONFIG_DEF(number/events_min_time_mul) // Multipliers for random events minimal starting time and minimal players amounts
value = 1
min_val = 0
integer = FALSE
CONFIG_DEF(number/events_min_players_mul)
value = 1
min_val = 0
integer = FALSE
CONFIG_DEF(number/mice_roundstart)
value = 10
min_val = 0
CONFIG_DEF(number/bombcap)
value = 14
min_val = 4
/datum/config_entry/number/bombcap/ValidateAndSet(str_val)
. = ..()
if(.)
GLOB.MAX_EX_DEVESTATION_RANGE = round(value / 4)
GLOB.MAX_EX_HEAVY_RANGE = round(value / 2)
GLOB.MAX_EX_LIGHT_RANGE = value
GLOB.MAX_EX_FLASH_RANGE = value
GLOB.MAX_EX_FLAME_RANGE = value
+2 -2
View File
@@ -169,7 +169,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
var/start_timeofday = REALTIMEOFDAY
// Initialize subsystems.
current_ticklimit = config.tick_limit_mc_init
current_ticklimit = CONFIG_GET(number/tick_limit_mc_init)
for (var/datum/controller/subsystem/SS in subsystems)
if (SS.flags & SS_NO_INIT)
continue
@@ -189,7 +189,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
sortTim(subsystems, /proc/cmp_subsystem_display)
// Set world options.
world.sleep_offline = 1
world.fps = config.fps
world.fps = CONFIG_GET(number/fps)
var/initialized_tod = REALTIMEOFDAY
sleep(1)
initializations_finished_with_no_players_logged_in = initialized_tod < REALTIMEOFDAY - 10
+1 -1
View File
@@ -38,7 +38,7 @@ SUBSYSTEM_DEF(blackbox)
var/datum/DBQuery/query_record_playercount = SSdbcore.NewQuery("INSERT INTO [format_table_name("legacy_population")] (playercount, admincount, time, server_ip, server_port, round_id) VALUES ([playercount], [admincount], '[SQLtime()]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', '[GLOB.round_id]')")
query_record_playercount.Execute()
if(config.use_exp_tracking)
if(CONFIG_GET(flag/use_exp_tracking))
if((triggertime < 0) || (world.time > (triggertime +3000))) //subsystem fires once at roundstart then once every 10 minutes. a 5 min check skips the first fire. The <0 is midnight rollover check
update_exp(10,FALSE)
+9 -14
View File
@@ -54,32 +54,27 @@ SUBSYSTEM_DEF(dbcore)
if(failed_connections > FAILED_DB_CONNECTION_CUTOFF) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to connect anymore.
return FALSE
if(!config.sql_enabled)
if(!CONFIG_GET(flag/sql_enabled))
return FALSE
var/user = global.sqlfdbklogin
var/pass = global.sqlfdbkpass
var/db = global.sqlfdbkdb
var/address = global.sqladdress
var/port = global.sqlport
var/user = CONFIG_GET(string/feedback_login)
var/pass = CONFIG_GET(string/feedback_password)
var/db = CONFIG_GET(string/feedback_database)
var/address = CONFIG_GET(string/address)
var/port = CONFIG_GET(number/port)
doConnect("dbi:mysql:[db]:[address]:[port]", user, pass)
_dm_db_connect(_db_con, "dbi:mysql:[db]:[address]:[port]", user, pass, Default_Cursor, null)
. = IsConnected()
if (!.)
log_sql("Connect() failed | [ErrorMsg()]")
++failed_connections
/datum/controller/subsystem/dbcore/proc/doConnect(dbi_handler, user_handler, password_handler)
if(!config.sql_enabled)
return FALSE
return _dm_db_connect(_db_con, dbi_handler, user_handler, password_handler, Default_Cursor, null)
/datum/controller/subsystem/dbcore/proc/Disconnect()
failed_connections = 0
return _dm_db_close(_db_con)
/datum/controller/subsystem/dbcore/proc/IsConnected()
if(!config.sql_enabled)
if(!CONFIG_GET(flag/sql_enabled))
return FALSE
return _dm_db_is_connected(_db_con)
@@ -87,7 +82,7 @@ SUBSYSTEM_DEF(dbcore)
return _dm_db_quote(_db_con, str)
/datum/controller/subsystem/dbcore/proc/ErrorMsg()
if(!config.sql_enabled)
if(!CONFIG_GET(flag/sql_enabled))
return "Database disabled by configuration"
return _dm_db_error_msg(_db_con)
+2 -2
View File
@@ -56,7 +56,7 @@ SUBSYSTEM_DEF(events)
//selects a random event based on whether it can occur and it's 'weight'(probability)
/datum/controller/subsystem/events/proc/spawnEvent()
set waitfor = FALSE //for the admin prompt
if(!config.allow_random_events)
if(!CONFIG_GET(flag/allow_random_events))
// var/datum/round_event_control/E = locate(/datum/round_event_control/dust) in control
// if(E) E.runEvent()
return
@@ -171,7 +171,7 @@ SUBSYSTEM_DEF(events)
//sets up the holidays and holidays list
/datum/controller/subsystem/events/proc/getHoliday()
if(!config.allow_holidays)
if(!CONFIG_GET(flag/allow_holidays))
return // Holiday stuff was not enabled in the config!
var/YY = text2num(time2text(world.timeofday, "YY")) // get the current year
+18 -14
View File
@@ -16,7 +16,7 @@ SUBSYSTEM_DEF(job)
/datum/controller/subsystem/job/Initialize(timeofday)
if(!occupations.len)
SetupOccupations()
if(config.load_jobs_from_txt)
if(CONFIG_GET(flag/load_jobs_from_txt))
LoadJobs()
..()
@@ -106,7 +106,7 @@ SUBSYSTEM_DEF(job)
if(player.mind && job.title in player.mind.restricted_roles)
Debug("FOC incompatible with antagonist role, Player: [player]")
continue
if(config.enforce_human_authority && !player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features))
if(CONFIG_GET(flag/enforce_human_authority) && !player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features))
Debug("FOC non-human failed, Player: [player]")
continue
if(player.client.prefs.GetJobDepartment(job, level) & job.flag)
@@ -143,7 +143,7 @@ SUBSYSTEM_DEF(job)
Debug("GRJ incompatible with antagonist role, Player: [player], Job: [job.title]")
continue
if(config.enforce_human_authority && !player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features))
if(CONFIG_GET(flag/enforce_human_authority) && !player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features))
Debug("GRJ non-human failed, Player: [player]")
continue
@@ -245,11 +245,12 @@ SUBSYSTEM_DEF(job)
setup_officer_positions()
//Jobs will have fewer access permissions if the number of players exceeds the threshold defined in game_options.txt
if(config.minimal_access_threshold)
if(config.minimal_access_threshold > unassigned.len)
config.jobs_have_minimal_access = 0
var/mat = CONFIG_GET(number/minimal_access_threshold)
if(mat)
if(mat > unassigned.len)
CONFIG_SET(flag/jobs_have_minimal_access, FALSE)
else
config.jobs_have_minimal_access = 1
CONFIG_SET(flag/jobs_have_minimal_access, TRUE)
//Shuffle players and jobs
unassigned = shuffle(unassigned)
@@ -317,7 +318,7 @@ SUBSYSTEM_DEF(job)
Debug("DO incompatible with antagonist role, Player: [player], Job:[job.title]")
continue
if(config.enforce_human_authority && !player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features))
if(CONFIG_GET(flag/enforce_human_authority) && !player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features))
Debug("DO non-human failed, Player: [player], Job:[job.title]")
continue
@@ -415,8 +416,8 @@ SUBSYSTEM_DEF(job)
to_chat(M, "<b>To speak on your departments radio, use the :h button. To see others, look closely at your headset.</b>")
if(job.req_admin_notify)
to_chat(M, "<b>You are playing a job that is important for Game Progression. If you have to disconnect, please notify the admins via adminhelp.</b>")
if(config.minimal_access_threshold)
to_chat(M, "<FONT color='blue'><B>As this station was initially staffed with a [config.jobs_have_minimal_access ? "full crew, only your job's necessities" : "skeleton crew, additional access may"] have been added to your ID card.</B></font>")
if(CONFIG_GET(number/minimal_access_threshold))
to_chat(M, "<FONT color='blue'><B>As this station was initially staffed with a [CONFIG_GET(flag/jobs_have_minimal_access) ? "full crew, only your job's necessities" : "skeleton crew, additional access may"] have been added to your ID card.</B></font>")
if(job && H)
job.after_spawn(H, M)
@@ -429,9 +430,10 @@ SUBSYSTEM_DEF(job)
if(!J)
throw EXCEPTION("setup_officer_positions(): Security officer job is missing")
if(config.security_scaling_coeff > 0)
var/ssc = CONFIG_GET(number/security_scaling_coeff)
if(ssc > 0)
if(J.spawn_positions > 0)
var/officer_positions = min(12, max(J.spawn_positions, round(unassigned.len/config.security_scaling_coeff))) //Scale between configured minimum and 12 officers
var/officer_positions = min(12, max(J.spawn_positions, round(unassigned.len / ssc))) //Scale between configured minimum and 12 officers
Debug("Setting open security officer positions to [officer_positions]")
J.total_positions = officer_positions
J.spawn_positions = officer_positions
@@ -491,8 +493,10 @@ SUBSYSTEM_DEF(job)
SSblackbox.add_details("job_preferences",tmp_str)
/datum/controller/subsystem/job/proc/PopcapReached()
if(config.hard_popcap || config.extreme_popcap)
var/relevent_cap = max(config.hard_popcap, config.extreme_popcap)
var/hpc = CONFIG_GET(number/hard_popcap)
var/epc = CONFIG_GET(number/extreme_popcap)
if(hpc || epc)
var/relevent_cap = max(hpc, epc)
if((initial_players_to_assign - unassigned.len) >= relevent_cap)
return 1
return 0
+1 -1
View File
@@ -16,7 +16,7 @@ SUBSYSTEM_DEF(lighting)
/datum/controller/subsystem/lighting/Initialize(timeofday)
if(!initialized)
if (config.starlight)
if (CONFIG_GET(flag/starlight))
for(var/I in GLOB.sortedAreas)
var/area/A = I
if (A.dynamic_lighting == DYNAMIC_LIGHTING_IFSTARLIGHT)
+5 -4
View File
@@ -43,7 +43,7 @@ SUBSYSTEM_DEF(mapping)
loading_ruins = TRUE
var/mining_type = config.minetype
if (mining_type == "lavaland")
seedRuins(list(ZLEVEL_LAVALAND), global.config.lavaland_budget, /area/lavaland/surface/outdoors/unexplored, lava_ruins_templates)
seedRuins(list(ZLEVEL_LAVALAND), CONFIG_GET(number/lavaland_budget), /area/lavaland/surface/outdoors/unexplored, lava_ruins_templates)
spawn_rivers()
// deep space ruins
@@ -55,7 +55,7 @@ SUBSYSTEM_DEF(mapping)
else
space_zlevels += i
seedRuins(space_zlevels, global.config.space_budget, /area/space, space_ruins_templates)
seedRuins(space_zlevels, CONFIG_GET(number/space_budget), /area/space, space_ruins_templates)
loading_ruins = FALSE
repopulate_sorted_areas()
// Set up Z-level transistions.
@@ -141,7 +141,8 @@ SUBSYSTEM_DEF(mapping)
var/players = GLOB.clients.len
var/list/mapvotes = list()
//count votes
if(global.config.allow_map_voting)
var/amv = CONFIG_GET(flag/allow_map_voting)
if(amv)
for (var/client/c in GLOB.clients)
var/vote = c.prefs.preferred_map
if (!vote)
@@ -174,7 +175,7 @@ SUBSYSTEM_DEF(mapping)
mapvotes.Remove(map)
continue
if(global.config.allow_map_voting)
if(amv)
mapvotes[map] = mapvotes[map]*VM.voteweight
var/pickedmap = pickweight(mapvotes)
+1 -1
View File
@@ -9,7 +9,7 @@ SUBSYSTEM_DEF(minimap)
/datum/controller/subsystem/minimap/Initialize(timeofday)
var/hash = md5(SSmapping.config.GetFullMapPath())
if(config.generate_minimaps)
if(CONFIG_GET(flag/generate_minimaps))
if(hash == trim(file2text(hash_path())))
for(var/z in z_levels) //We have these files cached, let's register them
register_asset("minimap_[z].png", fcopy_rsc(map_path(z)))
+12 -9
View File
@@ -10,7 +10,7 @@ SUBSYSTEM_DEF(server_maint)
var/list/currentrun
/datum/controller/subsystem/server_maint/Initialize(timeofday)
if (config.hub)
if (CONFIG_GET(flag/hub))
world.update_hub_visibility(TRUE)
..()
@@ -21,16 +21,19 @@ SUBSYSTEM_DEF(server_maint)
var/list/currentrun = src.currentrun
var/round_started = SSticker.HasRoundStarted()
var/kick_inactive = CONFIG_GET(flag/kick_inactive)
var/afk_period
if(kick_inactive)
afk_period = CONFIG_GET(number/afk_period)
for(var/I in currentrun)
var/client/C = I
//handle kicking inactive players
if(round_started && config.kick_inactive)
if(C.is_afk(config.afk_period))
var/cmob = C.mob
if(!(isobserver(cmob) || (isdead(cmob) && C.holder)))
log_access("AFK: [key_name(C)]")
to_chat(C, "<span class='danger'>You have been inactive for more than [DisplayTimeText(config.afk_period)] and have been disconnected.</span>")
qdel(C)
if(round_started && kick_inactive && C.is_afk(afk_period))
var/cmob = C.mob
if(!(isobserver(cmob) || (isdead(cmob) && C.holder)))
log_access("AFK: [key_name(C)]")
to_chat(C, "<span class='danger'>You have been inactive for more than [DisplayTimeText(afk_period)] and have been disconnected.</span>")
qdel(C)
if (!(!C || world.time - C.connection_time < PING_BUFFER_TIME || C.inactivity >= (wait-1)))
winset(C, null, "command=.update_ping+[world.time+world.tick_lag*TICK_USAGE_REAL/100]")
@@ -40,7 +43,7 @@ SUBSYSTEM_DEF(server_maint)
/datum/controller/subsystem/server_maint/Shutdown()
kick_clients_in_lobby("<span class='boldannounce'>The round came to an end with you in the lobby.</span>", TRUE) //second parameter ensures only afk clients are kicked
var/server = config.server
var/server = CONFIG_GET(string/server)
for(var/thing in GLOB.clients)
if(!thing)
continue
+3 -3
View File
@@ -176,9 +176,9 @@ SUBSYSTEM_DEF(shuttle)
Good luck.")
return
emergency = backup_shuttle
if(world.time - SSticker.round_start_time < config.shuttle_refuel_delay)
to_chat(user, "The emergency shuttle is refueling. Please wait [DisplayTimeText((world.time - SSticker.round_start_time) - config.shuttle_refuel_delay)] before trying again.")
var/srd = CONFIG_GET(number/shuttle_refuel_delay)
if(world.time - SSticker.round_start_time < srd)
to_chat(user, "The emergency shuttle is refueling. Please wait [DisplayTimeText((world.time - SSticker.round_start_time) - srd)] before trying again.")
return
switch(emergency.mode)
+1 -1
View File
@@ -10,7 +10,7 @@ SUBSYSTEM_DEF(squeak)
var/list/exposed_wires = list()
/datum/controller/subsystem/squeak/Initialize(timeofday)
trigger_migration(config.mice_roundstart)
trigger_migration(CONFIG_GET(number/mice_roundstart))
return ..()
/datum/controller/subsystem/squeak/proc/trigger_migration(num_mice=10)
+10 -9
View File
@@ -79,13 +79,13 @@ SUBSYSTEM_DEF(ticker)
if(!GLOB.syndicate_code_response)
GLOB.syndicate_code_response = generate_code_phrase()
..()
start_at = world.time + (config.lobby_countdown * 10)
start_at = world.time + (CONFIG_GET(number/lobby_countdown) * 10)
/datum/controller/subsystem/ticker/fire()
switch(current_state)
if(GAME_STATE_STARTUP)
if(Master.initializations_finished_with_no_players_logged_in)
start_at = world.time + (config.lobby_countdown * 10)
start_at = world.time + (CONFIG_GET(number/lobby_countdown) * 10)
for(var/client/C in GLOB.clients)
window_flash(C, ignorepref = TRUE) //let them know lobby has opened up.
to_chat(world, "<span class='boldnotice'>Welcome to [station_name()]!</span>")
@@ -207,7 +207,7 @@ SUBSYSTEM_DEF(ticker)
else
mode.announce()
if(!config.ooc_during_round)
if(!CONFIG_GET(flag/ooc_during_round))
toggle_ooc(FALSE) // Turn it off
CHECK_TICK
@@ -429,7 +429,7 @@ SUBSYSTEM_DEF(ticker)
CHECK_TICK
if(config.cross_allowed)
if(CONFIG_GET(string/cross_server_address))
send_news_report()
CHECK_TICK
@@ -495,7 +495,8 @@ SUBSYSTEM_DEF(ticker)
to_chat(world, "<font color='purple'><b>Tip of the round: </b>[html_encode(m)]</font>")
/datum/controller/subsystem/ticker/proc/check_queue()
if(!queued_players.len || !config.hard_popcap)
var/hpc = CONFIG_GET(number/hard_popcap)
if(!queued_players.len || !hpc)
return
queue_delay++
@@ -503,7 +504,7 @@ SUBSYSTEM_DEF(ticker)
switch(queue_delay)
if(5) //every 5 ticks check if there is a slot available
if(living_player_count() < config.hard_popcap)
if(living_player_count() < hpc)
if(next_in_line && next_in_line.client)
to_chat(next_in_line, "<span class='userdanger'>A slot has opened! You have approximately 20 seconds to join. <a href='?src=\ref[next_in_line];late_join=override'>\>\>Join Game\<\<</a></span>")
SEND_SOUND(next_in_line, sound('sound/misc/notice1.ogg'))
@@ -517,7 +518,7 @@ SUBSYSTEM_DEF(ticker)
queue_delay = 0
/datum/controller/subsystem/ticker/proc/check_maprotate()
if (!config.maprotation)
if (!CONFIG_GET(flag/maprotation))
return
if (SSshuttle.emergency && SSshuttle.emergency.mode != SHUTTLE_ESCAPE || SSshuttle.canRecall())
return
@@ -527,7 +528,7 @@ SUBSYSTEM_DEF(ticker)
maprotatechecked = 1
//map rotate chance defaults to 75% of the length of the round (in minutes)
if (!prob((world.time/600)*config.maprotatechancedelta))
if (!prob((world.time/600)*CONFIG_GET(number/maprotatechancedelta)))
return
INVOKE_ASYNC(SSmapping, /datum/controller/subsystem/mapping/.proc/maprotate)
@@ -687,7 +688,7 @@ SUBSYSTEM_DEF(ticker)
return
if(!delay)
delay = config.round_end_countdown * 10
delay = CONFIG_GET(number/round_end_countdown) * 10
var/skip_delay = check_rights()
if(delay_end && !skip_delay)
+17 -14
View File
@@ -18,7 +18,7 @@ SUBSYSTEM_DEF(vote)
/datum/controller/subsystem/vote/fire() //called by master_controller
if(mode)
time_remaining = round((started_time + config.vote_period - world.time)/10)
time_remaining = round((started_time + CONFIG_GET(number/vote_period) - world.time)/10)
if(time_remaining < 0)
result()
@@ -54,7 +54,7 @@ SUBSYSTEM_DEF(vote)
if(votes > greatest_votes)
greatest_votes = votes
//default-vote for everyone who didn't vote
if(!config.vote_no_default && choices.len)
if(!CONFIG_GET(flag/default_no_vote) && choices.len)
var/list/non_voters = GLOB.directory.Copy()
non_voters -= voted
for (var/non_voter_ckey in non_voters)
@@ -146,7 +146,7 @@ SUBSYSTEM_DEF(vote)
/datum/controller/subsystem/vote/proc/submit_vote(vote)
if(mode)
if(config.vote_no_dead && usr.stat == DEAD && !usr.client.holder)
if(CONFIG_GET(flag/no_dead_vote) && usr.stat == DEAD && !usr.client.holder)
return 0
if(!(usr.ckey in voted))
if(vote && 1<=vote && vote<=choices.len)
@@ -158,7 +158,7 @@ SUBSYSTEM_DEF(vote)
/datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key)
if(!mode)
if(started_time)
var/next_allowed_time = (started_time + config.vote_delay)
var/next_allowed_time = (started_time + CONFIG_GET(number/vote_delay))
if(mode)
to_chat(usr, "<span class='warning'>There is already a vote in progress! please wait for it to finish.</span>")
return 0
@@ -198,8 +198,9 @@ SUBSYSTEM_DEF(vote)
if(mode == "custom")
text += "\n[question]"
log_vote(text)
to_chat(world, "\n<font color='purple'><b>[text]</b>\nType <b>vote</b> or click <a href='?src=\ref[src]'>here</a> to place your votes.\nYou have [DisplayTimeText(config.vote_period)] to vote.</font>")
time_remaining = round(config.vote_period/10)
var/vp = CONFIG_GET(number/vote_period)
to_chat(world, "\n<font color='purple'><b>[text]</b>\nType <b>vote</b> or click <a href='?src=\ref[src]'>here</a> to place your votes.\nYou have [DisplayTimeText(vp)] to vote.</font>")
time_remaining = round(vp/10)
for(var/c in GLOB.clients)
var/client/C = c
var/datum/action/vote/V = new
@@ -238,20 +239,22 @@ SUBSYSTEM_DEF(vote)
else
. += "<h2>Start a vote:</h2><hr><ul><li>"
//restart
if(trialmin || config.allow_vote_restart)
var/avr = CONFIG_GET(flag/allow_vote_restart)
if(trialmin || avr)
. += "<a href='?src=\ref[src];vote=restart'>Restart</a>"
else
. += "<font color='grey'>Restart (Disallowed)</font>"
if(trialmin)
. += "\t(<a href='?src=\ref[src];vote=toggle_restart'>[config.allow_vote_restart?"Allowed":"Disallowed"]</a>)"
. += "\t(<a href='?src=\ref[src];vote=toggle_restart'>[avr ? "Allowed" : "Disallowed"]</a>)"
. += "</li><li>"
//gamemode
if(trialmin || config.allow_vote_mode)
var/avm = CONFIG_GET(flag/allow_vote_mode)
if(trialmin || avm)
. += "<a href='?src=\ref[src];vote=gamemode'>GameMode</a>"
else
. += "<font color='grey'>GameMode (Disallowed)</font>"
if(trialmin)
. += "\t(<a href='?src=\ref[src];vote=toggle_gamemode'>[config.allow_vote_mode?"Allowed":"Disallowed"]</a>)"
. += "\t(<a href='?src=\ref[src];vote=toggle_gamemode'>[avm ? "Allowed" : "Disallowed"]</a>)"
. += "</li>"
//custom
@@ -275,15 +278,15 @@ SUBSYSTEM_DEF(vote)
reset()
if("toggle_restart")
if(usr.client.holder)
config.allow_vote_restart = !config.allow_vote_restart
CONFIG_SET(flag/allow_vote_restart, !CONFIG_GET(flag/allow_vote_restart))
if("toggle_gamemode")
if(usr.client.holder)
config.allow_vote_mode = !config.allow_vote_mode
CONFIG_SET(flag/allow_vote_mode, !CONFIG_GET(flag/allow_vote_mode))
if("restart")
if(config.allow_vote_restart || usr.client.holder)
if(CONFIG_GET(flag/allow_vote_restart) || usr.client.holder)
initiate_vote("restart",usr.key)
if("gamemode")
if(config.allow_vote_mode || usr.client.holder)
if(CONFIG_GET(flag/allow_vote_mode) || usr.client.holder)
initiate_vote("gamemode",usr.key)
if("custom")
if(usr.client.holder)
+7 -13
View File
@@ -208,7 +208,8 @@
/* General ai_law functions */
/datum/ai_laws/proc/set_laws_config()
switch(config.default_laws)
var/list/law_ids = CONFIG_GET(keyed_flag_list/random_laws)
switch(CONFIG_GET(number/default_laws))
if(0)
add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.")
add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.")
@@ -220,7 +221,7 @@
var/list/randlaws = list()
for(var/lpath in subtypesof(/datum/ai_laws))
var/datum/ai_laws/L = lpath
if(initial(L.id) in config.lawids)
if(initial(L.id) in law_ids)
randlaws += lpath
var/datum/ai_laws/lawtype
if(randlaws.len)
@@ -234,21 +235,14 @@
if(3)
pick_weighted_lawset()
else:
log_law("Invalid law config. Please check silicon_laws.txt")
add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.")
add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.")
add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.")
WARNING("Invalid custom AI laws, check silicon_laws.txt")
/datum/ai_laws/proc/pick_weighted_lawset()
var/datum/ai_laws/lawtype
while(!lawtype && config.law_weights.len)
var/possible_id = pickweight(config.law_weights)
var/list/law_weights = CONFIG_GET(keyed_number_list/law_weight)
while(!lawtype && law_weights)
var/possible_id = pickweight(law_weights)
lawtype = lawid_to_type(possible_id)
if(!lawtype)
config.law_weights -= possible_id
law_weights -= possible_id
WARNING("Bad lawid in game_options.txt: [possible_id]")
if(!lawtype)
+8 -14
View File
@@ -138,10 +138,11 @@
assign_exchange_role(SSticker.mode.exchange_red)
assign_exchange_role(SSticker.mode.exchange_blue)
objective_count += 1 //Exchange counts towards number of objectives
for(var/i = objective_count, i < config.traitor_objectives_amount, i++)
var/toa = CONFIG_GET(number/traitor_objectives_amount)
for(var/i = objective_count, i < toa, i++)
forge_single_objective()
if(is_hijacker && objective_count <= config.traitor_objectives_amount) //Don't assign hijack if it would exceed the number of objectives set in config.traitor_objectives_amount
if(is_hijacker && objective_count <= toa) //Don't assign hijack if it would exceed the number of objectives set in config.traitor_objectives_amount
if (!(locate(/datum/objective/hijack) in owner.objectives))
var/datum/objective/hijack/hijack_objective = new
hijack_objective.owner = owner
@@ -173,18 +174,11 @@
if(prob(30))
objective_count += forge_single_objective()
for(var/i = objective_count, i < config.traitor_objectives_amount, i++)
if(prob(20)) //AI's are less likely to look for a late-joiner than normal traitors
var/datum/objective/assassinate/late/late_objective = new
late_objective.owner = owner
late_objective.find_target()
add_objective(late_objective)
else
var/datum/objective/assassinate/kill_objective = new
kill_objective.owner = owner
kill_objective.find_target()
add_objective(kill_objective)
for(var/i = objective_count, i < CONFIG_GET(number/traitor_objectives_amount), i++)
var/datum/objective/assassinate/kill_objective = new
kill_objective.owner = owner
kill_objective.find_target()
add_objective(kill_objective)
var/datum/objective/survive/exist/exist_objective = new
exist_objective.owner = owner
+1 -1
View File
@@ -222,7 +222,7 @@
G.fields["name"] = H.real_name
G.fields["rank"] = assignment
G.fields["age"] = H.age
if(config.mutant_races)
if(CONFIG_GET(flag/join_with_mutant_race))
G.fields["species"] = H.dna.species.name
G.fields["fingerprint"] = md5(H.dna.uni_identity)
G.fields["p_stat"] = "Active"
+393 -401
View File
@@ -1,401 +1,393 @@
/////////////////////////// DNA DATUM
/datum/dna
var/unique_enzymes
var/struc_enzymes
var/uni_identity
var/blood_type
var/datum/species/species = new /datum/species/human() //The type of mutant race the player is if applicable (i.e. potato-man)
var/list/features = list("FFF") //first value is mutant color
var/real_name //Stores the real name of the person who originally got this dna datum. Used primarely for changelings,
var/list/mutations = list() //All mutations are from now on here
var/list/temporary_mutations = list() //Timers for temporary mutations
var/list/previous = list() //For temporary name/ui/ue/blood_type modifications
var/mob/living/holder
/datum/dna/New(mob/living/new_holder)
if(new_holder)
holder = new_holder
/datum/dna/proc/transfer_identity(mob/living/carbon/destination, transfer_SE = 0)
if(!istype(destination))
return
destination.dna.unique_enzymes = unique_enzymes
destination.dna.uni_identity = uni_identity
destination.dna.blood_type = blood_type
destination.set_species(species.type, icon_update=0)
destination.dna.features = features.Copy()
destination.dna.real_name = real_name
destination.dna.temporary_mutations = temporary_mutations.Copy()
if(transfer_SE)
destination.dna.struc_enzymes = struc_enzymes
if(ishuman(destination))
var/mob/living/carbon/human/H = destination
H.give_genitals(TRUE)//This gives the body the genitals of this DNA. Used for any transformations based on DNA
destination.flavor_text = destination.dna.features["flavor_text"] //Update the flavor_text to use new dna text
/datum/dna/proc/copy_dna(datum/dna/new_dna)
new_dna.unique_enzymes = unique_enzymes
new_dna.struc_enzymes = struc_enzymes
new_dna.uni_identity = uni_identity
new_dna.blood_type = blood_type
new_dna.features = features.Copy()
new_dna.species = new species.type
new_dna.real_name = real_name
new_dna.mutations = mutations.Copy()
/datum/dna/proc/add_mutation(mutation_name)
var/datum/mutation/human/HM = GLOB.mutations_list[mutation_name]
HM.on_acquiring(holder)
/datum/dna/proc/remove_mutation(mutation_name)
var/datum/mutation/human/HM = GLOB.mutations_list[mutation_name]
HM.on_losing(holder)
/datum/dna/proc/check_mutation(mutation_name)
var/datum/mutation/human/HM = GLOB.mutations_list[mutation_name]
return mutations.Find(HM)
/datum/dna/proc/remove_all_mutations()
remove_mutation_group(mutations)
/datum/dna/proc/remove_mutation_group(list/group)
if(!group)
return
for(var/datum/mutation/human/HM in group)
HM.force_lose(holder)
/datum/dna/proc/generate_uni_identity()
. = ""
var/list/L = new /list(DNA_UNI_IDENTITY_BLOCKS)
L[DNA_GENDER_BLOCK] = construct_block((holder.gender!=MALE)+1, 2)
if(ishuman(holder))
var/mob/living/carbon/human/H = holder
if(!GLOB.hair_styles_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/hair,GLOB.hair_styles_list, GLOB.hair_styles_male_list, GLOB.hair_styles_female_list)
L[DNA_HAIR_STYLE_BLOCK] = construct_block(GLOB.hair_styles_list.Find(H.hair_style), GLOB.hair_styles_list.len)
L[DNA_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.hair_color)
if(!GLOB.facial_hair_styles_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_hair, GLOB.facial_hair_styles_list, GLOB.facial_hair_styles_male_list, GLOB.facial_hair_styles_female_list)
L[DNA_FACIAL_HAIR_STYLE_BLOCK] = construct_block(GLOB.facial_hair_styles_list.Find(H.facial_hair_style), GLOB.facial_hair_styles_list.len)
L[DNA_FACIAL_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.facial_hair_color)
L[DNA_SKIN_TONE_BLOCK] = construct_block(GLOB.skin_tones.Find(H.skin_tone), GLOB.skin_tones.len)
L[DNA_EYE_COLOR_BLOCK] = sanitize_hexcolor(H.eye_color)
for(var/i=1, i<=DNA_UNI_IDENTITY_BLOCKS, i++)
if(L[i])
. += L[i]
else
. += random_string(DNA_BLOCK_SIZE,GLOB.hex_characters)
return .
/datum/dna/proc/generate_struc_enzymes()
var/list/sorting = new /list(DNA_STRUC_ENZYMES_BLOCKS)
var/result = ""
for(var/datum/mutation/human/A in GLOB.good_mutations + GLOB.bad_mutations + GLOB.not_good_mutations)
if(A.name == RACEMUT && ismonkey(holder))
sorting[A.dna_block] = num2hex(A.lowest_value + rand(0, 256 * 6), DNA_BLOCK_SIZE)
mutations |= A
else
sorting[A.dna_block] = random_string(DNA_BLOCK_SIZE, list("0","1","2","3","4","5","6"))
for(var/B in sorting)
result += B
return result
/datum/dna/proc/generate_unique_enzymes()
. = ""
if(istype(holder))
real_name = holder.real_name
. += md5(holder.real_name)
else
. += random_string(DNA_UNIQUE_ENZYMES_LEN, GLOB.hex_characters)
return .
/datum/dna/proc/update_ui_block(blocknumber)
if(!blocknumber || !ishuman(holder))
return
var/mob/living/carbon/human/H = holder
switch(blocknumber)
if(DNA_HAIR_COLOR_BLOCK)
setblock(uni_identity, blocknumber, sanitize_hexcolor(H.hair_color))
if(DNA_FACIAL_HAIR_COLOR_BLOCK)
setblock(uni_identity, blocknumber, sanitize_hexcolor(H.facial_hair_color))
if(DNA_SKIN_TONE_BLOCK)
setblock(uni_identity, blocknumber, construct_block(GLOB.skin_tones.Find(H.skin_tone), GLOB.skin_tones.len))
if(DNA_EYE_COLOR_BLOCK)
setblock(uni_identity, blocknumber, sanitize_hexcolor(H.eye_color))
if(DNA_GENDER_BLOCK)
setblock(uni_identity, blocknumber, construct_block((H.gender!=MALE)+1, 2))
if(DNA_FACIAL_HAIR_STYLE_BLOCK)
setblock(uni_identity, blocknumber, construct_block(GLOB.facial_hair_styles_list.Find(H.facial_hair_style), GLOB.facial_hair_styles_list.len))
if(DNA_HAIR_STYLE_BLOCK)
setblock(uni_identity, blocknumber, construct_block(GLOB.hair_styles_list.Find(H.hair_style), GLOB.hair_styles_list.len))
/datum/dna/proc/mutations_say_mods(message)
if(message)
for(var/datum/mutation/human/M in mutations)
message = M.say_mod(message)
return message
/datum/dna/proc/mutations_get_spans()
var/list/spans = list()
for(var/datum/mutation/human/M in mutations)
spans |= M.get_spans()
return spans
/datum/dna/proc/species_get_spans()
var/list/spans = list()
if(species)
spans |= species.get_spans()
return spans
/datum/dna/proc/is_same_as(datum/dna/D)
if(uni_identity == D.uni_identity && struc_enzymes == D.struc_enzymes && real_name == D.real_name)
if(species.type == D.species.type && features == D.features && blood_type == D.blood_type)
return 1
return 0
//used to update dna UI, UE, and dna.real_name.
/datum/dna/proc/update_dna_identity()
uni_identity = generate_uni_identity()
unique_enzymes = generate_unique_enzymes()
/datum/dna/proc/initialize_dna(newblood_type)
if(newblood_type)
blood_type = newblood_type
unique_enzymes = generate_unique_enzymes()
uni_identity = generate_uni_identity()
struc_enzymes = generate_struc_enzymes()
features = random_features()
/datum/dna/stored //subtype used by brain mob's stored_dna
/datum/dna/stored/add_mutation(mutation_name) //no mutation changes on stored dna.
return
/datum/dna/stored/remove_mutation(mutation_name)
return
/datum/dna/stored/check_mutation(mutation_name)
return
/datum/dna/stored/remove_all_mutations()
return
/datum/dna/stored/remove_mutation_group(list/group)
return
/////////////////////////// DNA MOB-PROCS //////////////////////
/mob/proc/set_species(datum/species/mrace, icon_update = 1)
return
/mob/living/brain/set_species(datum/species/mrace, icon_update = 1)
if(mrace)
if(ispath(mrace))
stored_dna.species = new mrace()
else
stored_dna.species = mrace //not calling any species update procs since we're a brain, not a monkey/human
/mob/living/carbon/set_species(datum/species/mrace, icon_update = 1)
if(mrace && has_dna())
dna.species.on_species_loss(src)
var/old_species = dna.species
if(ispath(mrace))
dna.species = new mrace()
else
dna.species = mrace
dna.species.on_species_gain(src, old_species)
/mob/living/carbon/human/set_species(datum/species/mrace, icon_update = 1)
..()
if(icon_update)
update_body()
update_hair()
update_body_parts()
update_mutations_overlay()// no lizard with human hulk overlay please.
/mob/proc/has_dna()
return
/mob/living/carbon/has_dna()
return dna
/mob/living/carbon/human/proc/hardset_dna(ui, se, newreal_name, newblood_type, datum/species/mrace, newfeatures)
if(newfeatures)
dna.features = newfeatures
flavor_text = dna.features["flavor_text"] //Update the flavor_text to use new dna text
if(mrace)
var/datum/species/newrace = new mrace.type
newrace.copy_properties_from(mrace)
set_species(newrace, icon_update=0)
if(newreal_name)
real_name = newreal_name
dna.generate_unique_enzymes()
if(newblood_type)
dna.blood_type = newblood_type
if(ui)
dna.uni_identity = ui
updateappearance(icon_update=0)
if(se)
dna.struc_enzymes = se
domutcheck()
give_genitals(TRUE)//Give all genitalia that DNA says you should have, remove any pre-existing ones as this is a hardset!
if(mrace || newfeatures || ui)
update_body()
update_hair()
update_body_parts()
update_mutations_overlay()
/mob/living/carbon/proc/create_dna()
dna = new /datum/dna(src)
if(!dna.species)
var/rando_race = pick(config.roundstart_races)
dna.species = new rando_race()
//proc used to update the mob's appearance after its dna UI has been changed
/mob/living/carbon/proc/updateappearance(icon_update=1, mutcolor_update=0, mutations_overlay_update=0)
if(!has_dna())
return
gender = (deconstruct_block(getblock(dna.uni_identity, DNA_GENDER_BLOCK), 2)-1) ? FEMALE : MALE
/mob/living/carbon/human/updateappearance(icon_update=1, mutcolor_update=0, mutations_overlay_update=0)
..()
var/structure = dna.uni_identity
hair_color = sanitize_hexcolor(getblock(structure, DNA_HAIR_COLOR_BLOCK))
facial_hair_color = sanitize_hexcolor(getblock(structure, DNA_FACIAL_HAIR_COLOR_BLOCK))
skin_tone = GLOB.skin_tones[deconstruct_block(getblock(structure, DNA_SKIN_TONE_BLOCK), GLOB.skin_tones.len)]
eye_color = sanitize_hexcolor(getblock(structure, DNA_EYE_COLOR_BLOCK))
facial_hair_style = GLOB.facial_hair_styles_list[deconstruct_block(getblock(structure, DNA_FACIAL_HAIR_STYLE_BLOCK), GLOB.facial_hair_styles_list.len)]
hair_style = GLOB.hair_styles_list[deconstruct_block(getblock(structure, DNA_HAIR_STYLE_BLOCK), GLOB.hair_styles_list.len)]
if(icon_update)
update_body()
update_hair()
if(mutcolor_update)
update_body_parts()
if(mutations_overlay_update)
update_mutations_overlay()
/mob/proc/domutcheck()
return
/mob/living/carbon/domutcheck(force_powers=0) //Set force_powers to 1 to bypass the power chance
if(!has_dna())
return
for(var/datum/mutation/human/A in GLOB.good_mutations | GLOB.bad_mutations | GLOB.not_good_mutations)
if(ismob(A.check_block(src, force_powers)))
return //we got monkeyized/humanized, this mob will be deleted, no need to continue.
update_mutations_overlay()
/////////////////////////// DNA HELPER-PROCS //////////////////////////////
/proc/getleftblocks(input,blocknumber,blocksize)
if(blocknumber > 1)
return copytext(input,1,((blocksize*blocknumber)-(blocksize-1)))
/proc/getrightblocks(input,blocknumber,blocksize)
if(blocknumber < (length(input)/blocksize))
return copytext(input,blocksize*blocknumber+1,length(input)+1)
/proc/getblock(input, blocknumber, blocksize=DNA_BLOCK_SIZE)
return copytext(input, blocksize*(blocknumber-1)+1, (blocksize*blocknumber)+1)
/proc/setblock(istring, blocknumber, replacement, blocksize=DNA_BLOCK_SIZE)
if(!istring || !blocknumber || !replacement || !blocksize)
return 0
return getleftblocks(istring, blocknumber, blocksize) + replacement + getrightblocks(istring, blocknumber, blocksize)
/mob/living/carbon/proc/randmut(list/candidates, difficulty = 2)
if(!has_dna())
return
var/datum/mutation/human/num = pick(candidates)
. = num.force_give(src)
/mob/living/carbon/proc/randmutb()
if(!has_dna())
return
var/datum/mutation/human/HM = pick((GLOB.bad_mutations | GLOB.not_good_mutations) - GLOB.mutations_list[RACEMUT])
. = HM.force_give(src)
/mob/living/carbon/proc/randmutg()
if(!has_dna())
return
var/datum/mutation/human/HM = pick(GLOB.good_mutations)
. = HM.force_give(src)
/mob/living/carbon/proc/randmutvg()
if(!has_dna())
return
var/datum/mutation/human/HM = pick((GLOB.good_mutations) - GLOB.mutations_list[HULK] - GLOB.mutations_list[DWARFISM])
. = HM.force_give(src)
/mob/living/carbon/proc/randmuti()
if(!has_dna())
return
var/num = rand(1, DNA_UNI_IDENTITY_BLOCKS)
var/newdna = setblock(dna.uni_identity, num, random_string(DNA_BLOCK_SIZE, GLOB.hex_characters))
dna.uni_identity = newdna
updateappearance(mutations_overlay_update=1)
/mob/living/carbon/proc/clean_dna()
if(!has_dna())
return
dna.remove_all_mutations()
/mob/living/carbon/proc/clean_randmut(list/candidates, difficulty = 2)
clean_dna()
randmut(candidates, difficulty)
/proc/scramble_dna(mob/living/carbon/M, ui=FALSE, se=FALSE, probability)
if(!M.has_dna())
return 0
if(se)
for(var/i=1, i<=DNA_STRUC_ENZYMES_BLOCKS, i++)
if(prob(probability))
M.dna.struc_enzymes = setblock(M.dna.struc_enzymes, i, random_string(DNA_BLOCK_SIZE, GLOB.hex_characters))
M.domutcheck()
if(ui)
for(var/i=1, i<=DNA_UNI_IDENTITY_BLOCKS, i++)
if(prob(probability))
M.dna.uni_identity = setblock(M.dna.uni_identity, i, random_string(DNA_BLOCK_SIZE, GLOB.hex_characters))
M.updateappearance(mutations_overlay_update=1)
return 1
//value in range 1 to values. values must be greater than 0
//all arguments assumed to be positive integers
/proc/construct_block(value, values, blocksize=DNA_BLOCK_SIZE)
var/width = round((16**blocksize)/values)
if(value < 1)
value = 1
value = (value * width) - rand(1,width)
return num2hex(value, blocksize)
//value is hex
/proc/deconstruct_block(value, values, blocksize=DNA_BLOCK_SIZE)
var/width = round((16**blocksize)/values)
value = round(hex2num(value) / width) + 1
if(value > values)
value = values
return value
/////////////////////////// DNA HELPER-PROCS
/////////////////////////// DNA DATUM
/datum/dna
var/unique_enzymes
var/struc_enzymes
var/uni_identity
var/blood_type
var/datum/species/species = new /datum/species/human() //The type of mutant race the player is if applicable (i.e. potato-man)
var/list/features = list("FFF") //first value is mutant color
var/real_name //Stores the real name of the person who originally got this dna datum. Used primarely for changelings,
var/list/mutations = list() //All mutations are from now on here
var/list/temporary_mutations = list() //Timers for temporary mutations
var/list/previous = list() //For temporary name/ui/ue/blood_type modifications
var/mob/living/holder
/datum/dna/New(mob/living/new_holder)
if(new_holder)
holder = new_holder
/datum/dna/proc/transfer_identity(mob/living/carbon/destination, transfer_SE = 0)
if(!istype(destination))
return
destination.dna.unique_enzymes = unique_enzymes
destination.dna.uni_identity = uni_identity
destination.dna.blood_type = blood_type
destination.set_species(species.type, icon_update=0)
destination.dna.features = features.Copy()
destination.dna.real_name = real_name
destination.dna.temporary_mutations = temporary_mutations.Copy()
if(transfer_SE)
destination.dna.struc_enzymes = struc_enzymes
/datum/dna/proc/copy_dna(datum/dna/new_dna)
new_dna.unique_enzymes = unique_enzymes
new_dna.struc_enzymes = struc_enzymes
new_dna.uni_identity = uni_identity
new_dna.blood_type = blood_type
new_dna.features = features.Copy()
new_dna.species = new species.type
new_dna.real_name = real_name
new_dna.mutations = mutations.Copy()
/datum/dna/proc/add_mutation(mutation_name)
var/datum/mutation/human/HM = GLOB.mutations_list[mutation_name]
HM.on_acquiring(holder)
/datum/dna/proc/remove_mutation(mutation_name)
var/datum/mutation/human/HM = GLOB.mutations_list[mutation_name]
HM.on_losing(holder)
/datum/dna/proc/check_mutation(mutation_name)
var/datum/mutation/human/HM = GLOB.mutations_list[mutation_name]
return mutations.Find(HM)
/datum/dna/proc/remove_all_mutations()
remove_mutation_group(mutations)
/datum/dna/proc/remove_mutation_group(list/group)
if(!group)
return
for(var/datum/mutation/human/HM in group)
HM.force_lose(holder)
/datum/dna/proc/generate_uni_identity()
. = ""
var/list/L = new /list(DNA_UNI_IDENTITY_BLOCKS)
L[DNA_GENDER_BLOCK] = construct_block((holder.gender!=MALE)+1, 2)
if(ishuman(holder))
var/mob/living/carbon/human/H = holder
if(!GLOB.hair_styles_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/hair,GLOB.hair_styles_list, GLOB.hair_styles_male_list, GLOB.hair_styles_female_list)
L[DNA_HAIR_STYLE_BLOCK] = construct_block(GLOB.hair_styles_list.Find(H.hair_style), GLOB.hair_styles_list.len)
L[DNA_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.hair_color)
if(!GLOB.facial_hair_styles_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_hair, GLOB.facial_hair_styles_list, GLOB.facial_hair_styles_male_list, GLOB.facial_hair_styles_female_list)
L[DNA_FACIAL_HAIR_STYLE_BLOCK] = construct_block(GLOB.facial_hair_styles_list.Find(H.facial_hair_style), GLOB.facial_hair_styles_list.len)
L[DNA_FACIAL_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.facial_hair_color)
L[DNA_SKIN_TONE_BLOCK] = construct_block(GLOB.skin_tones.Find(H.skin_tone), GLOB.skin_tones.len)
L[DNA_EYE_COLOR_BLOCK] = sanitize_hexcolor(H.eye_color)
for(var/i=1, i<=DNA_UNI_IDENTITY_BLOCKS, i++)
if(L[i])
. += L[i]
else
. += random_string(DNA_BLOCK_SIZE,GLOB.hex_characters)
return .
/datum/dna/proc/generate_struc_enzymes()
var/list/sorting = new /list(DNA_STRUC_ENZYMES_BLOCKS)
var/result = ""
for(var/datum/mutation/human/A in GLOB.good_mutations + GLOB.bad_mutations + GLOB.not_good_mutations)
if(A.name == RACEMUT && ismonkey(holder))
sorting[A.dna_block] = num2hex(A.lowest_value + rand(0, 256 * 6), DNA_BLOCK_SIZE)
mutations |= A
else
sorting[A.dna_block] = random_string(DNA_BLOCK_SIZE, list("0","1","2","3","4","5","6"))
for(var/B in sorting)
result += B
return result
/datum/dna/proc/generate_unique_enzymes()
. = ""
if(istype(holder))
real_name = holder.real_name
. += md5(holder.real_name)
else
. += random_string(DNA_UNIQUE_ENZYMES_LEN, GLOB.hex_characters)
return .
/datum/dna/proc/update_ui_block(blocknumber)
if(!blocknumber || !ishuman(holder))
return
var/mob/living/carbon/human/H = holder
switch(blocknumber)
if(DNA_HAIR_COLOR_BLOCK)
setblock(uni_identity, blocknumber, sanitize_hexcolor(H.hair_color))
if(DNA_FACIAL_HAIR_COLOR_BLOCK)
setblock(uni_identity, blocknumber, sanitize_hexcolor(H.facial_hair_color))
if(DNA_SKIN_TONE_BLOCK)
setblock(uni_identity, blocknumber, construct_block(GLOB.skin_tones.Find(H.skin_tone), GLOB.skin_tones.len))
if(DNA_EYE_COLOR_BLOCK)
setblock(uni_identity, blocknumber, sanitize_hexcolor(H.eye_color))
if(DNA_GENDER_BLOCK)
setblock(uni_identity, blocknumber, construct_block((H.gender!=MALE)+1, 2))
if(DNA_FACIAL_HAIR_STYLE_BLOCK)
setblock(uni_identity, blocknumber, construct_block(GLOB.facial_hair_styles_list.Find(H.facial_hair_style), GLOB.facial_hair_styles_list.len))
if(DNA_HAIR_STYLE_BLOCK)
setblock(uni_identity, blocknumber, construct_block(GLOB.hair_styles_list.Find(H.hair_style), GLOB.hair_styles_list.len))
/datum/dna/proc/mutations_say_mods(message)
if(message)
for(var/datum/mutation/human/M in mutations)
message = M.say_mod(message)
return message
/datum/dna/proc/mutations_get_spans()
var/list/spans = list()
for(var/datum/mutation/human/M in mutations)
spans |= M.get_spans()
return spans
/datum/dna/proc/species_get_spans()
var/list/spans = list()
if(species)
spans |= species.get_spans()
return spans
/datum/dna/proc/is_same_as(datum/dna/D)
if(uni_identity == D.uni_identity && struc_enzymes == D.struc_enzymes && real_name == D.real_name)
if(species.type == D.species.type && features == D.features && blood_type == D.blood_type)
return 1
return 0
//used to update dna UI, UE, and dna.real_name.
/datum/dna/proc/update_dna_identity()
uni_identity = generate_uni_identity()
unique_enzymes = generate_unique_enzymes()
/datum/dna/proc/initialize_dna(newblood_type)
if(newblood_type)
blood_type = newblood_type
unique_enzymes = generate_unique_enzymes()
uni_identity = generate_uni_identity()
struc_enzymes = generate_struc_enzymes()
features = random_features()
/datum/dna/stored //subtype used by brain mob's stored_dna
/datum/dna/stored/add_mutation(mutation_name) //no mutation changes on stored dna.
return
/datum/dna/stored/remove_mutation(mutation_name)
return
/datum/dna/stored/check_mutation(mutation_name)
return
/datum/dna/stored/remove_all_mutations()
return
/datum/dna/stored/remove_mutation_group(list/group)
return
/////////////////////////// DNA MOB-PROCS //////////////////////
/mob/proc/set_species(datum/species/mrace, icon_update = 1)
return
/mob/living/brain/set_species(datum/species/mrace, icon_update = 1)
if(mrace)
if(ispath(mrace))
stored_dna.species = new mrace()
else
stored_dna.species = mrace //not calling any species update procs since we're a brain, not a monkey/human
/mob/living/carbon/set_species(datum/species/mrace, icon_update = 1)
if(mrace && has_dna())
dna.species.on_species_loss(src)
var/old_species = dna.species
if(ispath(mrace))
dna.species = new mrace()
else
dna.species = mrace
dna.species.on_species_gain(src, old_species)
/mob/living/carbon/human/set_species(datum/species/mrace, icon_update = 1)
..()
if(icon_update)
update_body()
update_hair()
update_body_parts()
update_mutations_overlay()// no lizard with human hulk overlay please.
/mob/proc/has_dna()
return
/mob/living/carbon/has_dna()
return dna
/mob/living/carbon/human/proc/hardset_dna(ui, se, newreal_name, newblood_type, datum/species/mrace, newfeatures)
if(newfeatures)
dna.features = newfeatures
if(mrace)
var/datum/species/newrace = new mrace.type
newrace.copy_properties_from(mrace)
set_species(newrace, icon_update=0)
if(newreal_name)
real_name = newreal_name
dna.generate_unique_enzymes()
if(newblood_type)
dna.blood_type = newblood_type
if(ui)
dna.uni_identity = ui
updateappearance(icon_update=0)
if(se)
dna.struc_enzymes = se
domutcheck()
if(mrace || newfeatures || ui)
update_body()
update_hair()
update_body_parts()
update_mutations_overlay()
/mob/living/carbon/proc/create_dna()
dna = new /datum/dna(src)
if(!dna.species)
var/rando_race = pick(CONFIG_GET(keyed_flag_list/roundstart_races))
dna.species = new rando_race()
//proc used to update the mob's appearance after its dna UI has been changed
/mob/living/carbon/proc/updateappearance(icon_update=1, mutcolor_update=0, mutations_overlay_update=0)
if(!has_dna())
return
gender = (deconstruct_block(getblock(dna.uni_identity, DNA_GENDER_BLOCK), 2)-1) ? FEMALE : MALE
/mob/living/carbon/human/updateappearance(icon_update=1, mutcolor_update=0, mutations_overlay_update=0)
..()
var/structure = dna.uni_identity
hair_color = sanitize_hexcolor(getblock(structure, DNA_HAIR_COLOR_BLOCK))
facial_hair_color = sanitize_hexcolor(getblock(structure, DNA_FACIAL_HAIR_COLOR_BLOCK))
skin_tone = GLOB.skin_tones[deconstruct_block(getblock(structure, DNA_SKIN_TONE_BLOCK), GLOB.skin_tones.len)]
eye_color = sanitize_hexcolor(getblock(structure, DNA_EYE_COLOR_BLOCK))
facial_hair_style = GLOB.facial_hair_styles_list[deconstruct_block(getblock(structure, DNA_FACIAL_HAIR_STYLE_BLOCK), GLOB.facial_hair_styles_list.len)]
hair_style = GLOB.hair_styles_list[deconstruct_block(getblock(structure, DNA_HAIR_STYLE_BLOCK), GLOB.hair_styles_list.len)]
if(icon_update)
update_body()
update_hair()
if(mutcolor_update)
update_body_parts()
if(mutations_overlay_update)
update_mutations_overlay()
/mob/proc/domutcheck()
return
/mob/living/carbon/domutcheck(force_powers=0) //Set force_powers to 1 to bypass the power chance
if(!has_dna())
return
for(var/datum/mutation/human/A in GLOB.good_mutations | GLOB.bad_mutations | GLOB.not_good_mutations)
if(ismob(A.check_block(src, force_powers)))
return //we got monkeyized/humanized, this mob will be deleted, no need to continue.
update_mutations_overlay()
/////////////////////////// DNA HELPER-PROCS //////////////////////////////
/proc/getleftblocks(input,blocknumber,blocksize)
if(blocknumber > 1)
return copytext(input,1,((blocksize*blocknumber)-(blocksize-1)))
/proc/getrightblocks(input,blocknumber,blocksize)
if(blocknumber < (length(input)/blocksize))
return copytext(input,blocksize*blocknumber+1,length(input)+1)
/proc/getblock(input, blocknumber, blocksize=DNA_BLOCK_SIZE)
return copytext(input, blocksize*(blocknumber-1)+1, (blocksize*blocknumber)+1)
/proc/setblock(istring, blocknumber, replacement, blocksize=DNA_BLOCK_SIZE)
if(!istring || !blocknumber || !replacement || !blocksize)
return 0
return getleftblocks(istring, blocknumber, blocksize) + replacement + getrightblocks(istring, blocknumber, blocksize)
/mob/living/carbon/proc/randmut(list/candidates, difficulty = 2)
if(!has_dna())
return
var/datum/mutation/human/num = pick(candidates)
. = num.force_give(src)
/mob/living/carbon/proc/randmutb()
if(!has_dna())
return
var/datum/mutation/human/HM = pick((GLOB.bad_mutations | GLOB.not_good_mutations) - GLOB.mutations_list[RACEMUT])
. = HM.force_give(src)
/mob/living/carbon/proc/randmutg()
if(!has_dna())
return
var/datum/mutation/human/HM = pick(GLOB.good_mutations)
. = HM.force_give(src)
/mob/living/carbon/proc/randmutvg()
if(!has_dna())
return
var/datum/mutation/human/HM = pick((GLOB.good_mutations) - GLOB.mutations_list[HULK] - GLOB.mutations_list[DWARFISM])
. = HM.force_give(src)
/mob/living/carbon/proc/randmuti()
if(!has_dna())
return
var/num = rand(1, DNA_UNI_IDENTITY_BLOCKS)
var/newdna = setblock(dna.uni_identity, num, random_string(DNA_BLOCK_SIZE, GLOB.hex_characters))
dna.uni_identity = newdna
updateappearance(mutations_overlay_update=1)
/mob/living/carbon/proc/clean_dna()
if(!has_dna())
return
dna.remove_all_mutations()
/mob/living/carbon/proc/clean_randmut(list/candidates, difficulty = 2)
clean_dna()
randmut(candidates, difficulty)
/proc/scramble_dna(mob/living/carbon/M, ui=FALSE, se=FALSE, probability)
if(!M.has_dna())
return 0
if(se)
for(var/i=1, i<=DNA_STRUC_ENZYMES_BLOCKS, i++)
if(prob(probability))
M.dna.struc_enzymes = setblock(M.dna.struc_enzymes, i, random_string(DNA_BLOCK_SIZE, GLOB.hex_characters))
M.domutcheck()
if(ui)
for(var/i=1, i<=DNA_UNI_IDENTITY_BLOCKS, i++)
if(prob(probability))
M.dna.uni_identity = setblock(M.dna.uni_identity, i, random_string(DNA_BLOCK_SIZE, GLOB.hex_characters))
M.updateappearance(mutations_overlay_update=1)
return 1
//value in range 1 to values. values must be greater than 0
//all arguments assumed to be positive integers
/proc/construct_block(value, values, blocksize=DNA_BLOCK_SIZE)
var/width = round((16**blocksize)/values)
if(value < 1)
value = 1
value = (value * width) - rand(1,width)
return num2hex(value, blocksize)
//value is hex
/proc/deconstruct_block(value, values, blocksize=DNA_BLOCK_SIZE)
var/width = round((16**blocksize)/values)
value = round(hex2num(value) / width) + 1
if(value > values)
value = values
return value
/////////////////////////// DNA HELPER-PROCS
+1 -1
View File
@@ -140,7 +140,7 @@ GLOBAL_LIST_EMPTY(explosions)
var/list/exploded_this_tick = list() //open turfs that need to be blocked off while we sleep
var/list/affected_turfs = GatherSpiralTurfs(max_range, epicenter)
var/reactionary = config.reactionary_explosions
var/reactionary = CONFIG_GET(flag/reactionary_explosions)
var/list/cached_exp_block
if(reactionary)
+25 -24
View File
@@ -47,19 +47,17 @@
else
log_world(originmastercommit)
/datum/getrev/proc/DownloadPRDetails()
if(!config.githubrepoid)
var/repo_id = CONFIG_GET(number/githubrepoid)
if(!repo_id)
if(testmerge.len)
log_world("PR details download failed: No github repo config set")
return
if(!isnum(text2num(config.githubrepoid)))
log_world("PR details download failed: Invalid github repo id: [config.githubrepoid]")
return
for(var/line in testmerge)
if(!isnum(text2num(line)))
log_world("PR details download failed: Invalid PR number: [line]")
return
var/url = "https://api.github.com/repositories/[config.githubrepoid]/pulls/[line].json"
var/url = "https://api.github.com/repositories/[repo_id]/pulls/[line].json"
GLOB.valid_HTTPSGet = TRUE
var/json = HTTPSGet(url)
if(!json)
@@ -87,7 +85,7 @@
details = ": '" + html_encode(testmerge[line]["title"]) + "' by " + html_encode(testmerge[line]["user"]["login"])
if(details && findtext(details, "\[s\]") && (!usr || !usr.client.holder))
continue
. += "<a href=\"[config.githuburl]/pull/[line]\">#[line][details]</a><br>"
. += "<a href=\"[CONFIG_GET(string/githuburl)]/pull/[line]\">#[line][details]</a><br>"
/client/verb/showrevinfo()
set category = "OOC"
@@ -101,44 +99,47 @@
to_chat(src, GLOB.revdata.GetTestMergeInfo())
prefix = "Based off origin/master commit: "
var/pc = GLOB.revdata.originmastercommit
to_chat(src, "[prefix]<a href=\"[config.githuburl]/commit/[pc]\">[copytext(pc, 1, min(length(pc), 7))]</a>")
to_chat(src, "[prefix]<a href=\"[CONFIG_GET(string/githuburl)]/commit/[pc]\">[copytext(pc, 1, min(length(pc), 7))]</a>")
else
to_chat(src, "Revision unknown")
to_chat(src, "<b>Current Informational Settings:</b>")
to_chat(src, "Protect Authority Roles From Traitor: [config.protect_roles_from_antagonist]")
to_chat(src, "Protect Assistant Role From Traitor: [config.protect_assistant_from_antagonist]")
to_chat(src, "Enforce Human Authority: [config.enforce_human_authority]")
to_chat(src, "Allow Latejoin Antagonists: [config.allow_latejoin_antagonists]")
to_chat(src, "Enforce Continuous Rounds: [config.continuous.len] of [config.modes.len] roundtypes")
to_chat(src, "Allow Midround Antagonists: [config.midround_antag.len] of [config.modes.len] roundtypes")
if(config.show_game_type_odds)
to_chat(src, "Protect Authority Roles From Traitor: [CONFIG_GET(flag/protect_roles_from_antagonist)]")
to_chat(src, "Protect Assistant Role From Traitor: [CONFIG_GET(flag/protect_assistant_from_antagonist)]")
to_chat(src, "Enforce Human Authority: [CONFIG_GET(flag/enforce_human_authority)]")
to_chat(src, "Allow Latejoin Antagonists: [CONFIG_GET(flag/allow_latejoin_antagonists)]")
to_chat(src, "Enforce Continuous Rounds: [length(CONFIG_GET(keyed_flag_list/continuous))] of [config.modes.len] roundtypes")
to_chat(src, "Allow Midround Antagonists: [length(CONFIG_GET(keyed_flag_list/midround_antag))] of [config.modes.len] roundtypes")
if(CONFIG_GET(flag/show_game_type_odds))
var/list/probabilities = CONFIG_GET(keyed_number_list/probability)
if(SSticker.IsRoundInProgress())
var/prob_sum = 0
var/current_odds_differ = FALSE
var/list/probs = list()
var/list/modes = config.gamemode_cache
var/list/min_pop = CONFIG_GET(keyed_number_list/min_pop)
var/list/max_pop = CONFIG_GET(keyed_number_list/max_pop)
for(var/mode in modes)
var/datum/game_mode/M = mode
var/ctag = initial(M.config_tag)
if(!(ctag in config.probabilities))
if(!(ctag in probabilities))
continue
if((config.min_pop[ctag] && (config.min_pop[ctag] > SSticker.totalPlayersReady)) || (config.max_pop[ctag] && (config.max_pop[ctag] < SSticker.totalPlayersReady)) || (initial(M.required_players) > SSticker.totalPlayersReady))
if((min_pop[ctag] && (min_pop[ctag] > SSticker.totalPlayersReady)) || (max_pop[ctag] && (max_pop[ctag] < SSticker.totalPlayersReady)) || (initial(M.required_players) > SSticker.totalPlayersReady))
current_odds_differ = TRUE
continue
probs[ctag] = 1
prob_sum += config.probabilities[ctag]
prob_sum += probabilities[ctag]
if(current_odds_differ)
to_chat(src, "<b>Game Mode Odds for current round:</b>")
for(var/ctag in probs)
if(config.probabilities[ctag] > 0)
var/percentage = round(config.probabilities[ctag] / prob_sum * 100, 0.1)
if(probabilities[ctag] > 0)
var/percentage = round(probabilities[ctag] / prob_sum * 100, 0.1)
to_chat(src, "[ctag] [percentage]%")
to_chat(src, "<b>All Game Mode Odds:</b>")
var/sum = 0
for(var/ctag in config.probabilities)
sum += config.probabilities[ctag]
for(var/ctag in config.probabilities)
if(config.probabilities[ctag] > 0)
var/percentage = round(config.probabilities[ctag] / sum * 100, 0.1)
for(var/ctag in probabilities)
sum += probabilities[ctag]
for(var/ctag in probabilities)
if(probabilities[ctag] > 0)
var/percentage = round(probabilities[ctag] / sum * 100, 0.1)
to_chat(src, "[ctag] [percentage]%")
+1 -1
View File
@@ -118,7 +118,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
else if(dynamic_lighting != DYNAMIC_LIGHTING_IFSTARLIGHT)
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
if(dynamic_lighting == DYNAMIC_LIGHTING_IFSTARLIGHT)
dynamic_lighting = config.starlight ? DYNAMIC_LIGHTING_ENABLED : DYNAMIC_LIGHTING_DISABLED
dynamic_lighting = CONFIG_GET(flag/starlight) ? DYNAMIC_LIGHTING_ENABLED : DYNAMIC_LIGHTING_DISABLED
. = ..()
+1 -1
View File
@@ -7,7 +7,7 @@
if(B.blob_core || !B.placed)
return 0
if(!GLOB.blob_cores.len) //blob is dead
if(config.continuous["blob"])
if(CONFIG_GET(keyed_flag_list/continuous)["blob"])
message_sent = FALSE //disable the win count at this point
continuous_sanity_checked = 1 //Nonstandard definition of "alive" gets past the check otherwise
SSshuttle.clearHostileEnvironment(src)
+6 -5
View File
@@ -17,7 +17,7 @@
/datum/objective_team/brother_team/proc/forge_brother_objectives()
objectives = list()
var/is_hijacker = prob(10)
for(var/i = 1 to max(1, config.brother_objectives_amount + (members.len > 2) - is_hijacker))
for(var/i = 1 to max(1, CONFIG_GET(number/brother_objectives_amount) + (members.len > 2) - is_hijacker))
forge_single_objective()
if(is_hijacker)
if(!locate(/datum/objective/hijack) in objectives)
@@ -58,16 +58,17 @@
var/meeting_areas = list("The Bar", "Dorms", "Escape Dock", "Arrivals", "Holodeck", "Primary Tool Storage", "Recreation Area", "Chapel", "Library")
/datum/game_mode/traitor/bros/pre_setup()
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/list/datum/mind/possible_brothers = get_players_for_role(ROLE_BROTHER)
var/num_teams = team_amount
if(config.brother_scaling_coeff)
num_teams = max(1, round(num_players()/config.brother_scaling_coeff))
var/bsc = CONFIG_GET(number/brother_scaling_coeff)
if(bsc)
num_teams = max(1, round(num_players() / bsc))
for(var/j = 1 to num_teams)
if(possible_brothers.len < min_team_size || antag_candidates.len <= required_enemies)
+8 -6
View File
@@ -52,16 +52,17 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
/datum/game_mode/changeling/pre_setup()
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/num_changelings = 1
if(config.changeling_scaling_coeff)
num_changelings = max(1, min( round(num_players()/(config.changeling_scaling_coeff*2))+2, round(num_players()/config.changeling_scaling_coeff) ))
var/csc = CONFIG_GET(number/changeling_scaling_coeff)
if(csc)
num_changelings = max(1, min(round(num_players() / (csc * 2)) + 2, round(num_players() / csc)))
else
num_changelings = max(1, min(num_players(), changeling_amount))
@@ -102,10 +103,11 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
..()
/datum/game_mode/changeling/make_antag_chance(mob/living/carbon/human/character) //Assigns changeling to latejoiners
var/changelingcap = min( round(GLOB.joined_player_list.len/(config.changeling_scaling_coeff*2))+2, round(GLOB.joined_player_list.len/config.changeling_scaling_coeff) )
var/csc = CONFIG_GET(number/changeling_scaling_coeff)
var/changelingcap = min(round(GLOB.joined_player_list.len / (csc * 2)) + 2, round(GLOB.joined_player_list.len / csc))
if(SSticker.mode.changelings.len >= changelingcap) //Caps number of latejoin antagonists
return
if(SSticker.mode.changelings.len <= (changelingcap - 2) || prob(100 - (config.changeling_scaling_coeff*2)))
if(SSticker.mode.changelings.len <= (changelingcap - 2) || prob(100 - (csc * 2)))
if(ROLE_CHANGELING in character.client.prefs.be_special)
if(!jobban_isbanned(character, ROLE_CHANGELING) && !jobban_isbanned(character, "Syndicate"))
if(age_check(character.client))
@@ -25,18 +25,19 @@
return 1
/datum/game_mode/traitor/changeling/pre_setup()
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/list/datum/mind/possible_changelings = get_players_for_role(ROLE_CHANGELING)
var/num_changelings = 1
if(config.changeling_scaling_coeff)
num_changelings = max(1, min( round(num_players()/(config.changeling_scaling_coeff*4))+2, round(num_players()/(config.changeling_scaling_coeff*2)) ))
var/csc = CONFIG_GET(number/changeling_scaling_coeff)
if(csc)
num_changelings = max(1, min(round(num_players() / (csc * 4)) + 2, round(num_players() / (csc * 2))))
else
num_changelings = max(1, min(num_players(), changeling_amount/2))
@@ -64,11 +65,12 @@
return
/datum/game_mode/traitor/changeling/make_antag_chance(mob/living/carbon/human/character) //Assigns changeling to latejoiners
var/changelingcap = min( round(GLOB.joined_player_list.len/(config.changeling_scaling_coeff*4))+2, round(GLOB.joined_player_list.len/(config.changeling_scaling_coeff*2)) )
var/csc = CONFIG_GET(number/changeling_scaling_coeff)
var/changelingcap = min( round(GLOB.joined_player_list.len / (csc * 4)) + 2, round(GLOB.joined_player_list.len / (csc * 2)))
if(SSticker.mode.changelings.len >= changelingcap) //Caps number of latejoin antagonists
..()
return
if(SSticker.mode.changelings.len <= (changelingcap - 2) || prob(100 / (config.changeling_scaling_coeff * 4)))
if(SSticker.mode.changelings.len <= (changelingcap - 2) || prob(100 / (csc * 4)))
if(ROLE_CHANGELING in character.client.prefs.be_special)
if(!jobban_isbanned(character, ROLE_CHANGELING) && !jobban_isbanned(character, "Syndicate"))
if(age_check(character.client))
+2 -2
View File
@@ -107,9 +107,9 @@ Credit where due:
var/ark_time //In minutes, how long the Ark waits before activation; this is equal to 30 + (number of players / 5) (max 40 mins.)
/datum/game_mode/clockwork_cult/pre_setup()
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/starter_servants = 4 //Guaranteed four servants
var/number_players = num_players()
+2 -2
View File
@@ -55,10 +55,10 @@
/datum/game_mode/cult/pre_setup()
cult_objectives += "sacrifice"
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
//cult scaling goes here
+5 -4
View File
@@ -20,15 +20,16 @@
+ <span class='notice'>Crew</span>: Resist the lure of sin and remain pure!"
/datum/game_mode/devil/pre_setup()
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/num_devils = 1
if(config.traitor_scaling_coeff)
num_devils = max(minimum_devils, min( round(num_players()/(config.traitor_scaling_coeff*3))+ 2 + num_modifier, round(num_players()/(config.traitor_scaling_coeff*1.5)) + num_modifier ))
var/tsc = CONFIG_GET(number/traitor_scaling_coeff)
if(tsc)
num_devils = max(minimum_devils, min( round(num_players() / (tsc * 3))+ 2 + num_modifier, round(num_players() / (tsc * 1.5)) + num_modifier))
else
num_devils = max(minimum_devils, min(num_players(), traitors_possible))
+18 -14
View File
@@ -78,7 +78,7 @@
///Everyone should now be on the station and have their normal gear. This is the place to give the special roles extra things
/datum/game_mode/proc/post_setup(report) //Gamemodes can override the intercept report. Passing TRUE as the argument will force a report.
if(!report)
report = config.intercept
report = !CONFIG_GET(flag/no_intercept_report)
addtimer(CALLBACK(GLOBAL_PROC, .proc/display_roundstart_logout_report), ROUNDSTART_LOGOUT_REPORT_TIME)
if(SSdbcore.Connect())
@@ -113,8 +113,9 @@
for(var/mob/Player in GLOB.mob_list)
if(Player.mind && Player.stat != DEAD && !isnewplayer(Player) && !isbrain(Player) && Player.client)
living_crew += Player
if(living_crew.len / GLOB.joined_player_list.len <= config.midround_antag_life_check) //If a lot of the player base died, we start fresh
message_admins("Convert_roundtype failed due to too many dead people. Limit is [config.midround_antag_life_check * 100]% living crew")
var/malc = CONFIG_GET(number/midround_antag_life_check)
if(living_crew.len / GLOB.joined_player_list.len <= malc) //If a lot of the player base died, we start fresh
message_admins("Convert_roundtype failed due to too many dead people. Limit is [malc * 100]% living crew")
return null
var/list/datum/game_mode/runnable_modes = config.get_runnable_midround_modes(living_crew.len)
@@ -138,8 +139,9 @@
if(SSshuttle.emergency.timeLeft(1) < initial(SSshuttle.emergencyCallTime)*0.5)
return 1
if(world.time >= (config.midround_antag_time_check * 600))
message_admins("Convert_roundtype failed due to round length. Limit is [config.midround_antag_time_check] minutes.")
var/matc = CONFIG_GET(number/midround_antag_time_check)
if(world.time >= (matc * 600))
message_admins("Convert_roundtype failed due to round length. Limit is [matc] minutes.")
return null
var/list/antag_candidates = list()
@@ -154,9 +156,9 @@
antag_candidates = shuffle(antag_candidates)
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
replacementmode.restricted_jobs += replacementmode.protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
replacementmode.restricted_jobs += "Assistant"
message_admins("The roundtype will be converted. If you have other plans for the station or feel the station is too messed up to inhabit <A HREF='?_src_=holder;[HrefToken()];toggle_midround_antag=\ref[usr]'>stop the creation of antags</A> or <A HREF='?_src_=holder;[HrefToken()];end_round=\ref[usr]'>end the round now</A>.")
@@ -168,7 +170,7 @@
round_converted = 0
return
//somewhere between 1 and 3 minutes from now
if(!config.midround_antag[SSticker.mode.config_tag])
if(!CONFIG_GET(keyed_flag_list/midround_antag)[SSticker.mode.config_tag])
round_converted = 0
return 1
for(var/mob/living/carbon/human/H in antag_candidates)
@@ -189,7 +191,9 @@
return TRUE
if(station_was_nuked)
return TRUE
if(!round_converted && (!config.continuous[config_tag] || (config.continuous[config_tag] && config.midround_antag[config_tag]))) //Non-continuous or continous with replacement antags
var/list/continuous = CONFIG_GET(keyed_flag_list/continuous)
var/list/midround_antag = CONFIG_GET(keyed_flag_list/midround_antag)
if(!round_converted && (!continuous[config_tag] || (continuous[config_tag] && midround_antag[config_tag]))) //Non-continuous or continous with replacement antags
if(!continuous_sanity_checked) //make sure we have antags to be checking in the first place
for(var/mob/Player in GLOB.mob_list)
if(Player.mind)
@@ -198,8 +202,8 @@
return 0
if(!continuous_sanity_checked)
message_admins("The roundtype ([config_tag]) has no antagonists, continuous round has been defaulted to on and midround_antag has been defaulted to off.")
config.continuous[config_tag] = 1
config.midround_antag[config_tag] = 0
continuous[config_tag] = TRUE
midround_antag[config_tag] = FALSE
SSshuttle.clearHostileEnvironment(src)
return 0
@@ -213,7 +217,7 @@
living_antag_player = Player
return 0
if(!config.continuous[config_tag] || force_ending)
if(!continuous[config_tag] || force_ending)
return 1
else
@@ -222,7 +226,7 @@
if(round_ends_with_antag_death)
return 1
else
config.midround_antag[config_tag] = 0
midround_antag[config_tag] = 0
return 0
return 0
@@ -517,7 +521,7 @@
/datum/game_mode/proc/get_remaining_days(client/C)
if(!C)
return 0
if(!config.use_age_restriction_for_jobs)
if(!CONFIG_GET(flag/use_age_restriction_for_jobs))
return 0
if(!isnum(C.player_age))
return 0 //This is only a number if the db connection is established, otherwise it is text: "Requires database", meaning these restrictions cannot be enforced
@@ -34,7 +34,7 @@
to_chat(world, "<b>Crew</b> - don't get abducted and stop the abductors.")
/datum/game_mode/abduction/pre_setup()
var/num_teams = max(1, min(max_teams, round(num_players() / config.abductor_scaling_coeff)))
var/num_teams = max(1, min(max_teams, round(num_players() / CONFIG_GET(number/abductor_scaling_coeff))))
var/possible_teams = max(1, round(antag_candidates.len / 2))
num_teams = min(num_teams, possible_teams)
@@ -62,7 +62,7 @@
/obj/machinery/abductor/experiment/proc/dissection_icon(mob/living/carbon/human/H)
var/icon/photo = null
var/g = (H.gender == FEMALE) ? "f" : "m"
if(!config.mutant_races || H.dna.species.use_skintones)
if(!CONFIG_GET(flag/join_with_mutant_race) || H.dna.species.use_skintones)
photo = icon("icon" = 'icons/mob/human.dmi', "icon_state" = "[H.skin_tone]_[g]")
else
photo = icon("icon" = 'icons/mob/human.dmi', "icon_state" = "[H.dna.species.id]_[g]")
@@ -58,7 +58,7 @@
U.hidden_uplink.owner = "[user.key]"
U.hidden_uplink.telecrystals = CHALLENGE_TELECRYSTALS
U.hidden_uplink.set_gamemode(/datum/game_mode/nuclear)
config.shuttle_refuel_delay = max(config.shuttle_refuel_delay, CHALLENGE_SHUTTLE_DELAY)
CONFIG_SET(number/shuttle_refuel_delay, max(CONFIG_GET(number/shuttle_refuel_delay), CHALLENGE_SHUTTLE_DELAY))
SSblackbox.set_val("nuclear_challenge_mode",1)
qdel(src)
+3 -3
View File
@@ -44,10 +44,10 @@
///////////////////////////////////////////////////////////////////////////////
/datum/game_mode/revolution/pre_setup()
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
for (var/i=1 to max_headrevs)
@@ -230,7 +230,7 @@
//Checks if the round is over//
///////////////////////////////
/datum/game_mode/revolution/check_finished()
if(config.continuous["revolution"])
if(CONFIG_GET(keyed_flag_list/continuous)["revolution"])
if(finished)
SSshuttle.clearHostileEnvironment(src)
return ..()
+298 -298
View File
@@ -1,303 +1,303 @@
GLOBAL_VAR_INIT(hsboxspawn, TRUE)
/mob
var/datum/hSB/sandbox = null
/mob/proc/CanBuild()
sandbox = new/datum/hSB
sandbox.owner = src.ckey
if(src.client.holder)
sandbox.admin = 1
verbs += new/mob/proc/sandbox_panel
/mob/proc/sandbox_panel()
set name = "Sandbox Panel"
if(sandbox)
sandbox.update()
/datum/hSB
var/owner = null
var/admin = 0
GLOBAL_VAR_INIT(hsboxspawn, TRUE)
/mob
var/datum/hSB/sandbox = null
/mob/proc/CanBuild()
sandbox = new/datum/hSB
sandbox.owner = src.ckey
if(src.client.holder)
sandbox.admin = 1
verbs += new/mob/proc/sandbox_panel
/mob/proc/sandbox_panel()
set name = "Sandbox Panel"
if(sandbox)
sandbox.update()
/datum/hSB
var/owner = null
var/admin = 0
var/static/clothinfo = null
var/static/reaginfo = null
var/static/objinfo = null
var/canisterinfo = null
var/hsbinfo = null
//items that shouldn't spawn on the floor because they would bug or act weird
var/global/list/spawn_forbidden = list(
/obj/item/tk_grab, /obj/item/implant, // not implanter, the actual thing that is inside you
var/canisterinfo = null
var/hsbinfo = null
//items that shouldn't spawn on the floor because they would bug or act weird
var/global/list/spawn_forbidden = list(
/obj/item/tk_grab, /obj/item/implant, // not implanter, the actual thing that is inside you
/obj/item/assembly, /obj/item/device/onetankbomb, /obj/item/radio, /obj/item/device/pda/ai,
/obj/item/device/uplink, /obj/item/smallDelivery, /obj/item/projectile,
/obj/item/device/uplink, /obj/item/smallDelivery, /obj/item/projectile,
/obj/item/borg/sight, /obj/item/borg/stun, /obj/item/robot_module)
/datum/hSB/proc/update()
var/global/list/hrefs = list(
"Space Gear",
"Suit Up (Space Travel Gear)" = "hsbsuit",
"Spawn Gas Mask" = "hsbspawn&path=[/obj/item/clothing/mask/gas]",
"Spawn Emergency Air Tank" = "hsbspawn&path=[/obj/item/tank/internals/emergency_oxygen/double]",
"Standard Tools",
"Spawn Flashlight" = "hsbspawn&path=[/obj/item/device/flashlight]",
"Spawn Toolbox" = "hsbspawn&path=[/obj/item/storage/toolbox/mechanical]",
"Spawn Light Replacer" = "hsbspawn&path=[/obj/item/device/lightreplacer]",
"Spawn Medical Kit" = "hsbspawn&path=[/obj/item/storage/firstaid/regular]",
"Spawn All-Access ID" = "hsbaaid",
"Building Supplies",
"Spawn 50 Wood" = "hsbwood",
"Spawn 50 Metal" = "hsbmetal",
"Spawn 50 Plasteel" = "hsbplasteel",
"Spawn 50 Reinforced Glass" = "hsbrglass",
"Spawn 50 Glass" = "hsbglass",
"Spawn Full Cable Coil" = "hsbspawn&path=[/obj/item/stack/cable_coil]",
"Spawn Hyper Capacity Power Cell" = "hsbspawn&path=[/obj/item/stock_parts/cell/hyper]",
"Spawn Inf. Capacity Power Cell" = "hsbspawn&path=[/obj/item/stock_parts/cell/infinite]",
"Spawn Rapid Construction Device" = "hsbrcd",
"Spawn RCD Ammo" = "hsb_safespawn&path=[/obj/item/rcd_ammo]",
"Spawn Airlock" = "hsbairlock",
"Miscellaneous",
"Spawn Air Scrubber" = "hsbscrubber",
"Spawn Welding Fuel Tank" = "hsbspawn&path=[/obj/structure/reagent_dispensers/fueltank]",
"Spawn Water Tank" = "hsbspawn&path=[/obj/structure/reagent_dispensers/watertank]",
"Bots",
"Spawn Cleanbot" = "hsbspawn&path=[/mob/living/simple_animal/bot/cleanbot]",
"Spawn Floorbot" = "hsbspawn&path=[/mob/living/simple_animal/bot/floorbot]",
"Spawn Medbot" = "hsbspawn&path=[/mob/living/simple_animal/bot/medbot]",
"Canisters",
"Spawn O2 Canister" = "hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/oxygen]",
"Spawn Air Canister" = "hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/air]")
if(!hsbinfo)
hsbinfo = "<center><b>Sandbox Panel</b></center><hr>"
if(admin)
hsbinfo += "<b>Administration</b><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbtobj'>Toggle Object Spawning</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbtac'>Toggle Item Spawn Panel Auto-close</a><br>"
hsbinfo += "<b>Canister Spawning</b><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/toxins]'>Spawn Plasma Canister</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/carbon_dioxide]'>Spawn CO2 Canister</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/nitrogen]'>Spawn Nitrogen Canister</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/nitrous_oxide]'>Spawn N2O Canister</a><hr>"
else
hsbinfo += "<i>Some item spawning may be disabled by the administrators.</i><br>"
hsbinfo += "<i>Only administrators may spawn dangerous canisters.</i><br>"
for(var/T in hrefs)
var/href = hrefs[T]
if(href)
hsbinfo += "- <a href='?\ref[src];hsb=[hrefs[T]]'>[T]</a><br>"
else
hsbinfo += "<br><b>[T]</b><br>"
hsbinfo += "<hr>"
hsbinfo += "- <a href='?\ref[src];hsb=hsbcloth'>Spawn Clothing...</a><br>"
hsbinfo += "- <a href='?\ref[src];hsb=hsbreag'>Spawn Reagent Container...</a><br>"
hsbinfo += "- <a href='?\ref[src];hsb=hsbobj'>Spawn Other Item...</a><br><br>"
usr << browse(hsbinfo, "window=hsbpanel")
/datum/hSB/Topic(href, href_list)
if(!usr || !src || !(src.owner == usr.ckey))
if(usr)
usr << browse(null,"window=sandbox")
return
if(href_list["hsb"])
switch(href_list["hsb"])
//
// Admin: toggle spawning
//
if("hsbtobj")
if(!admin) return
if(GLOB.hsboxspawn)
to_chat(world, "<span class='boldannounce'>Sandbox:</span> <b>\black[usr.key] has disabled object spawning!</b>")
GLOB.hsboxspawn = FALSE
return
else
to_chat(world, "<span class='boldnotice'>Sandbox:</span> <b>\black[usr.key] has enabled object spawning!</b>")
GLOB.hsboxspawn = TRUE
return
//
// Admin: Toggle auto-close
//
if("hsbtac")
if(!admin) return
if(config.sandbox_autoclose)
to_chat(world, "<span class='boldnotice'>Sandbox:</span> <b>\black [usr.key] has removed the object spawn limiter.</b>")
config.sandbox_autoclose = FALSE
else
to_chat(world, "<span class='danger'>Sandbox:</span> <b>\black [usr.key] has added a limiter to object spawning. The window will now auto-close after use.</b>")
config.sandbox_autoclose = TRUE
return
//
// Spacesuit with full air jetpack set as internals
//
if("hsbsuit")
var/mob/living/carbon/human/P = usr
if(!istype(P)) return
if(P.wear_suit)
P.wear_suit.loc = P.loc
P.wear_suit.layer = initial(P.wear_suit.layer)
P.wear_suit.plane = initial(P.wear_suit.plane)
P.wear_suit = null
P.wear_suit = new/obj/item/clothing/suit/space(P)
P.wear_suit.layer = ABOVE_HUD_LAYER
P.wear_suit.plane = ABOVE_HUD_PLANE
P.update_inv_wear_suit()
if(P.head)
P.head.loc = P.loc
P.head.layer = initial(P.head.layer)
P.head.plane = initial(P.head.plane)
P.head = null
P.head = new/obj/item/clothing/head/helmet/space(P)
P.head.layer = ABOVE_HUD_LAYER
P.head.plane = ABOVE_HUD_PLANE
P.update_inv_head()
if(P.wear_mask)
P.wear_mask.loc = P.loc
P.wear_mask.layer = initial(P.wear_mask.layer)
P.wear_mask.plane = initial(P.wear_mask.plane)
P.wear_mask = null
P.wear_mask = new/obj/item/clothing/mask/gas(P)
P.wear_mask.layer = ABOVE_HUD_LAYER
P.wear_mask.plane = ABOVE_HUD_PLANE
P.update_inv_wear_mask()
if(P.back)
P.back.loc = P.loc
P.back.layer = initial(P.back.layer)
P.back.plane = initial(P.back.plane)
P.back = null
P.back = new/obj/item/tank/jetpack/oxygen(P)
P.back.layer = ABOVE_HUD_LAYER
P.back.plane = ABOVE_HUD_PLANE
P.update_inv_back()
P.internal = P.back
P.update_internals_hud_icon(1)
if("hsbscrubber") // This is beyond its normal capability but this is sandbox and you spawned one, I assume you need it
var/obj/hsb = new/obj/machinery/portable_atmospherics/scrubber{volume_rate=50*ONE_ATMOSPHERE;on=1}(usr.loc)
hsb.update_icon() // hackish but it wasn't meant to be spawned I guess?
//
// Stacked Materials
//
if("hsbrglass")
new/obj/item/stack/sheet/rglass{amount=50}(usr.loc)
if("hsbmetal")
new/obj/item/stack/sheet/metal{amount=50}(usr.loc)
if("hsbplasteel")
new/obj/item/stack/sheet/plasteel{amount=50}(usr.loc)
if("hsbglass")
new/obj/item/stack/sheet/glass{amount=50}(usr.loc)
if("hsbwood")
new/obj/item/stack/sheet/mineral/wood{amount=50}(usr.loc)
//
// All access ID
//
if("hsbaaid")
var/obj/item/card/id/gold/ID = new(usr.loc)
ID.registered_name = usr.real_name
ID.assignment = "Sandbox"
ID.access = get_all_accesses()
ID.update_label()
//
// RCD - starts with full clip
// Spawn check due to grief potential (destroying floors, walls, etc)
//
if("hsbrcd")
if(!GLOB.hsboxspawn) return
new/obj/item/construction/rcd/combat(usr.loc)
//
// New sandbox airlock maker
//
if("hsbairlock")
new /datum/airlock_maker(usr.loc)
//
// Object spawn window
//
// Clothing
if("hsbcloth")
if(!GLOB.hsboxspawn) return
if(!clothinfo)
clothinfo = "<b>Clothing</b> <a href='?\ref[src];hsb=hsbreag'>(Reagent Containers)</a> <a href='?\ref[src];hsb=hsbobj'>(Other Items)</a><hr><br>"
var/list/all_items = subtypesof(/obj/item/clothing)
for(var/typekey in spawn_forbidden)
all_items -= typesof(typekey)
for(var/O in reverseRange(all_items))
clothinfo += "<a href='?src=\ref[src];hsb=hsb_safespawn&path=[O]'>[O]</a><br>"
usr << browse(clothinfo,"window=sandbox")
// Reagent containers
if("hsbreag")
if(!GLOB.hsboxspawn) return
if(!reaginfo)
reaginfo = "<b>Reagent Containers</b> <a href='?\ref[src];hsb=hsbcloth'>(Clothing)</a> <a href='?\ref[src];hsb=hsbobj'>(Other Items)</a><hr><br>"
var/list/all_items = subtypesof(/obj/item/reagent_containers)
for(var/typekey in spawn_forbidden)
all_items -= typesof(typekey)
for(var/O in reverseRange(all_items))
reaginfo += "<a href='?src=\ref[src];hsb=hsb_safespawn&path=[O]'>[O]</a><br>"
usr << browse(reaginfo,"window=sandbox")
// Other items
if("hsbobj")
if(!GLOB.hsboxspawn) return
if(!objinfo)
objinfo = "<b>Other Items</b> <a href='?\ref[src];hsb=hsbcloth'>(Clothing)</a> <a href='?\ref[src];hsb=hsbreag'>(Reagent Containers)</a><hr><br>"
var/list/all_items = subtypesof(/obj/item/) - typesof(/obj/item/clothing) - typesof(/obj/item/reagent_containers)
for(var/typekey in spawn_forbidden)
all_items -= typesof(typekey)
for(var/O in reverseRange(all_items))
objinfo += "<a href='?src=\ref[src];hsb=hsb_safespawn&path=[O]'>[O]</a><br>"
usr << browse(objinfo,"window=sandbox")
//
// Safespawn checks to see if spawning is disabled.
//
if("hsb_safespawn")
if(!GLOB.hsboxspawn)
usr << browse(null,"window=sandbox")
return
var/typepath = text2path(href_list["path"])
if(!typepath)
to_chat(usr, "Bad path: \"[href_list["path"]]\"")
return
new typepath(usr.loc)
if(config.sandbox_autoclose)
usr << browse(null,"window=sandbox")
//
// For everything else in the href list
//
if("hsbspawn")
var/typepath = text2path(href_list["path"])
if(!typepath)
to_chat(usr, "Bad path: \"[href_list["path"]]\"")
return
new typepath(usr.loc)
if(config.sandbox_autoclose)
usr << browse(null,"window=sandbox")
/datum/hSB/proc/update()
var/global/list/hrefs = list(
"Space Gear",
"Suit Up (Space Travel Gear)" = "hsbsuit",
"Spawn Gas Mask" = "hsbspawn&path=[/obj/item/clothing/mask/gas]",
"Spawn Emergency Air Tank" = "hsbspawn&path=[/obj/item/tank/internals/emergency_oxygen/double]",
"Standard Tools",
"Spawn Flashlight" = "hsbspawn&path=[/obj/item/device/flashlight]",
"Spawn Toolbox" = "hsbspawn&path=[/obj/item/storage/toolbox/mechanical]",
"Spawn Light Replacer" = "hsbspawn&path=[/obj/item/device/lightreplacer]",
"Spawn Medical Kit" = "hsbspawn&path=[/obj/item/storage/firstaid/regular]",
"Spawn All-Access ID" = "hsbaaid",
"Building Supplies",
"Spawn 50 Wood" = "hsbwood",
"Spawn 50 Metal" = "hsbmetal",
"Spawn 50 Plasteel" = "hsbplasteel",
"Spawn 50 Reinforced Glass" = "hsbrglass",
"Spawn 50 Glass" = "hsbglass",
"Spawn Full Cable Coil" = "hsbspawn&path=[/obj/item/stack/cable_coil]",
"Spawn Hyper Capacity Power Cell" = "hsbspawn&path=[/obj/item/stock_parts/cell/hyper]",
"Spawn Inf. Capacity Power Cell" = "hsbspawn&path=[/obj/item/stock_parts/cell/infinite]",
"Spawn Rapid Construction Device" = "hsbrcd",
"Spawn RCD Ammo" = "hsb_safespawn&path=[/obj/item/rcd_ammo]",
"Spawn Airlock" = "hsbairlock",
"Miscellaneous",
"Spawn Air Scrubber" = "hsbscrubber",
"Spawn Welding Fuel Tank" = "hsbspawn&path=[/obj/structure/reagent_dispensers/fueltank]",
"Spawn Water Tank" = "hsbspawn&path=[/obj/structure/reagent_dispensers/watertank]",
"Bots",
"Spawn Cleanbot" = "hsbspawn&path=[/mob/living/simple_animal/bot/cleanbot]",
"Spawn Floorbot" = "hsbspawn&path=[/mob/living/simple_animal/bot/floorbot]",
"Spawn Medbot" = "hsbspawn&path=[/mob/living/simple_animal/bot/medbot]",
"Canisters",
"Spawn O2 Canister" = "hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/oxygen]",
"Spawn Air Canister" = "hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/air]")
if(!hsbinfo)
hsbinfo = "<center><b>Sandbox Panel</b></center><hr>"
if(admin)
hsbinfo += "<b>Administration</b><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbtobj'>Toggle Object Spawning</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbtac'>Toggle Item Spawn Panel Auto-close</a><br>"
hsbinfo += "<b>Canister Spawning</b><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/toxins]'>Spawn Plasma Canister</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/carbon_dioxide]'>Spawn CO2 Canister</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/nitrogen]'>Spawn Nitrogen Canister</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/nitrous_oxide]'>Spawn N2O Canister</a><hr>"
else
hsbinfo += "<i>Some item spawning may be disabled by the administrators.</i><br>"
hsbinfo += "<i>Only administrators may spawn dangerous canisters.</i><br>"
for(var/T in hrefs)
var/href = hrefs[T]
if(href)
hsbinfo += "- <a href='?\ref[src];hsb=[hrefs[T]]'>[T]</a><br>"
else
hsbinfo += "<br><b>[T]</b><br>"
hsbinfo += "<hr>"
hsbinfo += "- <a href='?\ref[src];hsb=hsbcloth'>Spawn Clothing...</a><br>"
hsbinfo += "- <a href='?\ref[src];hsb=hsbreag'>Spawn Reagent Container...</a><br>"
hsbinfo += "- <a href='?\ref[src];hsb=hsbobj'>Spawn Other Item...</a><br><br>"
usr << browse(hsbinfo, "window=hsbpanel")
/datum/hSB/Topic(href, href_list)
if(!usr || !src || !(src.owner == usr.ckey))
if(usr)
usr << browse(null,"window=sandbox")
return
if(href_list["hsb"])
switch(href_list["hsb"])
//
// Admin: toggle spawning
//
if("hsbtobj")
if(!admin) return
if(GLOB.hsboxspawn)
to_chat(world, "<span class='boldannounce'>Sandbox:</span> <b>\black[usr.key] has disabled object spawning!</b>")
GLOB.hsboxspawn = FALSE
return
else
to_chat(world, "<span class='boldnotice'>Sandbox:</span> <b>\black[usr.key] has enabled object spawning!</b>")
GLOB.hsboxspawn = TRUE
return
//
// Admin: Toggle auto-close
//
if("hsbtac")
if(!admin) return
var/sbac = CONFIG_GET(flag/sandbox_autoclose)
if(sbac)
to_chat(world, "<span class='boldnotice'>Sandbox:</span> <b>\black [usr.key] has removed the object spawn limiter.</b>")
else
to_chat(world, "<span class='danger'>Sandbox:</span> <b>\black [usr.key] has added a limiter to object spawning. The window will now auto-close after use.</b>")
CONFIG_SET(flag/sandbox_autoclose, !sbac)
return
//
// Spacesuit with full air jetpack set as internals
//
if("hsbsuit")
var/mob/living/carbon/human/P = usr
if(!istype(P)) return
if(P.wear_suit)
P.wear_suit.loc = P.loc
P.wear_suit.layer = initial(P.wear_suit.layer)
P.wear_suit.plane = initial(P.wear_suit.plane)
P.wear_suit = null
P.wear_suit = new/obj/item/clothing/suit/space(P)
P.wear_suit.layer = ABOVE_HUD_LAYER
P.wear_suit.plane = ABOVE_HUD_PLANE
P.update_inv_wear_suit()
if(P.head)
P.head.loc = P.loc
P.head.layer = initial(P.head.layer)
P.head.plane = initial(P.head.plane)
P.head = null
P.head = new/obj/item/clothing/head/helmet/space(P)
P.head.layer = ABOVE_HUD_LAYER
P.head.plane = ABOVE_HUD_PLANE
P.update_inv_head()
if(P.wear_mask)
P.wear_mask.loc = P.loc
P.wear_mask.layer = initial(P.wear_mask.layer)
P.wear_mask.plane = initial(P.wear_mask.plane)
P.wear_mask = null
P.wear_mask = new/obj/item/clothing/mask/gas(P)
P.wear_mask.layer = ABOVE_HUD_LAYER
P.wear_mask.plane = ABOVE_HUD_PLANE
P.update_inv_wear_mask()
if(P.back)
P.back.loc = P.loc
P.back.layer = initial(P.back.layer)
P.back.plane = initial(P.back.plane)
P.back = null
P.back = new/obj/item/tank/jetpack/oxygen(P)
P.back.layer = ABOVE_HUD_LAYER
P.back.plane = ABOVE_HUD_PLANE
P.update_inv_back()
P.internal = P.back
P.update_internals_hud_icon(1)
if("hsbscrubber") // This is beyond its normal capability but this is sandbox and you spawned one, I assume you need it
var/obj/hsb = new/obj/machinery/portable_atmospherics/scrubber{volume_rate=50*ONE_ATMOSPHERE;on=1}(usr.loc)
hsb.update_icon() // hackish but it wasn't meant to be spawned I guess?
//
// Stacked Materials
//
if("hsbrglass")
new/obj/item/stack/sheet/rglass{amount=50}(usr.loc)
if("hsbmetal")
new/obj/item/stack/sheet/metal{amount=50}(usr.loc)
if("hsbplasteel")
new/obj/item/stack/sheet/plasteel{amount=50}(usr.loc)
if("hsbglass")
new/obj/item/stack/sheet/glass{amount=50}(usr.loc)
if("hsbwood")
new/obj/item/stack/sheet/mineral/wood{amount=50}(usr.loc)
//
// All access ID
//
if("hsbaaid")
var/obj/item/card/id/gold/ID = new(usr.loc)
ID.registered_name = usr.real_name
ID.assignment = "Sandbox"
ID.access = get_all_accesses()
ID.update_label()
//
// RCD - starts with full clip
// Spawn check due to grief potential (destroying floors, walls, etc)
//
if("hsbrcd")
if(!GLOB.hsboxspawn) return
new/obj/item/construction/rcd/combat(usr.loc)
//
// New sandbox airlock maker
//
if("hsbairlock")
new /datum/airlock_maker(usr.loc)
//
// Object spawn window
//
// Clothing
if("hsbcloth")
if(!GLOB.hsboxspawn) return
if(!clothinfo)
clothinfo = "<b>Clothing</b> <a href='?\ref[src];hsb=hsbreag'>(Reagent Containers)</a> <a href='?\ref[src];hsb=hsbobj'>(Other Items)</a><hr><br>"
var/list/all_items = subtypesof(/obj/item/clothing)
for(var/typekey in spawn_forbidden)
all_items -= typesof(typekey)
for(var/O in reverseRange(all_items))
clothinfo += "<a href='?src=\ref[src];hsb=hsb_safespawn&path=[O]'>[O]</a><br>"
usr << browse(clothinfo,"window=sandbox")
// Reagent containers
if("hsbreag")
if(!GLOB.hsboxspawn) return
if(!reaginfo)
reaginfo = "<b>Reagent Containers</b> <a href='?\ref[src];hsb=hsbcloth'>(Clothing)</a> <a href='?\ref[src];hsb=hsbobj'>(Other Items)</a><hr><br>"
var/list/all_items = subtypesof(/obj/item/reagent_containers)
for(var/typekey in spawn_forbidden)
all_items -= typesof(typekey)
for(var/O in reverseRange(all_items))
reaginfo += "<a href='?src=\ref[src];hsb=hsb_safespawn&path=[O]'>[O]</a><br>"
usr << browse(reaginfo,"window=sandbox")
// Other items
if("hsbobj")
if(!GLOB.hsboxspawn) return
if(!objinfo)
objinfo = "<b>Other Items</b> <a href='?\ref[src];hsb=hsbcloth'>(Clothing)</a> <a href='?\ref[src];hsb=hsbreag'>(Reagent Containers)</a><hr><br>"
var/list/all_items = subtypesof(/obj/item/) - typesof(/obj/item/clothing) - typesof(/obj/item/reagent_containers)
for(var/typekey in spawn_forbidden)
all_items -= typesof(typekey)
for(var/O in reverseRange(all_items))
objinfo += "<a href='?src=\ref[src];hsb=hsb_safespawn&path=[O]'>[O]</a><br>"
usr << browse(objinfo,"window=sandbox")
//
// Safespawn checks to see if spawning is disabled.
//
if("hsb_safespawn")
if(!GLOB.hsboxspawn)
usr << browse(null,"window=sandbox")
return
var/typepath = text2path(href_list["path"])
if(!typepath)
to_chat(usr, "Bad path: \"[href_list["path"]]\"")
return
new typepath(usr.loc)
if(CONFIG_GET(flag/sandbox_autoclose))
usr << browse(null,"window=sandbox")
//
// For everything else in the href list
//
if("hsbspawn")
var/typepath = text2path(href_list["path"])
if(!typepath)
to_chat(usr, "Bad path: \"[href_list["path"]]\"")
return
new typepath(usr.loc)
if(CONFIG_GET(flag/sandbox_autoclose))
usr << browse(null,"window=sandbox")
+8 -6
View File
@@ -31,16 +31,17 @@
/datum/game_mode/traitor/pre_setup()
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/num_traitors = 1
if(config.traitor_scaling_coeff)
num_traitors = max(1, min( round(num_players()/(config.traitor_scaling_coeff*2))+ 2 + num_modifier, round(num_players()/(config.traitor_scaling_coeff)) + num_modifier ))
var/tsc = CONFIG_GET(number/traitor_scaling_coeff)
if(tsc)
num_traitors = max(1, min(round(num_players() / (tsc * 2)) + 2 + num_modifier, round(num_players() / tsc) + num_modifier))
else
num_traitors = max(1, min(num_players(), traitors_possible))
@@ -68,10 +69,11 @@
return 1
/datum/game_mode/traitor/make_antag_chance(mob/living/carbon/human/character) //Assigns traitor to latejoiners
var/traitorcap = min(round(GLOB.joined_player_list.len / (config.traitor_scaling_coeff * 2)) + 2 + num_modifier, round(GLOB.joined_player_list.len/config.traitor_scaling_coeff) + num_modifier )
var/tsc = CONFIG_GET(number/traitor_scaling_coeff)
var/traitorcap = min(round(GLOB.joined_player_list.len / (tsc * 2)) + 2 + num_modifier, round(GLOB.joined_player_list.len / tsc) + num_modifier)
if((SSticker.mode.traitors.len + pre_traitors.len) >= traitorcap) //Upper cap for number of latejoin antagonists
return
if((SSticker.mode.traitors.len + pre_traitors.len) <= (traitorcap - 2) || prob(100 / (config.traitor_scaling_coeff * 2)))
if((SSticker.mode.traitors.len + pre_traitors.len) <= (traitorcap - 2) || prob(100 / (tsc * 2)))
if(ROLE_TRAITOR in character.client.prefs.be_special)
if(!jobban_isbanned(character, ROLE_TRAITOR) && !jobban_isbanned(character, "Syndicate"))
if(age_check(character.client))
+3 -3
View File
@@ -478,7 +478,7 @@
/datum/spellbook_entry/summon/guns/IsAvailible()
if(!SSticker.mode) // In case spellbook is placed on map
return 0
return (!config.no_summon_guns)
return !CONFIG_GET(flag/no_summon_guns)
/datum/spellbook_entry/summon/guns/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
SSblackbox.add_details("wizard_spell_learned", name)
@@ -495,7 +495,7 @@
/datum/spellbook_entry/summon/magic/IsAvailible()
if(!SSticker.mode) // In case spellbook is placed on map
return 0
return (!config.no_summon_magic)
return !CONFIG_GET(flag/no_summon_magic)
/datum/spellbook_entry/summon/magic/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
SSblackbox.add_details("wizard_spell_learned", name)
@@ -513,7 +513,7 @@
/datum/spellbook_entry/summon/events/IsAvailible()
if(!SSticker.mode) // In case spellbook is placed on map
return 0
return (!config.no_summon_events)
return !CONFIG_GET(flag/no_summon_events)
/datum/spellbook_entry/summon/events/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
SSblackbox.add_details("wizard_spell_learned", name)
+3 -3
View File
@@ -231,9 +231,9 @@
else if(mob_occupant.cloneloss > (100 - heal_level))
mob_occupant.Unconscious(80)
var/dmg_mult = CONFIG_GET(number/damage_multiplier)
//Slowly get that clone healed and finished.
mob_occupant.adjustCloneLoss(-((speed_coeff/2) * config.damage_multiplier))
mob_occupant.adjustCloneLoss(-((speed_coeff / 2) * dmg_mult))
var/progress = CLONE_INITIAL_DAMAGE - mob_occupant.getCloneLoss()
// To avoid the default cloner making incomplete clones
progress += (100 - MINIMUM_HEAL_LEVEL)
@@ -251,7 +251,7 @@
BP.attach_limb(mob_occupant)
//Premature clones may have brain damage.
mob_occupant.adjustBrainLoss(-((speed_coeff/2) * config.damage_multiplier))
mob_occupant.adjustBrainLoss(-((speed_coeff / 2) * dmg_mult))
check_brine()
+1 -1
View File
@@ -47,7 +47,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
/obj/machinery/computer/card/Initialize()
. = ..()
change_position_cooldown = config.id_console_jobslot_delay
change_position_cooldown = CONFIG_GET(number/id_console_jobslot_delay)
/obj/machinery/computer/card/attackby(obj/O, mob/user, params)//TODO:SANITY
if(istype(O, /obj/item/card/id))
+497 -497
View File
@@ -1,502 +1,502 @@
/obj/machinery/computer/cloning
name = "cloning console"
desc = "Used to clone people and manage DNA."
icon_screen = "dna"
icon_keyboard = "med_key"
circuit = /obj/item/circuitboard/computer/cloning
/obj/machinery/computer/cloning
name = "cloning console"
desc = "Used to clone people and manage DNA."
icon_screen = "dna"
icon_keyboard = "med_key"
circuit = /obj/item/circuitboard/computer/cloning
req_access = list(ACCESS_HEADS) //ONLY USED FOR RECORD DELETION RIGHT NOW.
var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning.
var/list/pods //Linked cloning pods
var/temp = "Inactive"
var/scantemp_ckey
var/scantemp = "Ready to Scan"
var/menu = 1 //Which menu screen to display
var/list/records = list()
var/datum/data/record/active_record = null
var/obj/item/disk/data/diskette = null //Mostly so the geneticist can steal everything.
var/loading = 0 // Nice loading text
var/autoprocess = 0
light_color = LIGHT_COLOR_BLUE
/obj/machinery/computer/cloning/Initialize()
var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning.
var/list/pods //Linked cloning pods
var/temp = "Inactive"
var/scantemp_ckey
var/scantemp = "Ready to Scan"
var/menu = 1 //Which menu screen to display
var/list/records = list()
var/datum/data/record/active_record = null
var/obj/item/disk/data/diskette = null //Mostly so the geneticist can steal everything.
var/loading = 0 // Nice loading text
var/autoprocess = 0
light_color = LIGHT_COLOR_BLUE
/obj/machinery/computer/cloning/Initialize()
. = ..()
updatemodules(TRUE)
/obj/machinery/computer/cloning/Destroy()
if(pods)
for(var/P in pods)
DetachCloner(P)
pods = null
return ..()
/obj/machinery/computer/cloning/proc/GetAvailablePod(mind = null)
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.occupant && pod.clonemind == mind)
return null
if(pod.is_operational() && !(pod.occupant || pod.mess))
return pod
/obj/machinery/computer/cloning/proc/HasEfficientPod()
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.is_operational() && pod.efficiency > 5)
return TRUE
/obj/machinery/computer/cloning/proc/GetAvailableEfficientPod(mind = null)
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.occupant && pod.clonemind == mind)
return pod
else if(!. && pod.is_operational() && !(pod.occupant || pod.mess) && pod.efficiency > 5)
. = pod
/obj/machinery/computer/cloning/process()
if(!(scanner && LAZYLEN(pods) && autoprocess))
return
if(scanner.occupant && scanner.scan_level > 2)
scan_occupant(scanner.occupant)
for(var/datum/data/record/R in records)
var/obj/machinery/clonepod/pod = GetAvailableEfficientPod(R.fields["mind"])
if(!pod)
return
if(pod.occupant)
continue //how though?
if(pod.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["mrace"], R.fields["features"], R.fields["factions"]))
records -= R
/obj/machinery/computer/cloning/proc/updatemodules(findfirstcloner)
src.scanner = findscanner()
if(findfirstcloner && !LAZYLEN(pods))
findcloner()
/obj/machinery/computer/cloning/proc/findscanner()
var/obj/machinery/dna_scannernew/scannerf = null
// Loop through every direction
for(dir in list(NORTH,EAST,SOUTH,WEST))
// Try to find a scanner in that direction
scannerf = locate(/obj/machinery/dna_scannernew, get_step(src, dir))
// If found and operational, return the scanner
if (!isnull(scannerf) && scannerf.is_operational())
return scannerf
// If no scanner was found, it will return null
return null
/obj/machinery/computer/cloning/proc/findcloner()
var/obj/machinery/clonepod/podf = null
for(dir in list(NORTH,EAST,SOUTH,WEST))
podf = locate(/obj/machinery/clonepod, get_step(src, dir))
if (!isnull(podf) && podf.is_operational())
AttachCloner(podf)
/obj/machinery/computer/cloning/proc/AttachCloner(obj/machinery/clonepod/pod)
if(!pod.connected)
pod.connected = src
LAZYADD(pods, pod)
/obj/machinery/computer/cloning/proc/DetachCloner(obj/machinery/clonepod/pod)
pod.connected = null
LAZYREMOVE(pods, pod)
/obj/machinery/computer/cloning/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/disk/data)) //INSERT SOME DISKETTES
if (!src.diskette)
if(!user.drop_item())
return
W.loc = src
src.diskette = W
to_chat(user, "<span class='notice'>You insert [W].</span>")
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
src.updateUsrDialog()
updatemodules(TRUE)
/obj/machinery/computer/cloning/Destroy()
if(pods)
for(var/P in pods)
DetachCloner(P)
pods = null
return ..()
/obj/machinery/computer/cloning/proc/GetAvailablePod(mind = null)
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.occupant && pod.clonemind == mind)
return null
if(pod.is_operational() && !(pod.occupant || pod.mess))
return pod
/obj/machinery/computer/cloning/proc/HasEfficientPod()
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.is_operational() && pod.efficiency > 5)
return TRUE
/obj/machinery/computer/cloning/proc/GetAvailableEfficientPod(mind = null)
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.occupant && pod.clonemind == mind)
return pod
else if(!. && pod.is_operational() && !(pod.occupant || pod.mess) && pod.efficiency > 5)
. = pod
/obj/machinery/computer/cloning/process()
if(!(scanner && LAZYLEN(pods) && autoprocess))
return
if(scanner.occupant && scanner.scan_level > 2)
scan_occupant(scanner.occupant)
for(var/datum/data/record/R in records)
var/obj/machinery/clonepod/pod = GetAvailableEfficientPod(R.fields["mind"])
if(!pod)
return
if(pod.occupant)
continue //how though?
if(pod.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["mrace"], R.fields["features"], R.fields["factions"]))
records -= R
/obj/machinery/computer/cloning/proc/updatemodules(findfirstcloner)
src.scanner = findscanner()
if(findfirstcloner && !LAZYLEN(pods))
findcloner()
/obj/machinery/computer/cloning/proc/findscanner()
var/obj/machinery/dna_scannernew/scannerf = null
// Loop through every direction
for(dir in list(NORTH,EAST,SOUTH,WEST))
// Try to find a scanner in that direction
scannerf = locate(/obj/machinery/dna_scannernew, get_step(src, dir))
// If found and operational, return the scanner
if (!isnull(scannerf) && scannerf.is_operational())
return scannerf
// If no scanner was found, it will return null
return null
/obj/machinery/computer/cloning/proc/findcloner()
var/obj/machinery/clonepod/podf = null
for(dir in list(NORTH,EAST,SOUTH,WEST))
podf = locate(/obj/machinery/clonepod, get_step(src, dir))
if (!isnull(podf) && podf.is_operational())
AttachCloner(podf)
/obj/machinery/computer/cloning/proc/AttachCloner(obj/machinery/clonepod/pod)
if(!pod.connected)
pod.connected = src
LAZYADD(pods, pod)
/obj/machinery/computer/cloning/proc/DetachCloner(obj/machinery/clonepod/pod)
pod.connected = null
LAZYREMOVE(pods, pod)
/obj/machinery/computer/cloning/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/disk/data)) //INSERT SOME DISKETTES
if (!src.diskette)
if(!user.drop_item())
return
W.loc = src
src.diskette = W
to_chat(user, "<span class='notice'>You insert [W].</span>")
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
src.updateUsrDialog()
else if(istype(W, /obj/item/device/multitool))
var/obj/item/device/multitool/P = W
if(istype(P.buffer, /obj/machinery/clonepod))
if(get_area(P.buffer) != get_area(src))
to_chat(user, "<font color = #666633>-% Cannot link machines across power zones. Buffer cleared %-</font color>")
P.buffer = null
return
to_chat(user, "<font color = #666633>-% Successfully linked [P.buffer] with [src] %-</font color>")
var/obj/machinery/clonepod/pod = P.buffer
if(pod.connected)
pod.connected.DetachCloner(pod)
AttachCloner(pod)
else
P.buffer = src
to_chat(user, "<font color = #666633>-% Successfully stored \ref[P.buffer] [P.buffer.name] in buffer %-</font color>")
return
else
return ..()
/obj/machinery/computer/cloning/attack_hand(mob/user)
if(..())
return
interact(user)
/obj/machinery/computer/cloning/interact(mob/user)
user.set_machine(src)
add_fingerprint(user)
if(..())
return
updatemodules(TRUE)
var/dat = ""
dat += "<a href='byond://?src=\ref[src];refresh=1'>Refresh</a>"
if(scanner && HasEfficientPod() && scanner.scan_level > 2)
if(!autoprocess)
dat += "<a href='byond://?src=\ref[src];task=autoprocess'>Autoprocess</a>"
else
dat += "<a href='byond://?src=\ref[src];task=stopautoprocess'>Stop autoprocess</a>"
else
dat += "<span class='linkOff'>Autoprocess</span>"
dat += "<h3>Cloning Pod Status</h3>"
dat += "<div class='statusDisplay'>[temp]&nbsp;</div>"
switch(src.menu)
if(1)
// Modules
if (isnull(src.scanner) || !LAZYLEN(pods))
dat += "<h3>Modules</h3>"
//dat += "<a href='byond://?src=\ref[src];relmodules=1'>Reload Modules</a>"
if (isnull(src.scanner))
dat += "<font class='bad'>ERROR: No Scanner detected!</font><br>"
if (!LAZYLEN(pods))
dat += "<font class='bad'>ERROR: No Pod detected</font><br>"
// Scanner
if (!isnull(src.scanner))
var/mob/living/scanner_occupant = get_mob_or_brainmob(scanner.occupant)
dat += "<h3>Scanner Functions</h3>"
dat += "<div class='statusDisplay'>"
if(!scanner_occupant)
dat += "Scanner Unoccupied"
else if(loading)
dat += "[scanner_occupant] => Scanning..."
else
if(scanner_occupant.ckey != scantemp_ckey)
scantemp = "Ready to Scan"
scantemp_ckey = scanner_occupant.ckey
dat += "[scanner_occupant] => [scantemp]"
dat += "</div>"
if(scanner_occupant)
dat += "<a href='byond://?src=\ref[src];scan=1'>Start Scan</a>"
dat += "<br><a href='byond://?src=\ref[src];lock=1'>[src.scanner.locked ? "Unlock Scanner" : "Lock Scanner"]</a>"
else
dat += "<span class='linkOff'>Start Scan</span>"
// Database
dat += "<h3>Database Functions</h3>"
if (src.records.len && src.records.len > 0)
dat += "<a href='byond://?src=\ref[src];menu=2'>View Records ([src.records.len])</a><br>"
else
dat += "<span class='linkOff'>View Records (0)</span><br>"
if (src.diskette)
dat += "<a href='byond://?src=\ref[src];disk=eject'>Eject Disk</a><br>"
if(2)
dat += "<h3>Current records</h3>"
dat += "<a href='byond://?src=\ref[src];menu=1'><< Back</a><br><br>"
for(var/datum/data/record/R in records)
dat += "<h4>[R.fields["name"]]</h4>Scan ID [R.fields["id"]] <a href='byond://?src=\ref[src];view_rec=[R.fields["id"]]'>View Record</a>"
if(3)
dat += "<h3>Selected Record</h3>"
dat += "<a href='byond://?src=\ref[src];menu=2'><< Back</a><br>"
if (!src.active_record)
dat += "<font class='bad'>Record not found.</font>"
else
dat += "<h4>[src.active_record.fields["name"]]</h4>"
dat += "Scan ID [src.active_record.fields["id"]] <a href='byond://?src=\ref[src];clone=[active_record.fields["id"]]'>Clone</a><br>"
var/obj/item/implant/health/H = locate(src.active_record.fields["imp"])
if ((H) && (istype(H)))
dat += "<b>Health Implant Data:</b><br />[H.sensehealth()]<br><br />"
else
dat += "<font class='bad'>Unable to locate Health Implant.</font><br /><br />"
dat += "<b>Unique Identifier:</b><br /><span class='highlight'>[src.active_record.fields["UI"]]</span><br>"
dat += "<b>Structural Enzymes:</b><br /><span class='highlight'>[src.active_record.fields["SE"]]</span><br>"
if(diskette && diskette.fields)
dat += "<div class='block'>"
dat += "<h4>Inserted Disk</h4>"
dat += "<b>Contents:</b> "
var/list/L = list()
if(diskette.fields["UI"])
L += "Unique Identifier"
if(diskette.fields["UE"] && diskette.fields["name"] && diskette.fields["blood_type"])
L += "Unique Enzymes"
if(diskette.fields["SE"])
L += "Structural Enzymes"
dat += english_list(L, "Empty", " + ", " + ")
dat += "<br /><a href='byond://?src=\ref[src];disk=load'>Load from Disk</a>"
dat += "<br /><a href='byond://?src=\ref[src];disk=save'>Save to Disk</a>"
dat += "</div>"
dat += "<font size=1><a href='byond://?src=\ref[src];del_rec=1'>Delete Record</a></font>"
if(4)
if (!src.active_record)
src.menu = 2
dat = "[src.temp]<br>"
dat += "<h3>Confirm Record Deletion</h3>"
dat += "<b><a href='byond://?src=\ref[src];del_rec=1'>Scan card to confirm.</a></b><br>"
dat += "<b><a href='byond://?src=\ref[src];menu=3'>Cancel</a></b>"
var/datum/browser/popup = new(user, "cloning", "Cloning System Control")
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/computer/cloning/Topic(href, href_list)
if(..())
return
if(loading)
return
if(href_list["task"])
switch(href_list["task"])
if("autoprocess")
autoprocess = 1
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
if("stopautoprocess")
autoprocess = 0
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if ((href_list["scan"]) && !isnull(scanner) && scanner.is_operational())
scantemp = ""
loading = 1
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
say("Initiating scan...")
spawn(20)
src.scan_occupant(scanner.occupant)
loading = 0
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
//No locking an open scanner.
else if ((href_list["lock"]) && !isnull(scanner) && scanner.is_operational())
if ((!scanner.locked) && (scanner.occupant))
var/obj/item/device/multitool/P = W
if(istype(P.buffer, /obj/machinery/clonepod))
if(get_area(P.buffer) != get_area(src))
to_chat(user, "<font color = #666633>-% Cannot link machines across power zones. Buffer cleared %-</font color>")
P.buffer = null
return
to_chat(user, "<font color = #666633>-% Successfully linked [P.buffer] with [src] %-</font color>")
var/obj/machinery/clonepod/pod = P.buffer
if(pod.connected)
pod.connected.DetachCloner(pod)
AttachCloner(pod)
else
P.buffer = src
to_chat(user, "<font color = #666633>-% Successfully stored \ref[P.buffer] [P.buffer.name] in buffer %-</font color>")
return
else
return ..()
/obj/machinery/computer/cloning/attack_hand(mob/user)
if(..())
return
interact(user)
/obj/machinery/computer/cloning/interact(mob/user)
user.set_machine(src)
add_fingerprint(user)
if(..())
return
updatemodules(TRUE)
var/dat = ""
dat += "<a href='byond://?src=\ref[src];refresh=1'>Refresh</a>"
if(scanner && HasEfficientPod() && scanner.scan_level > 2)
if(!autoprocess)
dat += "<a href='byond://?src=\ref[src];task=autoprocess'>Autoprocess</a>"
else
dat += "<a href='byond://?src=\ref[src];task=stopautoprocess'>Stop autoprocess</a>"
else
dat += "<span class='linkOff'>Autoprocess</span>"
dat += "<h3>Cloning Pod Status</h3>"
dat += "<div class='statusDisplay'>[temp]&nbsp;</div>"
switch(src.menu)
if(1)
// Modules
if (isnull(src.scanner) || !LAZYLEN(pods))
dat += "<h3>Modules</h3>"
//dat += "<a href='byond://?src=\ref[src];relmodules=1'>Reload Modules</a>"
if (isnull(src.scanner))
dat += "<font class='bad'>ERROR: No Scanner detected!</font><br>"
if (!LAZYLEN(pods))
dat += "<font class='bad'>ERROR: No Pod detected</font><br>"
// Scanner
if (!isnull(src.scanner))
var/mob/living/scanner_occupant = get_mob_or_brainmob(scanner.occupant)
dat += "<h3>Scanner Functions</h3>"
dat += "<div class='statusDisplay'>"
if(!scanner_occupant)
dat += "Scanner Unoccupied"
else if(loading)
dat += "[scanner_occupant] => Scanning..."
else
if(scanner_occupant.ckey != scantemp_ckey)
scantemp = "Ready to Scan"
scantemp_ckey = scanner_occupant.ckey
dat += "[scanner_occupant] => [scantemp]"
dat += "</div>"
if(scanner_occupant)
dat += "<a href='byond://?src=\ref[src];scan=1'>Start Scan</a>"
dat += "<br><a href='byond://?src=\ref[src];lock=1'>[src.scanner.locked ? "Unlock Scanner" : "Lock Scanner"]</a>"
else
dat += "<span class='linkOff'>Start Scan</span>"
// Database
dat += "<h3>Database Functions</h3>"
if (src.records.len && src.records.len > 0)
dat += "<a href='byond://?src=\ref[src];menu=2'>View Records ([src.records.len])</a><br>"
else
dat += "<span class='linkOff'>View Records (0)</span><br>"
if (src.diskette)
dat += "<a href='byond://?src=\ref[src];disk=eject'>Eject Disk</a><br>"
if(2)
dat += "<h3>Current records</h3>"
dat += "<a href='byond://?src=\ref[src];menu=1'><< Back</a><br><br>"
for(var/datum/data/record/R in records)
dat += "<h4>[R.fields["name"]]</h4>Scan ID [R.fields["id"]] <a href='byond://?src=\ref[src];view_rec=[R.fields["id"]]'>View Record</a>"
if(3)
dat += "<h3>Selected Record</h3>"
dat += "<a href='byond://?src=\ref[src];menu=2'><< Back</a><br>"
if (!src.active_record)
dat += "<font class='bad'>Record not found.</font>"
else
dat += "<h4>[src.active_record.fields["name"]]</h4>"
dat += "Scan ID [src.active_record.fields["id"]] <a href='byond://?src=\ref[src];clone=[active_record.fields["id"]]'>Clone</a><br>"
var/obj/item/implant/health/H = locate(src.active_record.fields["imp"])
if ((H) && (istype(H)))
dat += "<b>Health Implant Data:</b><br />[H.sensehealth()]<br><br />"
else
dat += "<font class='bad'>Unable to locate Health Implant.</font><br /><br />"
dat += "<b>Unique Identifier:</b><br /><span class='highlight'>[src.active_record.fields["UI"]]</span><br>"
dat += "<b>Structural Enzymes:</b><br /><span class='highlight'>[src.active_record.fields["SE"]]</span><br>"
if(diskette && diskette.fields)
dat += "<div class='block'>"
dat += "<h4>Inserted Disk</h4>"
dat += "<b>Contents:</b> "
var/list/L = list()
if(diskette.fields["UI"])
L += "Unique Identifier"
if(diskette.fields["UE"] && diskette.fields["name"] && diskette.fields["blood_type"])
L += "Unique Enzymes"
if(diskette.fields["SE"])
L += "Structural Enzymes"
dat += english_list(L, "Empty", " + ", " + ")
dat += "<br /><a href='byond://?src=\ref[src];disk=load'>Load from Disk</a>"
dat += "<br /><a href='byond://?src=\ref[src];disk=save'>Save to Disk</a>"
dat += "</div>"
dat += "<font size=1><a href='byond://?src=\ref[src];del_rec=1'>Delete Record</a></font>"
if(4)
if (!src.active_record)
src.menu = 2
dat = "[src.temp]<br>"
dat += "<h3>Confirm Record Deletion</h3>"
dat += "<b><a href='byond://?src=\ref[src];del_rec=1'>Scan card to confirm.</a></b><br>"
dat += "<b><a href='byond://?src=\ref[src];menu=3'>Cancel</a></b>"
var/datum/browser/popup = new(user, "cloning", "Cloning System Control")
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/computer/cloning/Topic(href, href_list)
if(..())
return
if(loading)
return
if(href_list["task"])
switch(href_list["task"])
if("autoprocess")
autoprocess = 1
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
if("stopautoprocess")
autoprocess = 0
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if ((href_list["scan"]) && !isnull(scanner) && scanner.is_operational())
scantemp = ""
loading = 1
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
say("Initiating scan...")
spawn(20)
src.scan_occupant(scanner.occupant)
loading = 0
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
//No locking an open scanner.
else if ((href_list["lock"]) && !isnull(scanner) && scanner.is_operational())
if ((!scanner.locked) && (scanner.occupant))
scanner.locked = TRUE
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
scanner.locked = FALSE
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
else if(href_list["view_rec"])
playsound(src, "terminal_type", 25, 0)
src.active_record = find_record("id", href_list["view_rec"], records)
if(active_record)
if(!active_record.fields["ckey"])
records -= active_record
active_record = null
src.temp = "<font class='bad'>Record Corrupt</font>"
else
src.menu = 3
else
src.temp = "Record missing."
else if (href_list["del_rec"])
if ((!src.active_record) || (src.menu < 3))
return
if (src.menu == 3) //If we are viewing a record, confirm deletion
src.temp = "Delete record?"
src.menu = 4
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
else if (src.menu == 4)
var/obj/item/card/id/C = usr.get_active_held_item()
if (istype(C)||istype(C, /obj/item/device/pda))
if(src.check_access(C))
src.temp = "[src.active_record.fields["name"]] => Record deleted."
src.records.Remove(active_record)
active_record = null
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
src.menu = 2
else
src.temp = "<font class='bad'>Access Denied.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if (href_list["disk"]) //Load or eject.
switch(href_list["disk"])
if("load")
if (!diskette || !istype(diskette.fields) || !diskette.fields["name"] || !diskette.fields)
src.temp = "<font class='bad'>Load error.</font>"
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if (!src.active_record)
src.temp = "<font class='bad'>Record error.</font>"
src.menu = 1
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
for(var/key in diskette.fields)
src.active_record.fields[key] = diskette.fields[key]
src.temp = "Load successful."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
if("eject")
if(src.diskette)
src.diskette.loc = src.loc
src.diskette = null
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
if("save")
if(!diskette || diskette.read_only || !active_record || !active_record.fields)
src.temp = "<font class='bad'>Save error.</font>"
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
diskette.fields = active_record.fields.Copy()
diskette.name = "data disk - '[src.diskette.fields["name"]]'"
src.temp = "Save successful."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
else if (href_list["refresh"])
src.updateUsrDialog()
playsound(src, "terminal_type", 25, 0)
else if (href_list["clone"])
var/datum/data/record/C = find_record("id", href_list["clone"], records)
//Look for that player! They better be dead!
if(C)
var/obj/machinery/clonepod/pod = GetAvailablePod()
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
if(!LAZYLEN(pods))
temp = "<font class='bad'>No Clonepods detected.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(!pod)
temp = "<font class='bad'>No Clonepods available.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(!config.revival_cloning)
temp = "<font class='bad'>Unable to initiate cloning cycle.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.occupant)
temp = "<font class='bad'>Cloning cycle already in progress.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["features"], C.fields["factions"]))
temp = "[C.fields["name"]] => <font class='good'>Cloning cycle in progress...</font>"
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
records.Remove(C)
if(active_record == C)
active_record = null
menu = 1
else
temp = "[C.fields["name"]] => <font class='bad'>Initialisation failure.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
temp = "<font class='bad'>Data corruption.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if (href_list["menu"])
src.menu = text2num(href_list["menu"])
playsound(src, "terminal_type", 25, 0)
src.add_fingerprint(usr)
src.updateUsrDialog()
return
/obj/machinery/computer/cloning/proc/scan_occupant(occupant)
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
var/datum/dna/dna
if(iscarbon(mob_occupant))
var/mob/living/carbon/C = mob_occupant
dna = C.has_dna()
if(isbrain(mob_occupant))
var/mob/living/brain/B = mob_occupant
dna = B.stored_dna
if(!istype(dna))
scantemp = "<font class='bad'>Unable to locate valid genetic data.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if(mob_occupant.suiciding || mob_occupant.hellbound)
scantemp = "<font class='bad'>Subject's brain is not responding to scanning stimuli.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if((mob_occupant.disabilities & NOCLONE) && (src.scanner.scan_level < 2))
scantemp = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
if ((!mob_occupant.ckey) || (!mob_occupant.client))
scantemp = "<font class='bad'>Mental interface failure.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if (find_record("ckey", mob_occupant.ckey, records))
scantemp = "<font class='average'>Subject already in database.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
var/datum/data/record/R = new()
if(dna.species)
// We store the instance rather than the path, because some
// species (abductors, slimepeople) store state in their
// species datums
R.fields["mrace"] = dna.species
else
var/datum/species/rando_race = pick(config.roundstart_races)
R.fields["mrace"] = rando_race.type
R.fields["ckey"] = mob_occupant.ckey
R.fields["name"] = mob_occupant.real_name
R.fields["id"] = copytext(md5(mob_occupant.real_name), 2, 6)
R.fields["UE"] = dna.unique_enzymes
R.fields["UI"] = dna.uni_identity
R.fields["SE"] = dna.struc_enzymes
R.fields["blood_type"] = dna.blood_type
R.fields["features"] = dna.features
R.fields["factions"] = mob_occupant.faction
if (!isnull(mob_occupant.mind)) //Save that mind so traitors can continue traitoring after cloning.
R.fields["mind"] = "\ref[mob_occupant.mind]"
//Add an implant if needed
var/obj/item/implant/health/imp
for(var/obj/item/implant/health/HI in mob_occupant.implants)
imp = HI
break
if(!imp)
imp = new /obj/item/implant/health(mob_occupant)
imp.implant(mob_occupant)
R.fields["imp"] = "\ref[imp]"
src.records += R
scantemp = "Subject successfully scanned."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
else if(href_list["view_rec"])
playsound(src, "terminal_type", 25, 0)
src.active_record = find_record("id", href_list["view_rec"], records)
if(active_record)
if(!active_record.fields["ckey"])
records -= active_record
active_record = null
src.temp = "<font class='bad'>Record Corrupt</font>"
else
src.menu = 3
else
src.temp = "Record missing."
else if (href_list["del_rec"])
if ((!src.active_record) || (src.menu < 3))
return
if (src.menu == 3) //If we are viewing a record, confirm deletion
src.temp = "Delete record?"
src.menu = 4
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
else if (src.menu == 4)
var/obj/item/card/id/C = usr.get_active_held_item()
if (istype(C)||istype(C, /obj/item/device/pda))
if(src.check_access(C))
src.temp = "[src.active_record.fields["name"]] => Record deleted."
src.records.Remove(active_record)
active_record = null
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
src.menu = 2
else
src.temp = "<font class='bad'>Access Denied.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if (href_list["disk"]) //Load or eject.
switch(href_list["disk"])
if("load")
if (!diskette || !istype(diskette.fields) || !diskette.fields["name"] || !diskette.fields)
src.temp = "<font class='bad'>Load error.</font>"
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if (!src.active_record)
src.temp = "<font class='bad'>Record error.</font>"
src.menu = 1
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
for(var/key in diskette.fields)
src.active_record.fields[key] = diskette.fields[key]
src.temp = "Load successful."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
if("eject")
if(src.diskette)
src.diskette.loc = src.loc
src.diskette = null
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
if("save")
if(!diskette || diskette.read_only || !active_record || !active_record.fields)
src.temp = "<font class='bad'>Save error.</font>"
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
diskette.fields = active_record.fields.Copy()
diskette.name = "data disk - '[src.diskette.fields["name"]]'"
src.temp = "Save successful."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
else if (href_list["refresh"])
src.updateUsrDialog()
playsound(src, "terminal_type", 25, 0)
else if (href_list["clone"])
var/datum/data/record/C = find_record("id", href_list["clone"], records)
//Look for that player! They better be dead!
if(C)
var/obj/machinery/clonepod/pod = GetAvailablePod()
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
if(!LAZYLEN(pods))
temp = "<font class='bad'>No Clonepods detected.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(!pod)
temp = "<font class='bad'>No Clonepods available.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(!CONFIG_GET(flag/revival_cloning))
temp = "<font class='bad'>Unable to initiate cloning cycle.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.occupant)
temp = "<font class='bad'>Cloning cycle already in progress.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["features"], C.fields["factions"]))
temp = "[C.fields["name"]] => <font class='good'>Cloning cycle in progress...</font>"
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
records.Remove(C)
if(active_record == C)
active_record = null
menu = 1
else
temp = "[C.fields["name"]] => <font class='bad'>Initialisation failure.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
temp = "<font class='bad'>Data corruption.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if (href_list["menu"])
src.menu = text2num(href_list["menu"])
playsound(src, "terminal_type", 25, 0)
src.add_fingerprint(usr)
src.updateUsrDialog()
return
/obj/machinery/computer/cloning/proc/scan_occupant(occupant)
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
var/datum/dna/dna
if(iscarbon(mob_occupant))
var/mob/living/carbon/C = mob_occupant
dna = C.has_dna()
if(isbrain(mob_occupant))
var/mob/living/brain/B = mob_occupant
dna = B.stored_dna
if(!istype(dna))
scantemp = "<font class='bad'>Unable to locate valid genetic data.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if(mob_occupant.suiciding || mob_occupant.hellbound)
scantemp = "<font class='bad'>Subject's brain is not responding to scanning stimuli.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if((mob_occupant.disabilities & NOCLONE) && (src.scanner.scan_level < 2))
scantemp = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
if ((!mob_occupant.ckey) || (!mob_occupant.client))
scantemp = "<font class='bad'>Mental interface failure.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if (find_record("ckey", mob_occupant.ckey, records))
scantemp = "<font class='average'>Subject already in database.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
var/datum/data/record/R = new()
if(dna.species)
// We store the instance rather than the path, because some
// species (abductors, slimepeople) store state in their
// species datums
R.fields["mrace"] = dna.species
else
var/datum/species/rando_race = pick(CONFIG_GET(keyed_flag_list/roundstart_races))
R.fields["mrace"] = rando_race.type
R.fields["ckey"] = mob_occupant.ckey
R.fields["name"] = mob_occupant.real_name
R.fields["id"] = copytext(md5(mob_occupant.real_name), 2, 6)
R.fields["UE"] = dna.unique_enzymes
R.fields["UI"] = dna.uni_identity
R.fields["SE"] = dna.struc_enzymes
R.fields["blood_type"] = dna.blood_type
R.fields["features"] = dna.features
R.fields["factions"] = mob_occupant.faction
if (!isnull(mob_occupant.mind)) //Save that mind so traitors can continue traitoring after cloning.
R.fields["mind"] = "\ref[mob_occupant.mind]"
//Add an implant if needed
var/obj/item/implant/health/imp
for(var/obj/item/implant/health/HI in mob_occupant.implants)
imp = HI
break
if(!imp)
imp = new /obj/item/implant/health(mob_occupant)
imp.implant(mob_occupant)
R.fields["imp"] = "\ref[imp]"
src.records += R
scantemp = "Subject successfully scanned."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
@@ -454,7 +454,7 @@
if (src.authenticated==2)
dat += "<BR><BR><B>Captain Functions</B>"
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=announce'>Make a Captain's Announcement</A> \]"
if(config.cross_allowed)
if(CONFIG_GET(string/cross_server_address))
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=crossserver'>Send a message to an allied station</A> \]"
if(SSmapping.config.allow_custom_shuttles == "yes")
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=purchase_menu'>Purchase Shuttle</A> \]"
+2 -2
View File
@@ -124,7 +124,7 @@
dat += "<tr><td>ID:</td><td>[active1.fields["id"]]</td></tr>"
dat += "<tr><td>Sex:</td><td><A href='?src=\ref[src];field=sex'>&nbsp;[active1.fields["sex"]]&nbsp;</A></td></tr>"
dat += "<tr><td>Age:</td><td><A href='?src=\ref[src];field=age'>&nbsp;[active1.fields["age"]]&nbsp;</A></td></tr>"
if(config.mutant_races)
if(CONFIG_GET(flag/join_with_mutant_race))
dat += "<tr><td>Species:</td><td><A href='?src=\ref[src];field=species'>&nbsp;[active1.fields["species"]]&nbsp;</A></td></tr>"
dat += "<tr><td>Fingerprint:</td><td><A href='?src=\ref[src];field=fingerprint'>&nbsp;[active1.fields["fingerprint"]]&nbsp;</A></td></tr>"
dat += "<tr><td>Physical Status:</td><td><A href='?src=\ref[src];field=p_stat'>&nbsp;[active1.fields["p_stat"]]&nbsp;</A></td></tr>"
@@ -543,7 +543,7 @@
P.info = "<CENTER><B>Medical Record - (MR-[GLOB.data_core.medicalPrintCount])</B></CENTER><BR>"
if(active1 in GLOB.data_core.general)
P.info += text("Name: [] ID: []<BR>\nSex: []<BR>\nAge: []<BR>", src.active1.fields["name"], src.active1.fields["id"], src.active1.fields["sex"], src.active1.fields["age"])
if(config.mutant_races)
if(CONFIG_GET(flag/join_with_mutant_race))
P.info += "\nSpecies: [active1.fields["species"]]<BR>"
P.info += text("\nFingerprint: []<BR>\nPhysical Status: []<BR>\nMental Status: []<BR>", src.active1.fields["fingerprint"], src.active1.fields["p_stat"], src.active1.fields["m_stat"])
else
+5 -5
View File
@@ -186,7 +186,7 @@
<tr><td>ID:</td><td><A href='?src=\ref[src];choice=Edit Field;field=id'>&nbsp;[active1.fields["id"]]&nbsp;</A></td></tr>
<tr><td>Sex:</td><td><A href='?src=\ref[src];choice=Edit Field;field=sex'>&nbsp;[active1.fields["sex"]]&nbsp;</A></td></tr>
<tr><td>Age:</td><td><A href='?src=\ref[src];choice=Edit Field;field=age'>&nbsp;[active1.fields["age"]]&nbsp;</A></td></tr>"}
if(config.mutant_races)
if(CONFIG_GET(flag/join_with_mutant_race))
dat += "<tr><td>Species:</td><td><A href ='?src=\ref[src];choice=Edit Field;field=species'>&nbsp;[active1.fields["species"]]&nbsp;</A></td></tr>"
dat += {"<tr><td>Rank:</td><td><A href='?src=\ref[src];choice=Edit Field;field=rank'>&nbsp;[active1.fields["rank"]]&nbsp;</A></td></tr>
<tr><td>Fingerprint:</td><td><A href='?src=\ref[src];choice=Edit Field;field=fingerprint'>&nbsp;[active1.fields["fingerprint"]]&nbsp;</A></td></tr>
@@ -373,7 +373,7 @@ What a mess.*/
P.info = "<CENTER><B>Security Record - (SR-[GLOB.data_core.securityPrintCount])</B></CENTER><BR>"
if((istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1)))
P.info += text("Name: [] ID: []<BR>\nSex: []<BR>\nAge: []<BR>", active1.fields["name"], active1.fields["id"], active1.fields["sex"], active1.fields["age"])
if(config.mutant_races)
if(CONFIG_GET(flag/join_with_mutant_race))
P.info += "\nSpecies: [active1.fields["species"]]<BR>"
P.info += text("\nFingerprint: []<BR>\nPhysical Status: []<BR>\nMental Status: []<BR>", active1.fields["fingerprint"], active1.fields["p_stat"], active1.fields["m_stat"])
else
@@ -519,7 +519,7 @@ What a mess.*/
G.fields["rank"] = "Unassigned"
G.fields["sex"] = "Male"
G.fields["age"] = "Unknown"
if(config.mutant_races)
if(CONFIG_GET(flag/join_with_mutant_race))
G.fields["species"] = "Human"
G.fields["photo_front"] = new /icon()
G.fields["photo_side"] = new /icon()
@@ -604,7 +604,7 @@ What a mess.*/
active1.fields["age"] = t1
if("species")
if(istype(active1, /datum/data/record))
var/t1 = input("Select a species", "Species Selection") as null|anything in GLOB.roundstart_species
var/t1 = input("Select a species", "Species Selection") as null|anything in CONFIG_GET(keyed_flag_list/roundstart_races)
if(!canUseSecurityRecordsConsole(usr, t1, a1))
return
active1.fields["species"] = t1
@@ -772,7 +772,7 @@ What a mess.*/
if(6)
R.fields["m_stat"] = pick("*Insane*", "*Unstable*", "*Watch*", "Stable")
if(7)
R.fields["species"] = pick(GLOB.roundstart_species)
R.fields["species"] = pick(CONFIG_GET(keyed_flag_list/roundstart_races))
if(8)
var/datum/data/record/G = pick(GLOB.data_core.general)
R.fields["photo_front"] = G.fields["photo_front"]
+1 -1
View File
@@ -54,7 +54,7 @@ AI MODULES
for(var/mylaw in lawlist)
if(mylaw != "")
tot_laws++
if(tot_laws > config.silicon_max_law_amount && !bypass_law_amt_check)//allows certain boards to avoid this check, eg: reset
if(tot_laws > CONFIG_GET(number/silicon_max_law_amount) && !bypass_law_amt_check)//allows certain boards to avoid this check, eg: reset
to_chat(user, "<span class='caution'>Not enough memory allocated to [law_datum.owner ? law_datum.owner : "the AI core"]'s law processor to handle this amount of laws.</span>")
message_admins("[key_name_admin(user)] tried to upload laws to [law_datum.owner ? key_name_admin(law_datum.owner) : "an AI core"] that would exceed the law cap.")
overflow = TRUE
+5 -6
View File
@@ -72,16 +72,15 @@
user.visible_message("<span class='suicide'>[user] is jamming [src] up [user.p_their()] nose and into [user.p_their()] brain. It looks like [user.p_theyre()] trying to commit suicide!</span>")
return (BRUTELOSS|OXYLOSS)
/obj/item/toy/crayon/New()
..()
/obj/item/toy/crayon/Initialize()
. = ..()
// Makes crayons identifiable in things like grinders
if(name == "crayon")
name = "[item_color] crayon"
if(config)
if(config.mutant_races == 1)
graffiti |= "antilizard"
graffiti |= "prolizard"
if(CONFIG_GET(flag/join_with_mutant_race))
graffiti |= "antilizard"
graffiti |= "prolizard"
all_drawables = graffiti + letters + numerals + oriented + runes + graffiti_large_h
drawtype = pick(all_drawables)
+962
View File
@@ -1,3 +1,4 @@
<<<<<<< HEAD
/*********************MANUALS (BOOKS)***********************/
//Oh god what the fuck I am not good at computer
@@ -956,3 +957,964 @@
author = "Engineering Encyclopedia"
title = "Hacking"
page_link = "Hacking"
=======
/*********************MANUALS (BOOKS)***********************/
//Oh god what the fuck I am not good at computer
/obj/item/book/manual
icon = 'icons/obj/library.dmi'
due_date = 0 // Game time in 1/10th seconds
unique = 1 // 0 - Normal book, 1 - Should not be treated as normal book, unable to be copied, unable to be modified
/obj/item/book/manual/engineering_particle_accelerator
name = "Particle Accelerator User's Guide"
icon_state ="bookParticleAccelerator"
author = "Engineering Encyclopedia" // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned
title = "Particle Accelerator User's Guide"
dat = {"<html>
<head>
<style>
h1 {font-size: 18px; margin: 15px 0px 5px;}
h2 {font-size: 15px; margin: 15px 0px 5px;}
li {margin: 2px 0px 2px 15px;}
ul {list-style: none; margin: 5px; padding: 0px;}
ol {margin: 5px; padding: 0px 15px;}
</style>
</head>
<body>
<h3>Experienced user's guide</h3>
<h4>Setting up</h4>
<ol>
<li><b>Wrench</b> all pieces to the floor</li>
<li>Add <b>wires</b> to all the pieces</li>
<li>Close all the panels with your <b>screwdriver</b></li>
</ol>
<h4>Use</h4>
<ol>
<li>Open the control panel</li>
<li>Set the speed to 2</li>
<li>Start firing at the singularity generator</li>
<li><font color='red'><b>When the singularity reaches a large enough size so it starts moving on its own set the speed down to 0, but don't shut it off</b></font></li>
<li>Remember to wear a radiation suit when working with this machine... we did tell you that at the start, right?</li>
</ol>
</body>
</html>"}
/obj/item/book/manual/engineering_singularity_safety
name = "Singularity Safety in Special Circumstances"
icon_state ="bookEngineeringSingularitySafety"
author = "Engineering Encyclopedia" // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned
title = "Singularity Safety in Special Circumstances"
//big pile of shit below.
dat = {"<html>
<head>
<style>
h1 {font-size: 18px; margin: 15px 0px 5px;}
h2 {font-size: 15px; margin: 15px 0px 5px;}
li {margin: 2px 0px 2px 15px;}
ul {list-style: none; margin: 5px; padding: 0px;}
ol {margin: 5px; padding: 0px 15px;}
</style>
</head>
<body>
<h3>Singularity Safety in Special Circumstances</h3>
<h4>Power outage</h4>
A power problem has made the entire station lose power? Could be station-wide wiring problems or syndicate power sinks. In any case follow these steps:
<p>
<b>Step one:</b> <b><font color='red'>PANIC!</font></b><br>
<b>Step two:</b> Get your ass over to engineering! <b>QUICKLY!!!</b><br>
<b>Step three:</b> Make sure the SMES is still powering the emitters, if not, setup the generator in secure storage and disconnect the emitters from the SMES.<br>
<b>Step four:</b> Next, head over to the APC and swipe it with your <b>ID card</b> - if it doesn't unlock, continue with step 15.<br>
<b>Step five:</b> Open the console and disengage the cover lock.<br>
<b>Step six:</b> Pry open the APC with a <b>Crowbar.</b><br>
<b>Step seven:</b> Take out the empty <b>power cell.</b><br>
<b>Step eight:</b> Put in the new, <b>full power cell</b> - if you don't have one, continue with step 15.<br>
<b>Step nine:</b> Quickly put on a <b>Radiation suit.</b><br>
<b>Step ten:</b> Check if the <b>singularity field generators</b> withstood the down-time - if they didn't, continue with step 15.<br>
<b>Step eleven:</b> Since disaster was averted you now have to ensure it doesn't repeat. If it was a powersink which caused it and if the engineering apc is wired to the same powernet, which the powersink is on, you have to remove the piece of wire which links the apc to the powernet. If it wasn't a powersink which caused it, then skip to step 14.<br>
<b>Step twelve:</b> Grab your crowbar and pry away the tile closest to the APC.<br>
<b>Step thirteen:</b> Use the wirecutters to cut the wire which is conecting the grid to the terminal. <br>
<b>Step fourteen:</b> Go to the bar and tell the guys how you saved them all. Stop reading this guide here.<br>
<b>Step fifteen:</b> <b>GET THE FUCK OUT OF THERE!!!</b><br>
</p>
<h4>Shields get damaged</h4>
Step one: <b>GET THE FUCK OUT OF THERE!!! FORGET THE WOMEN AND CHILDREN, SAVE YOURSELF!!!</b><br>
</body>
</html>
"}
/obj/item/book/manual/hydroponics_pod_people
name = "The Human Harvest - From seed to market"
icon_state ="bookHydroponicsPodPeople"
author = "Farmer John"
title = "The Human Harvest - From seed to market"
dat = {"<html>
<head>
<style>
h1 {font-size: 18px; margin: 15px 0px 5px;}
h2 {font-size: 15px; margin: 15px 0px 5px;}
li {margin: 2px 0px 2px 15px;}
ul {list-style: none; margin: 5px; padding: 0px;}
ol {margin: 5px; padding: 0px 15px;}
</style>
</head>
<body>
<h3>Growing Humans</h3>
Why would you want to grow humans? Well I'm expecting most readers to be in the slave trade, but a few might actually
want to revive fallen comrades. Growing pod people is easy, but prone to disaster.
<p>
<ol>
<li>Find a dead person who is in need of cloning. </li>
<li>Take a blood sample with a syringe. </li>
<li>Inject a seed pack with the blood sample. </li>
<li>Plant the seeds. </li>
<li>Tend to the plants water and nutrition levels until it is time to harvest the cloned human.</li>
</ol>
<p>
It really is that easy! Good luck!
</body>
</html>
"}
/obj/item/book/manual/medical_cloning
name = "Cloning techniques of the 26th century"
icon_state ="bookCloning"
author = "Medical Journal, volume 3" // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned
title = "Cloning techniques of the 26th century"
//big pile of shit below.
dat = {"<html>
<head>
<style>
h1 {font-size: 18px; margin: 15px 0px 5px;}
h2 {font-size: 15px; margin: 15px 0px 5px;}
li {margin: 2px 0px 2px 15px;}
ul {list-style: none; margin: 5px; padding: 0px;}
ol {margin: 5px; padding: 0px 15px;}
</style>
</head>
<body>
<H3>How to Clone People</H3>
So theres 50 dead people lying on the floor, chairs are spinning like no tomorrow and you havent the foggiest idea of what to do? Not to worry! This guide is intended to teach you how to clone people and how to do it right, in a simple step-by-step process! If at any point of the guide you have a mental meltdown, genetics probably isnt for you and you should get a job-change as soon as possible before youre sued for malpractice.
<ol>
<li><a href='#1'>Acquire body</a></li>
<li><a href='#2'>Strip body</a></li>
<li><a href='#3'>Put body in cloning machine</a></li>
<li><a href='#4'>Scan body</a></li>
<li><a href='#5'>Clone body</a></li>
<li><a href='#6'>Get clean Structurel Enzymes for the body</a></li>
<li><a href='#7'>Put body in morgue</a></li>
<li><a href='#8'>Await cloned body</a></li>
<li><a href='#9'>Use the clean SW injector</a></li>
<li><a href='#10'>Give person clothes back</a></li>
<li><a href='#11'>Send person on their way</a></li>
</ol>
<a name='1'><H4>Step 1: Acquire body</H4>
This is pretty much vital for the process because without a body, you cannot clone it. Usually, bodies will be brought to you, so you do not need to worry so much about this step. If you already have a body, great! Move on to the next step.
<a name='2'><H4>Step 2: Strip body</H4>
The cloning machine does not like abiotic items. What this means is you cant clone anyone if theyre wearing clothes, so take all of it off. If its just one person, its courteous to put their possessions in the closet. If you have about seven people awaiting cloning, just leave the piles where they are, but dont mix them around and for Gods sake dont let the Clown in to steal them.
<a name='3'><H4>Step 3: Put body in cloning machine</H4>
Grab the body and then put it inside the DNA modifier. If you cannot do this, then you messed up at Step 2. Go back and check you took EVERYTHING off - a commonly missed item is their headset.
<a name='4'><H4>Step 4: Scan body</H4>
Go onto the computer and scan the body by pressing Scan - <Subject Name Here>. If youre successful, they will be added to the records (note that this can be done at any time, even with living people, so that they can be cloned without a body in the event that they are lying dead on port solars and didnt turn on their suit sensors)! If not, and it says “Error: Mental interface failure.”, then they have left their bodily confines and are one with the spirits. If this happens, just shout at them to get back in their body, click Refresh and try scanning them again. If theres no success, threaten them with gibbing. Still no success? Skip over to Step 7 and dont continue after it, as you have an unresponsive body and it cannot be cloned. If you got “Error: Unable to locate valid genetic data.“, you are trying to clone a monkey - start over.
<a name='5'><H4>Step 5: Clone body</H4>
Now that the body has a record, click View Records, click the subjects name, and then click Clone to start the cloning process. Congratulations! Youre halfway there. Remember not to Eject the cloning pod as this will kill the developing clone and youll have to start the process again.
<a name='6'><H4>Step 6: Get clean SEs for body</H4>
Cloning is a finicky and unreliable process. Whilst it will most certainly bring someone back from the dead, they can have any number of nasty disabilities given to them during the cloning process! For this reason, you need to prepare a clean, defect-free Structural Enzyme (SE) injection for when theyre done. If youre a competent Geneticist, you will already have one ready on your working computer. If, for any reason, you do not, then eject the body from the DNA modifier (NOT THE CLONING POD) and take it next door to the Genetics research room. Put the body in one of those DNA modifiers and then go onto the console. Go into View/Edit/Transfer Buffer, find an open slot and click “SE“ to save it. Then click Injector to get the SEs in syringe form. Put this in your pocket or something for when the body is done.
<a name='7'><H4>Step 7: Put body in morgue</H4>
Now that the cloning process has been initiated and you have some clean Structural Enzymes, you no longer need the body! Drag it to the morgue and tell the Chef over the radio that they have some fresh meat waiting for them in there. To put a body in a morgue bed, simply open the tray, grab the body, put it on the open tray, then close the tray again. Use one of the nearby pens to label the bed “CHEF MEAT” in order to avoid confusion.
<a name='8'><H4>Step 8: Await cloned body</H4>
Now go back to the lab and wait for your patient to be cloned. It wont be long now, I promise.
<a name='9'><H4>Step 9: Use the clean SE injector on person</H4>
Has your body been cloned yet? Great! As soon as the guy pops out, grab your injector and jab it in them. Once youve injected them, they now have clean Structural Enzymes and their defects, if any, will disappear in a short while.
<a name='10'><H4>Step 10: Give person clothes back</H4>
Obviously the person will be naked after they have been cloned. Provided you werent an irresponsible little shit, you should have protected their possessions from thieves and should be able to give them back to the patient. No matter how cruel you are, its simply against protocol to force your patients to walk outside naked.
<a name='11'><H4>Step 11: Send person on their way</H4>
Give the patient one last check-over - make sure they dont still have any defects and that they have all their possessions. Ask them how they died, if they know, so that you can report any foul play over the radio. Once youre done, your patient is ready to go back to work! Chances are they do not have Medbay access, so you should let them out of Genetics and the Medbay main entrance.
<p>If youve gotten this far, congratulations! You have mastered the art of cloning. Now, the real problem is how to resurrect yourself after that traitor had his way with you for cloning his target.
</body>
</html>
"}
/obj/item/book/manual/ripley_build_and_repair
name = "APLU \"Ripley\" Construction and Operation Manual"
icon_state ="book"
author = "Weyland-Yutani Corp" // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned
title = "APLU \"Ripley\" Construction and Operation Manual"
//big pile of shit below.
dat = {"<html>
<head>
<style>
h1 {font-size: 18px; margin: 15px 0px 5px;}
h2 {font-size: 15px; margin: 15px 0px 5px;}
li {margin: 2px 0px 2px 15px;}
ul {list-style: none; margin: 5px; padding: 0px;}
ol {margin: 5px; padding: 0px 15px;}
</style>
</head>
<body>
<center>
<b style='font-size: 12px;'>Weyland-Yutani - Building Better Worlds</b>
<h1>Autonomous Power Loader Unit \"Ripley\"</h1>
</center>
<h2>Specifications:</h2>
<ul>
<li><b>Class:</b> Autonomous Power Loader</li>
<li><b>Scope:</b> Logistics and Construction</li>
<li><b>Weight:</b> 820kg (without operator and with empty cargo compartment)</li>
<li><b>Height:</b> 2.5m</li>
<li><b>Width:</b> 1.8m</li>
<li><b>Top speed:</b> 5km/hour</li>
<li><b>Operation in vacuum/hostile environment:</b> Possible</b>
<li><b>Airtank Volume:</b> 500liters</li>
<li><b>Devices:</b>
<ul>
<li>Hydraulic Clamp</li>
<li>High-speed Drill</li>
</ul>
</li>
<li><b>Propulsion Device:</b> Powercell-powered electro-hydraulic system.</li>
<li><b>Powercell capacity:</b> Varies.</li>
</ul>
<h2>Construction:</h2>
<ol>
<li>Connect all exosuit parts to the chassis frame</li>
<li>Connect all hydraulic fittings and tighten them up with a wrench</li>
<li>Adjust the servohydraulics with a screwdriver</li>
<li>Wire the chassis. (Cable is not included.)</li>
<li>Use the wirecutters to remove the excess cable if needed.</li>
<li>Install the central control module (Not included. Use supplied datadisk to create one).</li>
<li>Secure the mainboard with a screwdriver.</li>
<li>Install the peripherals control module (Not included. Use supplied datadisk to create one).</li>
<li>Secure the peripherals control module with a screwdriver</li>
<li>Install the internal armor plating (Not included due to Nanotrasen regulations. Can be made using 5 metal sheets.)</li>
<li>Secure the internal armor plating with a wrench</li>
<li>Weld the internal armor plating to the chassis</li>
<li>Install the external reinforced armor plating (Not included due to Nanotrasen regulations. Can be made using 5 reinforced metal sheets.)</li>
<li>Secure the external reinforced armor plating with a wrench</li>
<li>Weld the external reinforced armor plating to the chassis</li>
<li></li>
<li>Additional Information:</li>
<li>The firefighting variation is made in a similar fashion.</li>
<li>A firesuit must be connected to the Firefighter chassis for heat shielding.</li>
<li>Internal armor is plasteel for additional strength.</li>
<li>External armor must be installed in 2 parts, totaling 10 sheets.</li>
<li>Completed mech is more resiliant against fire, and is a bit more durable overall</li>
<li>Nanotrasen is determined to the safety of its <s>investments</s> employees.</li>
</ol>
</body>
</html>
<h2>Operation</h2>
Coming soon...
"}
/obj/item/book/manual/experimentor
name = "Mentoring your Experiments"
icon_state = "rdbook"
author = "Dr. H.P. Kritz"
title = "Mentoring your Experiments"
dat = {"<html>
<head>
<style>
h1 {font-size: 18px; margin: 15px 0px 5px;}
h2 {font-size: 15px; margin: 15px 0px 5px;}
li {margin: 2px 0px 2px 15px;}
ul {list-style: none; margin: 5px; padding: 0px;}
ol {margin: 5px; padding: 0px 15px;}
</style>
</head>
<body>
<h1>THE E.X.P.E.R.I-MENTOR</h1>
The Enhanced Xenobiological Period Extraction (and) Restoration Instructor is a machine designed to discover the secrets behind every item in existence.
With advanced technology, it can process 99.95% of items, and discover their uses and secrets.
The E.X.P.E.R.I-MENTOR is a Research apparatus that takes items, and through a process of elimination, it allows you to deduce new technological designs from them.
Due to the volatile nature of the E.X.P.E.R.I-MENTOR, there is a slight chance for malfunction, potentially causing irreparable damage to you or your environment.
However, upgrading the apparatus has proven to decrease the chances of undesirable, potentially life-threatening outcomes.
Please note that the E.X.P.E.R.I-MENTOR uses a state-of-the-art random generator, which has a larger entropy than the observable universe,
therefore it can generate wildly different results each day, therefore it is highly suggested to re-scan objects of interests frequently (e.g. each shift).
<h2>BASIC PROCESS</h2>
The usage of the E.X.P.E.R.I-MENTOR is quite simple:
<ol>
<li>Find an item with a technological background</li>
<li>Insert the item into the E.X.P.E.R.I-MENTOR</li>
<li>Cycle through each processing method of the device.</li>
<li>Stand back, even in case of a successful experiment, as the machine might produce undesired behaviour.</li>
</ol>
<h2>ADVANCED USAGE</h2>
The E.X.P.E.R.I-MENTOR has a variety of uses, beyond menial research work. The different results can be used to combat localised events, or even to get special items.
The E.X.P.E.R.I-MENTOR's OBLITERATE function has the added use of transferring the destroyed item's material into a linked lathe.
The IRRADIATE function can be used to transform items into other items, resulting in potential upgrades (or downgrades).
Users should remember to always wear appropriate protection when using the machine, because malfunction can occur at any moment!
<h1>EVENTS</h1>
<h2>GLOBAL (happens at any time):</h2>
<ol>
<li>DETECTION MALFUNCTION - The machine's onboard sensors have malfunctioned, causing it to redefine the item's experiment type.
Produces the message: The E.X.P.E.R.I-MENTOR's onboard detection system has malfunctioned!</li>
<li>IANIZATION - The machine's onboard corgi-filter has malfunctioned, causing it to produce a corgi from.. somewhere.
Produces the message: The E.X.P.E.R.I-MENTOR melts the banana, ian-izing the air around it!</li>
<li>RUNTIME ERROR - The machine's onboard C4T-P processor has encountered a critical error, causing it to produce a cat from.. somewhere.
Produces the message: The E.X.P.E.R.I-MENTOR encounters a run-time error!</li>
<li>B100DG0D.EXE - The machine has encountered an unknown subroutine, which has been injected into its runtime. It upgrades the held item!
Produces the message: The E.X.P.E.R.I-MENTOR improves the banana, drawing the life essence of those nearby!</li>
<li>POWERSINK - The machine's PSU has tripped the charging mechanism! It consumes massive amounts of power!
Produces the message: The E.X.P.E.R.I-MENTOR begins to smoke and hiss, shaking violently!</li>
</ol>
<h2>FAIL:</h2>
This event is produced when the item mismatches the selected experiment.
Produces a random message similar to: "the Banana rumbles, and shakes, the experiment was a failure!"
<h2>POKE:</h2>
<ol>
<li>WILD ARMS - The machine's gryoscopic processors malfunction, causing it to lash out at nearby people with its arms.
Produces the message: The E.X.P.E.R.I-MENTOR malfunctions and destroys the banana, lashing its arms out at nearby people!</li>
<li>MISTYPE - The machine's interface has been garbled, and it switches to OBLITERATE.
Produces the message: The E.X.P.E.R.I-MENTOR malfunctions!</li>
<li>THROW - The machine's spatial recognition device has shifted several meters across the room, causing it to try and repostion the item there.
Produces the message: The E.X.P.E.R.I-MENTOR malfunctions, throwing the banana!</li>
</ol>
<h2>IRRADIATE:</h2>
<ol>
<li>RADIATION LEAK - The machine's shield has failed, resulting in a toxic radiation leak.
Produces the message: The E.X.P.E.R.I-MENTOR malfunctions, melting the banana and leaking radiation!</li>
<li>RADIATION DUMP - The machine's recycling and containment functions have failed, resulting in a dump of toxic waste around it
Produces the message: The E.X.P.E.R.I-MENTOR malfunctions, spewing toxic waste!</li>
<li>MUTATION - The machine's radio-isotope level meter has malfunctioned, causing it over-irradiate the item, making it transform.
Produces the message: The E.X.P.E.R.I-MENTOR malfunctions, transforming the banana!</li>
</ol>
<h2>GAS:</h2>
<ol>
<li>TOXIN LEAK - The machine's filtering and vent systems have failed, resulting in a cloud of toxic gas being expelled.
Produces the message: The E.X.P.E.R.I-MENTOR destroys the banana, leaking dangerous gas!</li>
<li>GAS LEAK - The machine's vent systems have failed, resulting in a cloud of harmless, but obscuring gas.
Produces the message: The E.X.P.E.R.I-MENTOR malfunctions, spewing harmless gas!</li>
<li>ELECTROMAGNETIC IONS - The machine's electrolytic scanners have failed, causing a dangerous Electromagnetic reaction.
Produces the message: The E.X.P.E.R.I-MENTOR melts the banana, ionizing the air around it!</li>
</ol>
<h2>HEAT:</h2>
<ol>
<li>TOASTER - The machine's heating coils have come into contact with the machine's gas storage, causing a large, sudden blast of flame.
Produces the message: The E.X.P.E.R.I-MENTOR malfunctions, melting the banana and releasing a burst of flame!</li>
<li>SAUNA - The machine's vent loop has sprung a leak, resulting in a large amount of superheated air being dumped around it.
Produces the message: The E.X.P.E.R.I-MENTOR malfunctions, melting the banana and leaking hot air!</li>
<li>EMERGENCY VENT - The machine's temperature gauge has malfunctioned, resulting in it attempting to cool the area around it, but instead, dumping a cloud of steam.
Produces the message: The E.X.P.E.R.I-MENTOR malfunctions, activating its emergency coolant systems!</li>
</ol>
<h2>COLD:</h2>
<ol>
<li>FREEZER - The machine's cooling loop has sprung a leak, resulting in a cloud of super-cooled liquid being blasted into the air.
Produces the message: The E.X.P.E.R.I-MENTOR malfunctions, shattering the banana and releasing a dangerous cloud of coolant!</li>
<li>FRIDGE - The machine's cooling loop has been exposed to the outside air, resulting in a large decrease in temperature.
Produces the message: The E.X.P.E.R.I-MENTOR malfunctions, shattering the banana and leaking cold air!</li>
<li>SNOWSTORM - The machine's cooling loop has come into contact with the heating coils, resulting in a sudden blast of cool air.
Produces the message: The E.X.P.E.R.I-MENTOR malfunctions, releasing a flurry of chilly air as the banana pops out!</li>
</ol>
<h2>OBLITERATE:</h2>
<ol>
<li>IMPLOSION - The machine's pressure leveller has malfunctioned, causing it to pierce the space-time momentarily, making everything in the area fly towards it.
Produces the message: The E.X.P.E.R.I-MENTOR's crusher goes way too many levels too high, crushing right through space-time!</li>
<li>DISTORTION - The machine's pressure leveller has completely disabled, resulting in a momentary space-time distortion, causing everything to fly around.
Produces the message: The E.X.P.E.R.I-MENTOR's crusher goes one level too high, crushing right into space-time!</li>
</ol>
</body>
</html>
"}
/obj/item/book/manual/research_and_development
name = "Research and Development 101"
icon_state = "rdbook"
author = "Dr. L. Ight"
title = "Research and Development 101"
dat = {"<html>
<head>
<style>
h1 {font-size: 18px; margin: 15px 0px 5px;}
h2 {font-size: 15px; margin: 15px 0px 5px;}
li {margin: 2px 0px 2px 15px;}
ul {list-style: none; margin: 5px; padding: 0px;}
ol {margin: 5px; padding: 0px 15px;}
</style>
</head>
<body>
<h1>Science For Dummies</h1>
So you want to further SCIENCE? Good man/woman/thing! However, SCIENCE is a complicated process even though it's quite easy. For the most part, it's a three step process:
<ol>
<li> 1) Deconstruct items in the Destructive Analyzer to advance technology or improve the design.</li>
<li> 2) Build unlocked designs in the Protolathe and Circuit Imprinter</li>
<li> 3) Repeat!</li>
</ol>
Those are the basic steps to furthing science. What do you do science with, however? Well, you have four major tools: R&D Console, the Destructive Analyzer, the Protolathe, and the Circuit Imprinter.
<h2>The R&D Console</h2>
The R&D console is the cornerstone of any research lab. It is the central system from which the Destructive Analyzer, Protolathe, and Circuit Imprinter (your R&D systems) are controled. More on those systems in their own sections. On its own, the R&D console acts as a database for all your technological gains and new devices you discover. So long as the R&D console remains intact, you'll retain all that SCIENCE you've discovered. Protect it though, because if it gets damaged, you'll lose your data! In addition to this important purpose, the R&D console has a disk menu that lets you transfer data from the database onto disk or from the disk into the database. It also has a settings menu that lets you re-sync with nearby R&D devices (if they've become disconnected), lock the console from the unworthy, upload the data to all other R&D consoles in the network (all R&D consoles are networked by default), connect/disconnect from the network, and purge all data from the database.
<b>NOTE:</b> The technology list screen, circuit imprinter, and protolathe menus are accessible by non-scientists. This is intended to allow 'public' systems for the plebians to utilize some new devices.
<h2>Destructive Analyzer</h2>
This is the source of all technology. Whenever you put a handheld object in it, it analyzes it and determines what sort of technological advancements you can discover from it. If the technology of the object is equal or higher then your current knowledge, you can destroy the object to further those sciences. Some devices (notably, some devices made from the protolathe and circuit imprinter) aren't 100% reliable when you first discover them. If these devices break down, you can put them into the Destructive Analyzer and improve their reliability rather then futher science. If their reliability is high enough ,it'll also advance their related technologies.
<h2>Circuit Imprinter</h2>
This machine, along with the Protolathe, is used to actually produce new devices. The Circuit Imprinter takes glass and various chemicals (depends on the design) to produce new circuit boards to build new machines or computers. It can even be used to print AI modules.
<h2>Protolathe</h2>
This machine is an advanced form of the Autolathe that produce non-circuit designs. Unlike the Autolathe, it can use processed metal, glass, solid plasma, silver, gold, and diamonds along with a variety of chemicals to produce devices. The downside is that, again, not all devices you make are 100% reliable when you first discover them.
<h1>Reliability and You</h1>
As it has been stated, many devices when they're first discovered do not have a 100% reliablity when you first discover them. Instead, the reliablity of the device is dependent upon a base reliability value, whatever improvements to the design you've discovered through the Destructive Analyzer, and any advancements you've made with the device's source technologies. To be able to improve the reliability of a device, you have to use the device until it breaks beyond repair. Once that happens, you can analyze it in a Destructive Analyzer. Once the device reachs a certain minimum reliability, you'll gain tech advancements from it.
<h1>Building a Better Machine</h1>
Many machines produces from circuit boards and inserted into a machine frame require a variety of parts to construct. These are parts like capacitors, batteries, matter bins, and so forth. As your knowledge of science improves, more advanced versions are unlocked. If you use these parts when constructing something, its attributes may be improved. For example, if you use an advanced matter bin when constructing an autolathe (rather then a regular one), it'll hold more materials. Experiment around with stock parts of various qualities to see how they affect the end results! Be warned, however: Tier 3 and higher stock parts don't have 100% reliability and their low reliability may affect the reliability of the end machine.
</body>
</html>
"}
/obj/item/book/manual/robotics_cyborgs
name = "Cyborgs for Dummies"
icon_state = "borgbook"
author = "XISC"
title = "Cyborgs for Dummies"
dat = {"<html>
<head>
<style>
h1 {font-size: 21px; margin: 15px 0px 5px;}
h2 {font-size: 18px; margin: 15px 0px 5px;}
h3 {font-size: 15px; margin: 15px 0px 5px;}
li {margin: 2px 0px 2px 15px;}
ul {list-style: none; margin: 5px; padding: 0px;}
ol {margin: 5px; padding: 0px 15px;}
</style>
</head>
<body>
<h1>Cyborgs for Dummies</h1>
<h2>Chapters</h2>
<ol>
<li><a href="#Equipment">Cyborg Related Equipment</a></li>
<li><a href="#Modules">Cyborg Modules</a></li>
<li><a href="#Construction">Cyborg Construction</a></li>
<li><a href="#Deconstruction">Cyborg Deconstruction</a></li>
<li><a href="#Maintenance">Cyborg Maintenance</a></li>
<li><a href="#Repairs">Cyborg Repairs</a></li>
<li><a href="#Emergency">In Case of Emergency</a></li>
</ol>
<h2><a name="Equipment">Cyborg Related Equipment</h2>
<h3>Exosuit Fabricator</h3>
The Exosuit Fabricator is the most important piece of equipment related to cyborgs. It allows the construction of the core cyborg parts. Without these machines, cyborgs can not be built. It seems that they may also benefit from advanced research techniques.
<h3>Cyborg Recharging Station</h3>
This useful piece of equipment will suck power out of the power systems to charge a cyborg's power cell back up to full charge.
<h3>Robotics Control Console</h3>
This useful piece of equipment can be used to immobolize or destroy a cyborg. A word of warning: Cyborgs are expensive pieces of equipment, do not destroy them without good reason, or Nanotrasen may see to it that it never happens again.
<h2><a name="Modules">Cyborg Modules</h2>
When a cyborg is created it picks out of an array of modules to designate its purpose. There are 6 different cyborg modules.
<h3>Standard Cyborg</h3>
The standard cyborg module is a multi-purpose cyborg. It is equipped with various modules, allowing it to do basic tasks.<br>
<h3>Engineering Cyborg</h3>
The Engineering cyborg module comes equipped with various engineering-related tools to help with engineering-related tasks.<br>
<h3>Mining Cyborg</h3>
The Mining Cyborg module comes equipped with the latest in mining equipment. They are efficient at mining due to no need for oxygen, but their power cells limit their time in the mines.
<h3>Security Cyborg</h3>
The Security Cyborg module is equipped with effective security measures used to apprehend and arrest criminals without harming them a bit.
<h3>Janitor Cyborg</h3>
The Janitor Cyborg module is equipped with various cleaning-facilitating devices.
<h3>Service Cyborg</h3>
The service cyborg module comes ready to serve your human needs. It includes various entertainment and refreshment devices. Occasionally some service cyborgs may have been referred to as "Bros"
<h2><a name="Construction">Cyborg Construction</h2>
Cyborg construction is a rather easy process, requiring a decent amount of metal and a few other supplies.<br>The required materials to make a cyborg are:
<ul>
<li>Metal</li>
<li>Two Flashes</li>
<li>One Power Cell (Preferrably rated to 15000w)</li>
<li>Some electrical wires</li>
<li>One Human Brain</li>
<li>One Man-Machine Interface</li>
</ul>
Once you have acquired the materials, you can start on construction of your cyborg.<br>To construct a cyborg, follow the steps below:
<ol>
<li>Start the Exosuit Fabricators constructing all of the cyborg parts</li>
<li>While the parts are being constructed, take your human brain, and place it inside the Man-Machine Interface</li>
<li>Once you have a Robot Head, place your two flashes inside the eye sockets</li>
<li>Once you have your Robot Chest, wire the Robot chest, then insert the power cell</li>
<li>Attach all of the Robot parts to the Robot frame</li>
<li>Insert the Man-Machine Interface (With the Brain inside) Into the Robot Body</li>
<li>Congratulations! You have a new cyborg!</li>
</ol>
<h2><a name="Deconstruction">Cyborg Deconstruction</h2>
If you want to deconstruct a cyborg, say to remove its MMI without <a href="#Emergency">blowing the Cyborg to pieces</a>, they come apart very quickly, <b>and</b> very safely, in a few simple steps.
<ul>
<li>Crowbar</li>
<li>Wrench</li>
Optional:
<li>Screwdriver</li>
<li>Wirecutters</li>
</ul>
<ol>
<li>Begin by unlocking the Cyborg's access panel using your ID</li>
<li>Use your crowbar to open the Cyborg's access panel</li>
<li>Using your bare hands, remove the power cell from the Cyborg</li>
<li>Lockdown the Cyborg to disengage safety protocols</li>
<ol>
Option 1: Robotics console
<li>Use the Robotics console in the RD's office</li>
<li>Find the entry for your Cyborg</li>
<li>Press the Lockdown button on the Robotics console</li>
</ol>
<ol>
Option 2: Lockdown wire
<li>Use your screwdriver to expose the Cyborg's wiring</li>
<li>Use your wirecutters to start cutting all of the wires until the lockdown light turns off, cutting all of the wires irregardless of the lockdown light works as well</li>
</ol>
<li>Use your wrench to unfasten the Cyborg's bolts, the Cyborg will then fall apart onto the floor, the MMI will be there as well</li>
</ol>
<h2><a name="Maintenance">Cyborg Maintenance</h2>
Occasionally Cyborgs may require maintenance of a couple types, this could include replacing a power cell with a charged one, or possibly maintaining the cyborg's internal wiring.
<h3>Replacing a Power Cell</h3>
Replacing a Power cell is a common type of maintenance for cyborgs. It usually involves replacing the cell with a fully charged one, or upgrading the cell with a larger capacity cell.<br>The steps to replace a cell are follows:
<ol>
<li>Unlock the Cyborg's Interface by swiping your ID on it</li>
<li>Open the Cyborg's outer panel using a crowbar</li>
<li>Remove the old power cell</li>
<li>Insert the new power cell</li>
<li>Close the Cyborg's outer panel using a crowbar</li>
<li>Lock the Cyborg's Interface by swiping your ID on it, this will prevent non-qualified personnel from attempting to remove the power cell</li>
</ol>
<h3>Exposing the Internal Wiring</h3>
Exposing the internal wiring of a cyborg is fairly easy to do, and is mainly used for cyborg repairs.<br>You can easily expose the internal wiring by following the steps below:
<ol>
<li>Follow Steps 1 - 3 of "Replacing a Cyborg's Power Cell"</li>
<li>Open the cyborg's internal wiring panel by using a screwdriver to unsecure the panel</li>
</ol>
To re-seal the cyborg's internal wiring:
<ol>
<li>Use a screwdriver to secure the cyborg's internal panel</li>
<li>Follow steps 4 - 6 of "Replacing a Cyborg's Power Cell" to close up the cyborg</li>
</ol>
<h2><a name="Repairs">Cyborg Repairs</h2>
Occasionally a Cyborg may become damaged. This could be in the form of impact damage from a heavy or fast-travelling object, or it could be heat damage from high temperatures, or even lasers or Electromagnetic Pulses (EMPs).
<h3>Dents</h3>
If a cyborg becomes damaged due to impact from heavy or fast-moving objects, it will become dented. Sure, a dent may not seem like much, but it can compromise the structural integrity of the cyborg, possibly causing a critical failure.
Dents in a cyborg's frame are rather easy to repair, all you need is to apply a welding tool to the dented area, and the high-tech cyborg frame will repair the dent under the heat of the welder.
<h3>Excessive Heat Damage</h3>
If a cyborg becomes damaged due to excessive heat, it is likely that the internal wires will have been damaged. You must replace those wires to ensure that the cyborg remains functioning properly.<br>To replace the internal wiring follow the steps below:
<ol>
<li>Unlock the Cyborg's Interface by swiping your ID</li>
<li>Open the Cyborg's External Panel using a crowbar</li>
<li>Remove the Cyborg's Power Cell</li>
<li>Using a screwdriver, expose the internal wiring or the Cyborg</li>
<li>Replace the damaged wires inside the cyborg</li>
<li>Secure the internal wiring cover using a screwdriver</li>
<li>Insert the Cyborg's Power Cell</li>
<li>Close the Cyborg's External Panel using a crowbar</li>
<li>Lock the Cyborg's Interface by swiping your ID</li>
</ol>
These repair tasks may seem difficult, but are essential to keep your cyborgs running at peak efficiency.
<h2><a name="Emergency">In Case of Emergency</h2>
In case of emergency, there are a few steps you can take.
<h3>"Rogue" Cyborgs</h3>
If the cyborgs seem to become "rogue", they may have non-standard laws. In this case, use extreme caution.
To repair the situation, follow these steps:
<ol>
<li>Locate the nearest robotics console</li>
<li>Determine which cyborgs are "Rogue"</li>
<li>Press the lockdown button to immobolize the cyborg</li>
<li>Locate the cyborg</li>
<li>Expose the cyborg's internal wiring</li>
<li>Check to make sure the LawSync and AI Sync lights are lit</li>
<li>If they are not lit, pulse the LawSync wire using a multitool to enable the cyborg's Law Sync</li>
<li>Proceed to a cyborg upload console. Nanotrasen usually places these in the same location as AI uplaod consoles.</li>
<li>Use a "Reset" upload moduleto reset the cyborg's laws</li>
<li>Proceed to a Robotics Control console</li>
<li>Remove the lockdown on the cyborg</li>
</ol>
<h3>As a last resort</h3>
If all else fails in a case of cyborg-related emergency. There may be only one option. Using a Robotics Control console, you may have to remotely detonate the cyborg.
<h3>WARNING:</h3> Do not detonate a borg without an explicit reason for doing so. Cyborgs are expensive pieces of Nanotrasen equipment, and you may be punished for detonating them without reason.
</body>
</html>
"}
/obj/item/book/manual/chef_recipes
name = "Chef Recipes"
icon_state = "cooked_book"
author = "Lord Frenrir Cageth"
title = "Chef Recipes"
dat = {"<html>
<head>
<style>
h1 {font-size: 18px; margin: 15px 0px 5px;}
h2 {font-size: 15px; margin: 15px 0px 5px;}
li {margin: 2px 0px 2px 15px;}
ul {list-style: none; margin: 5px; padding: 0px;}
ol {margin: 5px; padding: 0px 15px;}
</style>
</head>
<body>
<h1>Food for Dummies</h1>
Here is a guide on basic food recipes and also how to not poison your customers accidentally.
<h2>Basic ingredients preparation:</h2>
<b>Dough:</b> 10u water + 15u flour for simple dough.<br>
15u egg yolk + 15u flour + 5u sugar for cake batter.<br>
Doughs can be transformed by using a knife and rolling pin.<br>
All doughs can be microwaved.<br>
<b>Bowl:</b> Add water to it for soup preparation.<br>
<b>Meat:</b> Microwave it, process it, slice it into microwavable cutlets with your knife, or use it raw.<br>
<b>Cheese:</b> Add 5u universal enzyme (catalyst) to milk and soy milk to prepare cheese (sliceable) and tofu.<br>
<b>Rice:</b> Mix 10u rice with 10u water in a bowl then microwave it.
<h2>Custom food:</h2>
Add ingredients to a base item to prepare a custom meal.<br>
The bases are:<br>
- bun (burger)<br>
- breadslices(sandwich)<br>
- plain bread<br>
- plain pie<br>
- vanilla cake<br>
- empty bowl (salad)<br>
- bowl with 10u water (soup)<br>
- boiled spaghetti<br>
- pizza bread<br>
- metal rod (kebab)
<h2>Table Craft:</h2>
Put ingredients on table, then click and drag the table onto yourself to see what recipes you can prepare.
<h2>Microwave:</h2>
Use it to cook or boil food ingredients (meats, doughs, egg, spaghetti, donkpocket, etc...).
It can cook multiple items at once.
<h2>Processor:</h2>
Use it to process certain ingredients (meat into faggot, doughslice into spaghetti, potato into fries,etc...)
<h2>Gibber:</h2>
Stuff an animal in it to grind it into meat.
<h2>Meat spike:</h2>
Stick an animal on it then begin collecting its meat.
<h2>Example recipes:</h2>
<b>Vanilla Cake</b>: Microwave cake batter.<br>
<b>Burger:</b> 1 bun + 1 meat steak<br>
<b>Bread:</b> Microwave dough.<br>
<b>Waffles:</b> 2 pastry base<br>
<b>Popcorn:</b> Microwave corn.<br>
<b>Meat Steak:</b> Microwave meat.<br>
<b>Meat Pie:</b> 1 plain pie + 1u black pepper + 1u salt + 2 meat cutlets<br>
<b>Boiled Spagetti:</b> Microwave spaghetti.<br>
<b>Donuts:</b> 1u sugar + 1 pastry base<br>
<b>Fries:</b> Process potato.
<h2>Sharing your food:</h2>
You can put your meals on your kitchen counter or load them in the snack vending machines.
</body>
</html>
"}
/obj/item/book/manual/barman_recipes
name = "Barman Recipes"
icon_state = "barbook"
author = "Sir John Rose"
title = "Barman Recipes"
dat = {"<html>
<head>
<style>
h1 {font-size: 18px; margin: 15px 0px 5px;}
h2 {font-size: 15px; margin: 15px 0px 5px;}
li {margin: 2px 0px 2px 15px;}
ul {list-style: none; margin: 5px; padding: 0px;}
ol {margin: 5px; padding: 0px 15px;}
</style>
</head>
<body>
<h1>Drinks for dummies</h1>
Heres a guide for some basic drinks.
<h2>Manly Dorf:</h2>
Mix ale and beer into a glass.
<h2>Grog:</h2>
Mix rum and water into a glass.
<h2>Black Russian:</h2>
Mix vodka and kahlua into a glass.
<h2>Irish Cream:</h2>
Mix cream and whiskey into a glass.
<h2>Screwdriver:</h2>
Mix vodka and orange juice into a glass.
<h2>Cafe Latte:</h2>
Mix milk and coffee into a glass.
<h2>Mead:</h2>
Mix Enzyme, water and sugar into a glass.
<h2>Gin Tonic:</h2>
Mix gin and tonic into a glass.
<h2>Classic Martini:</h2>
Mix vermouth and gin into a glass.
</body>
</html>
"}
/obj/item/book/manual/detective
name = "The Film Noir: Proper Procedures for Investigations"
icon_state ="bookDetective"
author = "Nanotrasen"
title = "The Film Noir: Proper Procedures for Investigations"
dat = {"<html>
<head>
<style>
h1 {font-size: 18px; margin: 15px 0px 5px;}
h2 {font-size: 15px; margin: 15px 0px 5px;}
li {margin: 2px 0px 2px 15px;}
ul {list-style: none; margin: 5px; padding: 0px;}
ol {margin: 5px; padding: 0px 15px;}
</style>
</head>
<body>
<h3>Detective Work</h3>
Between your bouts of self-narration, and drinking whiskey on the rocks, you might get a case or two to solve.<br>
To have the best chance to solve your case, follow these directions:
<p>
<ol>
<li>Go to the crime scene. </li>
<li>Take your scanner and scan EVERYTHING (Yes, the doors, the tables, even the dog.) </li>
<li>Once you are reasonably certain you have every scrap of evidence you can use, find all possible entry points and scan them, too. </li>
<li>Return to your office. </li>
<li>Using your forensic scanning computer, scan your Scanner to upload all of your evidence into the database.</li>
<li>Browse through the resulting dossiers, looking for the one that either has the most complete set of prints, or the most suspicious items handled. </li>
<li>If you have 80% or more of the print (The print is displayed) go to step 10, otherwise continue to step 8.</li>
<li>Look for clues from the suit fibres you found on your perp, and go about looking for more evidence with this new information, scanning as you go. </li>
<li>Try to get a fingerprint card of your perp, as if used in the computer, the prints will be completed on their dossier.</li>
<li>Assuming you have enough of a print to see it, grab the biggest complete piece of the print and search the security records for it. </li>
<li>Since you now have both your dossier and the name of the person, print both out as evidence, and get security to nab your baddie.</li>
<li>Give yourself a pat on the back and a bottle of the ships finest vodka, you did it!</li>
</ol>
<p>
It really is that easy! Good luck!
</body>
</html>"}
/obj/item/book/manual/nuclear
name = "Fission Mailed: Nuclear Sabotage 101"
icon_state ="bookNuclear"
author = "Syndicate"
title = "Fission Mailed: Nuclear Sabotage 101"
dat = {"<html>
Nuclear Explosives 101:<br>
Hello and thank you for choosing the Syndicate for your nuclear information needs.<br>
Today's crash course will deal with the operation of a Fusion Class Nanotrasen made Nuclear Device.<br>
First and foremost, DO NOT TOUCH ANYTHING UNTIL THE BOMB IS IN PLACE.<br>
Pressing any button on the compacted bomb will cause it to extend and bolt itself into place.<br>
If this is done to unbolt it one must completely log in which at this time may not be possible.<br>
To make the nuclear device functional:<br>
<li>Place the nuclear device in the designated detonation zone.</li>
<li>Extend and anchor the nuclear device from its interface.</li>
<li>Insert the nuclear authorisation disk into slot.</li>
<li>Type numeric authorisation code into the keypad. This should have been provided. Note: If you make a mistake press R to reset the device.
<li>Press the E button to log onto the device.</li>
You now have activated the device. To deactivate the buttons at anytime for example when you've already prepped the bomb for detonation remove the auth disk OR press the R on the keypad.<br>
Now the bomb CAN ONLY be detonated using the timer. Manual detonation is not an option.<br>
Note: Nanotrasen is a pain in the neck.<br>
Toggle off the SAFETY.<br>
Note: You wouldn't believe how many Syndicate Operatives with doctorates have forgotten this step.<br>
So use the - - and + + to set a det time between 5 seconds and 10 minutes.<br>
Then press the timer toggle button to start the countdown.<br>
Now remove the auth. disk so that the buttons deactivate.<br>
Note: THE BOMB IS STILL SET AND WILL DETONATE<br>
Now before you remove the disk if you need to move the bomb you can:<br>
Toggle off the anchor, move it, and re-anchor.<br><br>
Good luck. Remember the order:<br>
<b>Disk, Code, Safety, Timer, Disk, RUN!</b><br>
Intelligence Analysts believe that normal Nanotrasen procedure is for the Captain to secure the nuclear authorisation disk.<br>
Good luck!
</html>"}
// Wiki books that are linked to the configured wiki link.
// A book that links to the wiki
/obj/item/book/manual/wiki
var/page_link = ""
window_size = "970x710"
/obj/item/book/manual/wiki/attack_self()
if(!dat)
initialize_wikibook()
..()
/obj/item/book/manual/wiki/proc/initialize_wikibook()
var/wikiurl = CONFIG_GET(string/wikiurl)
if(wikiurl)
dat = {"
<html><head>
<style>
iframe {
display: none;
}
</style>
</head>
<body>
<script type="text/javascript">
function pageloaded(myframe) {
document.getElementById("loading").style.display = "none";
myframe.style.display = "inline";
}
</script>
<p id='loading'>You start skimming through the manual...</p>
<iframe width='100%' height='97%' onload="pageloaded(this)" src="[wikiurl]/[page_link]?printable=yes&remove_links=1" frameborder="0" id="main_frame"></iframe>
</body>
</html>
"}
/obj/item/book/manual/wiki/chemistry
name = "Chemistry Textbook"
icon_state ="chemistrybook"
author = "Nanotrasen"
title = "Chemistry Textbook"
page_link = "Guide_to_chemistry"
/obj/item/book/manual/wiki/engineering_construction
name = "Station Repairs and Construction"
icon_state ="bookEngineering"
author = "Engineering Encyclopedia"
title = "Station Repairs and Construction"
page_link = "Guide_to_construction"
/obj/item/book/manual/wiki/engineering_guide
name = "Engineering Textbook"
icon_state ="bookEngineering2"
author = "Engineering Encyclopedia"
title = "Engineering Textbook"
page_link = "Guide_to_engineering"
/obj/item/book/manual/wiki/security_space_law
name = "Space Law"
desc = "A set of Nanotrasen guidelines for keeping law and order on their space stations."
icon_state = "bookSpaceLaw"
author = "Nanotrasen"
title = "Space Law"
page_link = "Space_Law"
/obj/item/book/manual/wiki/infections
name = "Infections - Making your own pandemic!"
icon_state = "bookInfections"
author = "Infections Encyclopedia"
title = "Infections - Making your own pandemic!"
page_link = "Infections"
/obj/item/book/manual/wiki/telescience
name = "Teleportation Science - Bluespace for dummies!"
icon_state = "book7"
author = "University of Bluespace"
title = "Teleportation Science - Bluespace for dummies!"
page_link = "Guide_to_telescience"
/obj/item/book/manual/wiki/engineering_hacking
name = "Hacking"
icon_state ="bookHacking"
author = "Engineering Encyclopedia"
title = "Hacking"
page_link = "Hacking"
>>>>>>> 4178c20... Configuration datum refactor (#30763)
+1 -1
View File
@@ -134,7 +134,7 @@
to_chat(user, "<span class='warning'>Sticking an inactive [M.name] into the frame would sort of defeat the purpose.</span>")
return
if((config) && (!config.allow_ai) || jobban_isbanned(M.brainmob, "AI"))
if(!CONFIG_GET(flag/allow_ai) || jobban_isbanned(M.brainmob, "AI"))
to_chat(user, "<span class='warning'>This [M.name] does not seem to fit!</span>")
return
@@ -98,7 +98,7 @@
set category = "Object"
set src in oview(1)
if(config.ghost_interaction)
if(CONFIG_GET(flag/ghost_interaction))
spin()
else
if(!usr || !isturf(usr.loc))
@@ -23,7 +23,7 @@
return
move_delay = 1
if(step(src, direction))
spawn(config.walk_speed*move_speed_multiplier)
spawn(CONFIG_GET(number/walk_delay) * move_speed_multiplier)
move_delay = 0
else
move_delay = 0
+226 -225
View File
@@ -1,225 +1,226 @@
//wip wip wup
/obj/structure/mirror
name = "mirror"
desc = "Mirror mirror on the wall, who's the most robust of them all?"
icon = 'icons/obj/watercloset.dmi'
icon_state = "mirror"
density = FALSE
anchored = TRUE
max_integrity = 200
integrity_failure = 100
/obj/structure/mirror/attack_hand(mob/user)
if(broken || !Adjacent(user))
return
if(ishuman(user))
var/mob/living/carbon/human/H = user
var/userloc = H.loc
//see code/modules/mob/dead/new_player/preferences.dm at approx line 545 for comments!
//this is largely copypasted from there.
//handle facial hair (if necessary)
if(H.gender == MALE)
var/new_style = input(user, "Select a facial hair style", "Grooming") as null|anything in GLOB.facial_hair_styles_list
if(userloc != H.loc)
return //no tele-grooming
if(new_style)
H.facial_hair_style = new_style
else
H.facial_hair_style = "Shaved"
//handle normal hair
var/new_style = input(user, "Select a hair style", "Grooming") as null|anything in GLOB.hair_styles_list
if(userloc != H.loc)
return //no tele-grooming
if(new_style)
H.hair_style = new_style
H.update_hair()
/obj/structure/mirror/examine_status(mob/user)
if(broken)
return // no message spam
..()
/obj/structure/mirror/obj_break(damage_flag)
if(!broken && !(flags_1 & NODECONSTRUCT_1))
icon_state = "mirror_broke"
playsound(src, "shatter", 70, 1)
desc = "Oh no, seven years of bad luck!"
broken = 1
/obj/structure/mirror/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
if(!disassembled)
new /obj/item/shard( src.loc )
qdel(src)
/obj/structure/mirror/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/weldingtool) && user.a_intent != INTENT_HARM)
var/obj/item/weldingtool/WT = I
if(broken)
user.changeNext_move(CLICK_CD_MELEE)
if(WT.remove_fuel(0, user))
to_chat(user, "<span class='notice'>You begin repairing [src]...</span>")
playsound(src, 'sound/items/welder.ogg', 100, 1)
if(do_after(user, 10*I.toolspeed, target = src))
if(!user || !WT || !WT.isOn())
return
to_chat(user, "<span class='notice'>You repair [src].</span>")
broken = 0
icon_state = initial(icon_state)
desc = initial(desc)
else
return ..()
/obj/structure/mirror/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
switch(damage_type)
if(BRUTE)
playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 70, 1)
if(BURN)
playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 70, 1)
/obj/structure/mirror/magic
name = "magic mirror"
desc = "Turn and face the strange... face."
icon_state = "magic_mirror"
var/list/races_blacklist = list("skeleton", "agent", "angel", "military_synth", "memezombie")
var/list/choosable_races = list()
/obj/structure/mirror/magic/New()
if(!choosable_races.len)
for(var/speciestype in subtypesof(/datum/species))
var/datum/species/S = new speciestype()
if(!(S.id in races_blacklist))
choosable_races += S.id
..()
/obj/structure/mirror/magic/lesser/New()
choosable_races = GLOB.roundstart_species
..()
/obj/structure/mirror/magic/badmin/New()
for(var/speciestype in subtypesof(/datum/species))
var/datum/species/S = new speciestype()
choosable_races += S.id
..()
/obj/structure/mirror/magic/attack_hand(mob/user)
if(!ishuman(user))
return
var/mob/living/carbon/human/H = user
var/choice = input(user, "Something to change?", "Magical Grooming") as null|anything in list("name", "race", "gender", "hair", "eyes")
if(!Adjacent(user))
return
switch(choice)
if("name")
var/newname = copytext(sanitize(input(H, "Who are we again?", "Name change", H.name) as null|text),1,MAX_NAME_LEN)
if(!newname)
return
if(!Adjacent(user))
return
H.real_name = newname
H.name = newname
if(H.dna)
H.dna.real_name = newname
if(H.mind)
H.mind.name = newname
if("race")
var/newrace
var/racechoice = input(H, "What are we again?", "Race change") as null|anything in choosable_races
newrace = GLOB.species_list[racechoice]
if(!newrace)
return
if(!Adjacent(user))
return
H.set_species(newrace, icon_update=0)
if(H.dna.species.use_skintones)
var/new_s_tone = input(user, "Choose your skin tone:", "Race change") as null|anything in GLOB.skin_tones
if(new_s_tone)
H.skin_tone = new_s_tone
H.dna.update_ui_block(DNA_SKIN_TONE_BLOCK)
if(MUTCOLORS in H.dna.species.species_traits)
var/new_mutantcolor = input(user, "Choose your skin color:", "Race change") as color|null
if(new_mutantcolor)
var/temp_hsv = RGBtoHSV(new_mutantcolor)
if(ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright
H.dna.features["mcolor"] = sanitize_hexcolor(new_mutantcolor)
else
to_chat(H, "<span class='notice'>Invalid color. Your color is not bright enough.</span>")
H.update_body()
H.update_hair()
H.update_body_parts()
H.update_mutations_overlay() // no hulk lizard
if("gender")
if(!(H.gender in list("male", "female"))) //blame the patriarchy
return
if(!Adjacent(user))
return
if(H.gender == "male")
if(alert(H, "Become a Witch?", "Confirmation", "Yes", "No") == "Yes")
H.gender = "female"
to_chat(H, "<span class='notice'>Man, you feel like a woman!</span>")
else
return
else
if(alert(H, "Become a Warlock?", "Confirmation", "Yes", "No") == "Yes")
H.gender = "male"
to_chat(H, "<span class='notice'>Whoa man, you feel like a man!</span>")
else
return
H.dna.update_ui_block(DNA_GENDER_BLOCK)
H.update_body()
H.update_mutations_overlay() //(hulk male/female)
if("hair")
var/hairchoice = alert(H, "Hair style or hair color?", "Change Hair", "Style", "Color")
if(!Adjacent(user))
return
if(hairchoice == "Style") //So you just want to use a mirror then?
..()
else
var/new_hair_color = input(H, "Choose your hair color", "Hair Color") as null|color
if(new_hair_color)
H.hair_color = sanitize_hexcolor(new_hair_color)
H.dna.update_ui_block(DNA_HAIR_COLOR_BLOCK)
if(H.gender == "male")
var/new_face_color = input(H, "Choose your facial hair color", "Hair Color") as null|color
if(new_face_color)
H.facial_hair_color = sanitize_hexcolor(new_face_color)
H.dna.update_ui_block(DNA_FACIAL_HAIR_COLOR_BLOCK)
H.update_hair()
if("eyes")
var/new_eye_color = input(H, "Choose your eye color", "Eye Color") as null|color
if(!Adjacent(user))
return
if(new_eye_color)
H.eye_color = sanitize_hexcolor(new_eye_color)
H.dna.update_ui_block(DNA_EYE_COLOR_BLOCK)
H.update_body()
if(choice)
curse(user)
/obj/structure/mirror/magic/proc/curse(mob/living/user)
return
//wip wip wup
/obj/structure/mirror
name = "mirror"
desc = "Mirror mirror on the wall, who's the most robust of them all?"
icon = 'icons/obj/watercloset.dmi'
icon_state = "mirror"
density = FALSE
anchored = TRUE
max_integrity = 200
integrity_failure = 100
/obj/structure/mirror/attack_hand(mob/user)
if(broken || !Adjacent(user))
return
if(ishuman(user))
var/mob/living/carbon/human/H = user
var/userloc = H.loc
//see code/modules/mob/dead/new_player/preferences.dm at approx line 545 for comments!
//this is largely copypasted from there.
//handle facial hair (if necessary)
if(H.gender == MALE)
var/new_style = input(user, "Select a facial hair style", "Grooming") as null|anything in GLOB.facial_hair_styles_list
if(userloc != H.loc)
return //no tele-grooming
if(new_style)
H.facial_hair_style = new_style
else
H.facial_hair_style = "Shaved"
//handle normal hair
var/new_style = input(user, "Select a hair style", "Grooming") as null|anything in GLOB.hair_styles_list
if(userloc != H.loc)
return //no tele-grooming
if(new_style)
H.hair_style = new_style
H.update_hair()
/obj/structure/mirror/examine_status(mob/user)
if(broken)
return // no message spam
..()
/obj/structure/mirror/obj_break(damage_flag)
if(!broken && !(flags_1 & NODECONSTRUCT_1))
icon_state = "mirror_broke"
playsound(src, "shatter", 70, 1)
desc = "Oh no, seven years of bad luck!"
broken = 1
/obj/structure/mirror/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
if(!disassembled)
new /obj/item/shard( src.loc )
qdel(src)
/obj/structure/mirror/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/weldingtool) && user.a_intent != INTENT_HARM)
var/obj/item/weldingtool/WT = I
if(broken)
user.changeNext_move(CLICK_CD_MELEE)
if(WT.remove_fuel(0, user))
to_chat(user, "<span class='notice'>You begin repairing [src]...</span>")
playsound(src, 'sound/items/welder.ogg', 100, 1)
if(do_after(user, 10*I.toolspeed, target = src))
if(!user || !WT || !WT.isOn())
return
to_chat(user, "<span class='notice'>You repair [src].</span>")
broken = 0
icon_state = initial(icon_state)
desc = initial(desc)
else
return ..()
/obj/structure/mirror/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
switch(damage_type)
if(BRUTE)
playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 70, 1)
if(BURN)
playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 70, 1)
/obj/structure/mirror/magic
name = "magic mirror"
desc = "Turn and face the strange... face."
icon_state = "magic_mirror"
var/list/races_blacklist = list("skeleton", "agent", "angel", "military_synth", "memezombie")
var/list/choosable_races = list()
/obj/structure/mirror/magic/New()
if(!choosable_races.len)
for(var/speciestype in subtypesof(/datum/species))
var/datum/species/S = new speciestype()
if(!(S.id in races_blacklist))
choosable_races += S.id
..()
/obj/structure/mirror/magic/lesser/New()
var/list/L = CONFIG_GET(keyed_flag_list/roundstart_races)
choosable_races = L.Copy()
..()
/obj/structure/mirror/magic/badmin/New()
for(var/speciestype in subtypesof(/datum/species))
var/datum/species/S = new speciestype()
choosable_races += S.id
..()
/obj/structure/mirror/magic/attack_hand(mob/user)
if(!ishuman(user))
return
var/mob/living/carbon/human/H = user
var/choice = input(user, "Something to change?", "Magical Grooming") as null|anything in list("name", "race", "gender", "hair", "eyes")
if(!Adjacent(user))
return
switch(choice)
if("name")
var/newname = copytext(sanitize(input(H, "Who are we again?", "Name change", H.name) as null|text),1,MAX_NAME_LEN)
if(!newname)
return
if(!Adjacent(user))
return
H.real_name = newname
H.name = newname
if(H.dna)
H.dna.real_name = newname
if(H.mind)
H.mind.name = newname
if("race")
var/newrace
var/racechoice = input(H, "What are we again?", "Race change") as null|anything in choosable_races
newrace = GLOB.species_list[racechoice]
if(!newrace)
return
if(!Adjacent(user))
return
H.set_species(newrace, icon_update=0)
if(H.dna.species.use_skintones)
var/new_s_tone = input(user, "Choose your skin tone:", "Race change") as null|anything in GLOB.skin_tones
if(new_s_tone)
H.skin_tone = new_s_tone
H.dna.update_ui_block(DNA_SKIN_TONE_BLOCK)
if(MUTCOLORS in H.dna.species.species_traits)
var/new_mutantcolor = input(user, "Choose your skin color:", "Race change") as color|null
if(new_mutantcolor)
var/temp_hsv = RGBtoHSV(new_mutantcolor)
if(ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright
H.dna.features["mcolor"] = sanitize_hexcolor(new_mutantcolor)
else
to_chat(H, "<span class='notice'>Invalid color. Your color is not bright enough.</span>")
H.update_body()
H.update_hair()
H.update_body_parts()
H.update_mutations_overlay() // no hulk lizard
if("gender")
if(!(H.gender in list("male", "female"))) //blame the patriarchy
return
if(!Adjacent(user))
return
if(H.gender == "male")
if(alert(H, "Become a Witch?", "Confirmation", "Yes", "No") == "Yes")
H.gender = "female"
to_chat(H, "<span class='notice'>Man, you feel like a woman!</span>")
else
return
else
if(alert(H, "Become a Warlock?", "Confirmation", "Yes", "No") == "Yes")
H.gender = "male"
to_chat(H, "<span class='notice'>Whoa man, you feel like a man!</span>")
else
return
H.dna.update_ui_block(DNA_GENDER_BLOCK)
H.update_body()
H.update_mutations_overlay() //(hulk male/female)
if("hair")
var/hairchoice = alert(H, "Hair style or hair color?", "Change Hair", "Style", "Color")
if(!Adjacent(user))
return
if(hairchoice == "Style") //So you just want to use a mirror then?
..()
else
var/new_hair_color = input(H, "Choose your hair color", "Hair Color") as null|color
if(new_hair_color)
H.hair_color = sanitize_hexcolor(new_hair_color)
H.dna.update_ui_block(DNA_HAIR_COLOR_BLOCK)
if(H.gender == "male")
var/new_face_color = input(H, "Choose your facial hair color", "Hair Color") as null|color
if(new_face_color)
H.facial_hair_color = sanitize_hexcolor(new_face_color)
H.dna.update_ui_block(DNA_FACIAL_HAIR_COLOR_BLOCK)
H.update_hair()
if("eyes")
var/new_eye_color = input(H, "Choose your eye color", "Eye Color") as null|color
if(!Adjacent(user))
return
if(new_eye_color)
H.eye_color = sanitize_hexcolor(new_eye_color)
H.dna.update_ui_block(DNA_EYE_COLOR_BLOCK)
H.update_body()
if(choice)
curse(user)
/obj/structure/mirror/magic/proc/curse(mob/living/user)
return
+1 -1
View File
@@ -66,7 +66,7 @@
return
/turf/open/space/proc/update_starlight()
if(config.starlight)
if(CONFIG_GET(flag/starlight))
for(var/t in RANGE_TURFS(1,src)) //RANGE_TURFS is in code\__HELPERS\game.dm
if(isspaceturf(t))
//let's NOT update this that much pls
+31 -29
View File
@@ -12,7 +12,7 @@ GLOBAL_PROTECT(security_mode)
make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once)
config = new
new /datum/controller/configuration
CheckSchemaVersion()
SetRoundID()
@@ -25,7 +25,7 @@ GLOBAL_PROTECT(security_mode)
load_motd()
load_admins()
LoadVerbs(/datum/verbs/menu)
if(config.usewhitelist)
if(CONFIG_GET(flag/usewhitelist))
load_whitelist()
LoadBans()
@@ -33,7 +33,7 @@ GLOBAL_PROTECT(security_mode)
Master.Initialize(10, FALSE)
if(config.irc_announce_new_game)
if(CONFIG_GET(flag/irc_announce_new_game))
IRCBroadcast("New round starting on [SSmapping.config.map_name]!")
/world/proc/SetupExternalRSC()
@@ -48,7 +48,7 @@ GLOBAL_PROTECT(security_mode)
#endif
/world/proc/CheckSchemaVersion()
if(config.sql_enabled)
if(CONFIG_GET(flag/sql_enabled))
if(SSdbcore.Connect())
log_world("Database connection established.")
var/datum/DBQuery/query_db_version = SSdbcore.NewQuery("SELECT major, minor FROM [format_table_name("schema_revision")] ORDER BY date DESC LIMIT 1")
@@ -68,7 +68,7 @@ GLOBAL_PROTECT(security_mode)
log_world("Your server failed to establish a connection with the database.")
/world/proc/SetRoundID()
if(config.sql_enabled)
if(CONFIG_GET(flag/sql_enabled))
if(SSdbcore.Connect())
var/datum/DBQuery/query_round_start = SSdbcore.NewQuery("INSERT INTO [format_table_name("round")] (start_datetime, server_ip, server_port) VALUES (Now(), INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]')")
query_round_start.Execute()
@@ -122,12 +122,13 @@ GLOBAL_PROTECT(security_mode)
var/pinging = ("ping" in input)
var/playing = ("players" in input)
if(!pinging && !playing && config && config.log_world_topic)
if(!pinging && !playing && config && CONFIG_GET(flag/log_world_topic))
WRITE_FILE(GLOB.world_game_log, "TOPIC: \"[T]\", from:[addr], master:[master], key:[key]")
if(input[SERVICE_CMD_PARAM_KEY])
return ServiceCommand(input)
var/key_valid = (global.comms_allowed && input["key"] == global.comms_key)
var/comms_key = CONFIG_GET(string/comms_key)
var/key_valid = (comms_key && input["key"] == comms_key)
if(pinging)
var/x = 1
@@ -157,10 +158,10 @@ GLOBAL_PROTECT(security_mode)
var/list/s = list()
s["version"] = GLOB.game_version
s["mode"] = GLOB.master_mode
s["respawn"] = config ? GLOB.abandon_allowed : 0
s["respawn"] = config ? !CONFIG_GET(flag/norespawn) : FALSE
s["enter"] = GLOB.enter_allowed
s["vote"] = config.allow_vote_mode
s["ai"] = config.allow_ai
s["vote"] = CONFIG_GET(flag/allow_vote_mode)
s["ai"] = CONFIG_GET(flag/allow_ai)
s["host"] = host ? host : null
s["active_players"] = get_active_player_count()
s["players"] = GLOB.clients.len
@@ -262,17 +263,6 @@ GLOBAL_PROTECT(security_mode)
GLOB.join_motd = file2text("config/motd.txt") + "<br>" + GLOB.revdata.GetTestMergeInfo()
/world/proc/update_status()
var/s = ""
if (config && config.server_name)
s += "<b>[config.server_name]</b> &#8212; "
s += "<b>[station_name()]</b>";
s += " ("
s += "<a href=\"http://\">" //Change this to wherever you want the hub to link to.
s += "Default" //Replace this with something else. Or ever better, delete it and uncomment the game version.
s += "</a>"
s += ")"
var/list/features = list()
@@ -282,13 +272,25 @@ GLOBAL_PROTECT(security_mode)
if (!GLOB.enter_allowed)
features += "closed"
features += GLOB.abandon_allowed ? "respawn" : "no respawn"
var/s = ""
var/hostedby
if(config)
var/server_name = CONFIG_GET(string/servername)
if (server_name)
s += "<b>[server_name]</b> &#8212; "
features += "[CONFIG_GET(flag/norespawn) ? "no " : ""]respawn"
if(CONFIG_GET(flag/allow_vote_mode))
features += "vote"
if(CONFIG_GET(flag/allow_ai))
features += "AI allowed"
hostedby = CONFIG_GET(string/hostedby)
if (config && config.allow_vote_mode)
features += "vote"
if (config && config.allow_ai)
features += "AI allowed"
s += "<b>[station_name()]</b>";
s += " ("
s += "<a href=\"http://\">" //Change this to wherever you want the hub to link to.
s += "Default" //Replace this with something else. Or ever better, delete it and uncomment the game version.
s += "</a>"
s += ")"
var/n = 0
for (var/mob/M in GLOB.player_list)
@@ -300,8 +302,8 @@ GLOBAL_PROTECT(security_mode)
else if (n > 0)
features += "~[n] player"
if (!host && config && config.hostedby)
features += "hosted by <b>[config.hostedby]</b>"
if (!host && hostedby)
features += "hosted by <b>[hostedby]</b>"
if (features)
s += ": [jointext(features, ", ")]"
+7 -6
View File
@@ -20,7 +20,7 @@
admin = 1
//Whitelist
if(config.usewhitelist)
if(CONFIG_GET(flag/usewhitelist))
if(!check_whitelist(ckey(key)))
if (admin)
log_admin("The admin [key] has been allowed to bypass the whitelist")
@@ -32,19 +32,20 @@
//Guest Checking
if(IsGuestKey(key))
if (!GLOB.guests_allowed)
if (CONFIG_GET(flag/guest_ban))
log_access("Failed Login: [key] - Guests not allowed")
return list("reason"="guest", "desc"="\nReason: Guests not allowed. Please sign in with a byond account.")
if (config.panic_bunker && SSdbcore && SSdbcore.IsConnected())
if (CONFIG_GET(flag/panic_bunker) && SSdbcore.Connect())
log_access("Failed Login: [key] - Guests not allowed during panic bunker")
return list("reason"="guest", "desc"="\nReason: Sorry but the server is currently not accepting connections from never before seen players or guests. If you have played on this server with a byond account before, please log in to the byond account you have played from.")
//Population Cap Checking
if(config.extreme_popcap && living_player_count() >= config.extreme_popcap && !admin)
var/extreme_popcap = CONFIG_GET(number/extreme_popcap)
if(extreme_popcap && living_player_count() >= extreme_popcap && !admin)
log_access("Failed Login: [key] - Population cap reached")
return list("reason"="popcap", "desc"= "\nReason: [config.extreme_popcap_message]")
return list("reason"="popcap", "desc"= "\nReason: [CONFIG_GET(string/extreme_popcap_message)]")
if(config.ban_legacy_system)
if(CONFIG_GET(flag/ban_legacy_system))
//Ban Checking
. = CheckBan( ckey(key), computer_id, address )
+3 -2
View File
@@ -11,8 +11,9 @@ GLOBAL_PROTECT(Banlist)
. = list()
var/appeal
if(config && config.banappeals)
appeal = "\nFor more information on your ban, or to appeal, head to <a href='[config.banappeals]'>[config.banappeals]</a>"
var/bran = CONFIG_GET(string/banappeals)
if(bran)
appeal = "\nFor more information on your ban, or to appeal, head to <a href='[bran]'>[bran]</a>"
GLOB.Banlist.cd = "/base"
if( "[ckey][id]" in GLOB.Banlist.dir )
GLOB.Banlist.cd = "[ckey][id]"
+19 -16
View File
@@ -31,7 +31,7 @@
if(M.client)
body += " played by <b>[M.client]</b> "
body += "\[<A href='?_src_=holder;[HrefToken()];editrights=rank;ckey=[M.ckey]'>[M.client.holder ? M.client.holder.rank : "Player"]</A>\]"
if(config.use_exp_tracking)
if(CONFIG_GET(flag/use_exp_tracking))
body += "\[<A href='?_src_=holder;[HrefToken()];getplaytimewindow=\ref[M]'>" + M.client.get_exp_living() + "</a>\]"
if(isnewplayer(M))
@@ -555,28 +555,30 @@
set category = "Server"
set desc="People can't be AI"
set name="Toggle AI"
config.allow_ai = !( config.allow_ai )
if (!( config.allow_ai ))
var/alai = CONFIG_GET(flag/allow_ai)
CONFIG_SET(flag/allow_ai, !alai)
if (alai)
to_chat(world, "<B>The AI job is no longer chooseable.</B>")
else
to_chat(world, "<B>The AI job is chooseable now.</B>")
log_admin("[key_name(usr)] toggled AI allowed.")
world.update_status()
SSblackbox.add_details("admin_toggle","Toggle AI|[config.allow_ai]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
SSblackbox.add_details("admin_toggle","Toggle AI|[!alai]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/datum/admins/proc/toggleaban()
set category = "Server"
set desc="Respawn basically"
set name="Toggle Respawn"
GLOB.abandon_allowed = !( GLOB.abandon_allowed )
if (GLOB.abandon_allowed)
var/new_nores = !CONFIG_GET(flag/norespawn)
CONFIG_SET(flag/norespawn, new_nores)
if (!new_nores)
to_chat(world, "<B>You may now respawn.</B>")
else
to_chat(world, "<B>You may no longer respawn :(</B>")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled respawn to [GLOB.abandon_allowed ? "On" : "Off"].</span>")
log_admin("[key_name(usr)] toggled respawn to [GLOB.abandon_allowed ? "On" : "Off"].")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled respawn to [!new_nores ? "On" : "Off"].</span>")
log_admin("[key_name(usr)] toggled respawn to [!new_nores ? "On" : "Off"].")
world.update_status()
SSblackbox.add_details("admin_toggle","Toggle Respawn|[GLOB.abandon_allowed]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
SSblackbox.add_details("admin_toggle","Toggle Respawn|[!new_nores]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/datum/admins/proc/delay()
set category = "Server"
@@ -683,14 +685,15 @@
set category = "Server"
set desc="Guests can't enter"
set name="Toggle guests"
GLOB.guests_allowed = !( GLOB.guests_allowed )
if (!( GLOB.guests_allowed ))
var/new_guest_ban = !CONFIG_GET(flag/guest_ban)
CONFIG_SET(flag/guest_ban, new_guest_ban)
if (new_guest_ban)
to_chat(world, "<B>Guests may no longer enter the game.</B>")
else
to_chat(world, "<B>Guests may now enter the game.</B>")
log_admin("[key_name(usr)] toggled guests game entering [GLOB.guests_allowed?"":"dis"]allowed.")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled guests game entering [GLOB.guests_allowed?"":"dis"]allowed.</span>")
SSblackbox.add_details("admin_toggle","Toggle Guests|[GLOB.guests_allowed]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
log_admin("[key_name(usr)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled guests game entering [!new_guest_ban ? "" : "dis"]allowed.</span>")
SSblackbox.add_details("admin_toggle","Toggle Guests|[!new_guest_ban]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/datum/admins/proc/output_ai_laws()
var/ai_number = 0
@@ -828,10 +831,10 @@
/client/proc/adminGreet(logout)
if(SSticker.HasRoundStarted())
var/string
if(logout && config && config.announce_admin_logout)
if(logout && CONFIG_GET(flag/announce_admin_logout))
string = pick(
"Admin logout: [key_name(src)]")
else if(!logout && config && config.announce_admin_login && (prefs.toggles & ANNOUNCE_LOGIN))
else if(!logout && CONFIG_GET(flag/announce_admin_login) && (prefs.toggles & ANNOUNCE_LOGIN))
string = pick(
"Admin login: [key_name(src)]")
if(string)
+4 -4
View File
@@ -117,7 +117,7 @@ GLOBAL_PROTECT(admin_ranks)
return
GLOB.admin_ranks.Cut()
if(config.admin_legacy_system)
if(CONFIG_GET(flag/admin_legacy_system))
var/previous_rights = 0
//load text from file and process each line separately
for(var/line in world.file2list("config/admin_ranks.txt"))
@@ -143,7 +143,7 @@ GLOBAL_PROTECT(admin_ranks)
if(!SSdbcore.Connect())
log_world("Failed to connect to database in load_admin_ranks(). Reverting to legacy system.")
WRITE_FILE(GLOB.world_game_log, "Failed to connect to database in load_admin_ranks(). Reverting to legacy system.")
config.admin_legacy_system = 1
CONFIG_SET(flag/admin_legacy_system, TRUE)
load_admin_ranks()
return
@@ -191,7 +191,7 @@ GLOBAL_PROTECT(admin_ranks)
for(var/datum/admin_rank/R in GLOB.admin_ranks)
rank_names[R.name] = R
if(config.admin_legacy_system)
if(CONFIG_GET(flag/admin_legacy_system))
//load text from file
var/list/lines = world.file2list("config/admins.txt")
@@ -219,7 +219,7 @@ GLOBAL_PROTECT(admin_ranks)
if(!SSdbcore.Connect())
log_world("Failed to connect to database in load_admins(). Reverting to legacy system.")
WRITE_FILE(GLOB.world_game_log, "Failed to connect to database in load_admins(). Reverting to legacy system.")
config.admin_legacy_system = 1
CONFIG_SET(flag/admin_legacy_system, TRUE)
load_admins()
return
+2 -2
View File
@@ -262,7 +262,7 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
verbs += GLOB.admin_verbs_poll
if(rights & R_SOUNDS)
verbs += GLOB.admin_verbs_sounds
if(config.invoke_youtubedl)
if(CONFIG_GET(string/invoke_youtubedl))
verbs += /client/proc/play_web_sound
if(rights & R_SPAWN)
verbs += GLOB.admin_verbs_spawn
@@ -399,7 +399,7 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
set name = "Unban Panel"
set category = "Admin"
if(holder)
if(config.ban_legacy_system)
if(CONFIG_GET(flag/ban_legacy_system))
holder.unbanpanel()
else
holder.DB_ban_panel()
+10 -9
View File
@@ -14,18 +14,18 @@
. = FALSE
if (intel < 0)
return
if (intel <= config.ipintel_rating_bad)
if (world.realtime < cacherealtime+(config.ipintel_save_good*60*60*10))
if (intel <= CONFIG_GET(number/ipintel_rating_bad))
if (world.realtime < cacherealtime + (CONFIG_GET(number/ipintel_save_good) * 60 * 60 * 10))
return TRUE
else
if (world.realtime < cacherealtime+(config.ipintel_save_bad*60*60*10))
if (world.realtime < cacherealtime + (CONFIG_GET(number/ipintel_save_bad) * 60 * 60 * 10))
return TRUE
/proc/get_ip_intel(ip, bypasscache = FALSE, updatecache = TRUE)
var/datum/ipintel/res = new()
res.ip = ip
. = res
if (!ip || !config.ipintel_email || !SSipintel.enabled)
if (!ip || !CONFIG_GET(string/ipintel_email) || !SSipintel.enabled)
return
if (!bypasscache)
var/datum/ipintel/cachedintel = SSipintel.cache[ip]
@@ -34,19 +34,20 @@
return cachedintel
if(SSdbcore.Connect())
var/rating_bad = CONFIG_GET(number/ipintel_rating_bad)
var/datum/DBQuery/query_get_ip_intel = SSdbcore.NewQuery({"
SELECT date, intel, TIMESTAMPDIFF(MINUTE,date,NOW())
FROM [format_table_name("ipintel")]
WHERE
ip = INET_ATON('[ip]')
AND ((
intel < [config.ipintel_rating_bad]
intel < [rating_bad]
AND
date + INTERVAL [config.ipintel_save_good] HOUR > NOW()
date + INTERVAL [CONFIG_GET(number/ipintel_save_good)] HOUR > NOW()
) OR (
intel >= [config.ipintel_rating_bad]
intel >= [rating_bad]
AND
date + INTERVAL [config.ipintel_save_bad] HOUR > NOW()
date + INTERVAL [CONFIG_GET(number/ipintel_save_bad)] HOUR > NOW()
))
"})
if(!query_get_ip_intel.Execute())
@@ -77,7 +78,7 @@
if (!SSipintel.enabled)
return
var/list/http[] = world.Export("http://[config.ipintel_domain]/check.php?ip=[ip]&contact=[config.ipintel_email]&format=json&flags_1=f")
var/list/http[] = world.Export("http://[CONFIG_GET(string/ipintel_domain)]/check.php?ip=[ip]&contact=[CONFIG_GET(string/ipintel_email)]&format=json&flags=f")
if (http)
var/status = text2num(http["STATUS"])
@@ -51,7 +51,7 @@
usr << browse(output,"window=editrights;size=900x650")
/datum/admins/proc/log_admin_rank_modification(adm_ckey, new_rank)
if(config.admin_legacy_system)
if(CONFIG_GET(flag/admin_legacy_system))
return
if(!usr.client)
@@ -105,7 +105,7 @@
/datum/admins/proc/log_admin_permission_modification(adm_ckey, new_permission)
if(config.admin_legacy_system)
if(CONFIG_GET(flag/admin_legacy_system))
return
if(!usr.client)
return
+6 -6
View File
@@ -329,14 +329,14 @@
else
dat += "ETA: <a href='?_src_=holder;[HrefToken()];edit_shuttle_time=1'>[(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]</a><BR>"
dat += "<B>Continuous Round Status</B><BR>"
dat += "<a href='?_src_=holder;[HrefToken()];toggle_continuous=1'>[config.continuous[SSticker.mode.config_tag] ? "Continue if antagonists die" : "End on antagonist death"]</a>"
if(config.continuous[SSticker.mode.config_tag])
dat += ", <a href='?_src_=holder;[HrefToken()];toggle_midround_antag=1'>[config.midround_antag[SSticker.mode.config_tag] ? "creating replacement antagonists" : "not creating new antagonists"]</a><BR>"
dat += "<a href='?_src_=holder;[HrefToken()];toggle_continuous=1'>[CONFIG_GET(keyed_flag_list/continuous)[SSticker.mode.config_tag] ? "Continue if antagonists die" : "End on antagonist death"]</a>"
if(CONFIG_GET(keyed_flag_list/continuous)[SSticker.mode.config_tag])
dat += ", <a href='?_src_=holder;[HrefToken()];toggle_midround_antag=1'>[CONFIG_GET(keyed_flag_list/midround_antag)[SSticker.mode.config_tag] ? "creating replacement antagonists" : "not creating new antagonists"]</a><BR>"
else
dat += "<BR>"
if(config.midround_antag[SSticker.mode.config_tag])
dat += "Time limit: <a href='?_src_=holder;[HrefToken()];alter_midround_time_limit=1'>[config.midround_antag_time_check] minutes into round</a><BR>"
dat += "Living crew limit: <a href='?_src_=holder;[HrefToken()];alter_midround_life_limit=1'>[config.midround_antag_life_check * 100]% of crew alive</a><BR>"
if(CONFIG_GET(keyed_flag_list/midround_antag)[SSticker.mode.config_tag])
dat += "Time limit: <a href='?_src_=holder;[HrefToken()];alter_midround_time_limit=1'>[CONFIG_GET(number/midround_antag_time_check)] minutes into round</a><BR>"
dat += "Living crew limit: <a href='?_src_=holder;[HrefToken()];alter_midround_life_limit=1'>[CONFIG_GET(number/midround_antag_life_check) * 100]% of crew alive</a><BR>"
dat += "If limits past: <a href='?_src_=holder;[HrefToken()];toggle_noncontinuous_behavior=1'>[SSticker.mode.round_ends_with_antag_death ? "End The Round" : "Continue As Extended"]</a><BR>"
dat += "<a href='?_src_=holder;[HrefToken()];end_round=\ref[usr]'>End Round Now</a><br>"
dat += "<a href='?_src_=holder;[HrefToken()];delay_round_end=1'>[SSticker.delay_end ? "End Round Normally" : "Delay Round End"]</a>"
+1 -8
View File
@@ -354,16 +354,9 @@
SSblackbox.add_details("admin_secrets_fun_used","Bomb Cap")
var/newBombCap = input(usr,"What would you like the new bomb cap to be. (entered as the light damage range (the 3rd number in common (1,2,3) notation)) Must be above 4)", "New Bomb Cap", GLOB.MAX_EX_LIGHT_RANGE) as num|null
if (newBombCap < 4)
if (!CONFIG_SET(number/bombcap, newBombCap))
return
GLOB.MAX_EX_DEVESTATION_RANGE = round(newBombCap/4)
GLOB.MAX_EX_HEAVY_RANGE = round(newBombCap/2)
GLOB.MAX_EX_LIGHT_RANGE = newBombCap
//I don't know why these are their own variables, but fuck it, they are.
GLOB.MAX_EX_FLASH_RANGE = newBombCap
GLOB.MAX_EX_FLAME_RANGE = newBombCap
message_admins("<span class='boldannounce'>[key_name_admin(usr)] changed the bomb cap to [GLOB.MAX_EX_DEVESTATION_RANGE], [GLOB.MAX_EX_HEAVY_RANGE], [GLOB.MAX_EX_LIGHT_RANGE]</span>")
log_admin("[key_name(usr)] changed the bomb cap to [GLOB.MAX_EX_DEVESTATION_RANGE], [GLOB.MAX_EX_HEAVY_RANGE], [GLOB.MAX_EX_LIGHT_RANGE]")
+10 -6
View File
@@ -33,8 +33,9 @@
if(!timestamp)
timestamp = SQLtime()
if(!server)
if (config && config.server_sql_name)
server = config.server_sql_name
var/ssqlname = CONFIG_GET(string/serversqlname)
if (ssqlname)
server = ssqlname
server = sanitizeSQL(server)
if(isnull(secret))
switch(alert("Hide note from being viewed by players?", "Secret note?","Yes","No","Cancel"))
@@ -216,8 +217,10 @@
var/editor_ckey = query_get_messages.item[8]
var/age = text2num(query_get_messages.item[9])
var/alphatext = ""
if (agegate && type == "note" && isnum(config.note_stale_days) && isnum(config.note_fresh_days) && config.note_stale_days > config.note_fresh_days)
var/alpha = Clamp(100 - (age - config.note_fresh_days) * (85 / (config.note_stale_days - config.note_fresh_days)), 15, 100)
var/nsd = CONFIG_GET(number/note_stale_days)
var/nfd = CONFIG_GET(number/note_fresh_days)
if (agegate && type == "note" && isnum(nsd) && isnum(nfd) && nsd > nfd)
var/alpha = Clamp(100 - (age - nfd) * (85 / (nsd - nfd)), 15, 100)
if (alpha < 100)
if (alpha <= 15)
if (skipped)
@@ -353,8 +356,9 @@ proc/get_message_output(type, target_ckey)
var/notetext
notesfile >> notetext
var/server
if(config && config.server_sql_name)
server = config.server_sql_name
var/ssqlname = CONFIG_GET(string/serversqlname)
if (ssqlname)
server = ssqlname
var/regex/note = new("^(\\d{2}-\\w{3}-\\d{4}) \\| (.+) ~(\\w+)$", "i")
note.Find(notetext)
var/timestamp = note.group[1]
+26 -21
View File
@@ -5,7 +5,7 @@
return
var/msg = !auth ? "no" : "a bad"
message_admins("[key_name_admin(usr)] clicked an href with [msg] authorization key!")
if(config.debug_admin_hrefs)
if(CONFIG_GET(flag/debug_admin_hrefs))
message_admins("Debug mode enabled, call not blocked. Please ask your coders to review this round's logs.")
log_world("UAH: [href]")
return TRUE
@@ -318,35 +318,36 @@
else if(href_list["toggle_continuous"])
if(!check_rights(R_ADMIN))
return
if(!config.continuous[SSticker.mode.config_tag])
config.continuous[SSticker.mode.config_tag] = 1
var/list/continuous = CONFIG_GET(keyed_flag_list/continuous)
if(!continuous[SSticker.mode.config_tag])
continuous[SSticker.mode.config_tag] = TRUE
else
config.continuous[SSticker.mode.config_tag] = 0
continuous[SSticker.mode.config_tag] = FALSE
message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled the round to [config.continuous[SSticker.mode.config_tag] ? "continue if all antagonists die" : "end with the antagonists"].</span>")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled the round to [continuous[SSticker.mode.config_tag] ? "continue if all antagonists die" : "end with the antagonists"].</span>")
check_antagonists()
else if(href_list["toggle_midround_antag"])
if(!check_rights(R_ADMIN))
return
if(!config.midround_antag[SSticker.mode.config_tag])
config.midround_antag[SSticker.mode.config_tag] = 1
var/list/midround_antag = CONFIG_GET(keyed_flag_list/midround_antag)
if(!midround_antag[SSticker.mode.config_tag])
midround_antag[SSticker.mode.config_tag] = TRUE
else
config.midround_antag[SSticker.mode.config_tag] = 0
midround_antag[SSticker.mode.config_tag] = FALSE
message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled the round to [config.midround_antag[SSticker.mode.config_tag] ? "use" : "skip"] the midround antag system.</span>")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled the round to [midround_antag[SSticker.mode.config_tag] ? "use" : "skip"] the midround antag system.</span>")
check_antagonists()
else if(href_list["alter_midround_time_limit"])
if(!check_rights(R_ADMIN))
return
var/timer = input("Enter new maximum time",, config.midround_antag_time_check ) as num|null
var/timer = input("Enter new maximum time",, CONFIG_GET(number/midround_antag_time_check)) as num|null
if(!timer)
return
config.midround_antag_time_check = timer
CONFIG_SET(number/midround_antag_time_check, timer)
message_admins("<span class='adminnotice'>[key_name_admin(usr)] edited the maximum midround antagonist time to [timer] minutes.</span>")
check_antagonists()
@@ -354,9 +355,10 @@
if(!check_rights(R_ADMIN))
return
var/ratio = input("Enter new life ratio",, config.midround_antag_life_check*100) as num
if(ratio)
config.midround_antag_life_check = ratio/100
var/ratio = input("Enter new life ratio",, CONFIG_GET(number/midround_antag_life_check) * 100) as num
if(!ratio)
return
CONFIG_SET(number/midround_antag_life_check, ratio / 100)
message_admins("<span class='adminnotice'>[key_name_admin(usr)] edited the midround antagonist living crew ratio to [ratio]% alive.</span>")
check_antagonists()
@@ -586,8 +588,9 @@
to_chat(M, "<span class='boldannounce'><BIG>You have been appearance banned by [usr.client.ckey].</BIG></span>")
to_chat(M, "<span class='boldannounce'>The reason is: [reason]</span>")
to_chat(M, "<span class='danger'>Appearance ban can be lifted only upon request.</span>")
if(config.banappeals)
to_chat(M, "<span class='danger'>To try to resolve this matter head to [config.banappeals]</span>")
var/bran = CONFIG_GET(string/banappeals)
if(bran)
to_chat(M, "<span class='danger'>To try to resolve this matter head to [bran]</span>")
else
to_chat(M, "<span class='danger'>No ban appeals URL has been set.</span>")
if("No")
@@ -1156,8 +1159,9 @@
to_chat(M, "<span class='danger'>This is a temporary ban, it will be removed in [mins] minutes.</span>")
SSblackbox.inc("ban_tmp",1)
SSblackbox.inc("ban_tmp_mins",mins)
if(config.banappeals)
to_chat(M, "<span class='danger'>To try to resolve this matter head to [config.banappeals]</span>")
var/bran = CONFIG_GET(string/banappeals)
if(bran)
to_chat(M, "<span class='danger'>To try to resolve this matter head to [bran]</span>")
else
to_chat(M, "<span class='danger'>No ban appeals URL has been set.</span>")
log_admin_private("[key_name(usr)] has banned [M.ckey].\nReason: [key_name(M)]\nThis will be removed in [mins] minutes.")
@@ -1180,8 +1184,9 @@
AddBan(M.ckey, M.computer_id, reason, usr.ckey, 0, 0)
to_chat(M, "<span class='boldannounce'><BIG>You have been banned by [usr.client.ckey].\nReason: [reason]</BIG></span>")
to_chat(M, "<span class='danger'>This is a permanent ban.</span>")
if(config.banappeals)
to_chat(M, "<span class='danger'>To try to resolve this matter head to [config.banappeals]</span>")
var/bran = CONFIG_GET(string/banappeals)
if(bran)
to_chat(M, "<span class='danger'>To try to resolve this matter head to [bran]</span>")
else
to_chat(M, "<span class='danger'>No ban appeals URL has been set.</span>")
if(!DB_ban_record(BANTYPE_PERMA, M, -1, reason))
+6 -5
View File
@@ -589,19 +589,20 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
/proc/send2irc(msg,msg2)
if(world.RunningService())
world.ExportService("[SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE] [msg] | [msg2]")
else if(config.useircbot)
else if(CONFIG_GET(flag/useircbot))
shell("python nudge.py [msg] [msg2]")
/proc/send2otherserver(source,msg,type = "Ahelp")
if(config.cross_allowed)
var/comms_key = CONFIG_GET(string/comms_key)
if(comms_key)
var/list/message = list()
message["message_sender"] = source
message["message"] = msg
message["source"] = "([config.cross_name])"
message["key"] = global.comms_key
message["source"] = "([CONFIG_GET(string/cross_comms_name)])"
message["key"] = comms_key
message["crossmessage"] = type
world.Export("[config.cross_address]?[list2params(message)]")
world.Export("[CONFIG_GET(string/cross_server_address)]?[list2params(message)]")
/proc/ircadminwho()
+2 -2
View File
@@ -185,7 +185,7 @@
SEND_SOUND(recipient, sound('sound/effects/adminhelp.ogg'))
//AdminPM popup for ApocStation and anybody else who wants to use it. Set it with POPUP_ADMIN_PM in config.txt ~Carn
if(config.popup_admin_pm)
if(CONFIG_GET(flag/popup_admin_pm))
spawn() //so we don't hold the caller proc up
var/sender = src
var/sendername = key
@@ -277,7 +277,7 @@
return "Error: Ticket could not be found"
var/static/stealthkey
var/adminname = config.showircname ? irc_tagged : "Administrator"
var/adminname = CONFIG_GET(flag/show_irc_name) ? irc_tagged : "Administrator"
if(!C)
return "Error: No client"
+3 -3
View File
@@ -845,11 +845,11 @@ GLOBAL_PROTECT(LastAdminCalledProc)
if(!holder)
return
global.medals_enabled = !global.medals_enabled
GLOB.medals_enabled = !GLOB.medals_enabled
message_admins("<span class='adminnotice'>[key_name_admin(src)] [global.medals_enabled ? "disabled" : "enabled"] the medal hub lockout.</span>")
message_admins("<span class='adminnotice'>[key_name_admin(src)] [GLOB.medals_enabled ? "disabled" : "enabled"] the medal hub lockout.</span>")
SSblackbox.add_details("admin_verb","Toggle Medal Disable") // If...
log_admin("[key_name(src)] [global.medals_enabled ? "disabled" : "enabled"] the medal hub lockout.")
log_admin("[key_name(src)] [GLOB.medals_enabled ? "disabled" : "enabled"] the medal hub lockout.")
/client/proc/view_runtimes()
set category = "Debug"
+5 -3
View File
@@ -7,13 +7,14 @@
if(!check_rights(R_DEBUG))
return
var/new_fps = round(input("Sets game frames-per-second. Can potentially break the game (default: [config.fps])","FPS", world.fps) as num|null)
var/cfg_fps = CONFIG_GET(number/fps)
var/new_fps = round(input("Sets game frames-per-second. Can potentially break the game (default: [cfg_fps])","FPS", world.fps) as num|null)
if(new_fps <= 0)
to_chat(src, "<span class='danger'>Error: set_server_fps(): Invalid world.fps value. No changes made.</span>")
return
if(new_fps > config.fps*1.5)
if(alert(src, "You are setting fps to a high value:\n\t[new_fps] frames-per-second\n\tconfig.fps = [config.fps]","Warning!","Confirm","ABORT-ABORT-ABORT") != "Confirm")
if(new_fps > cfg_fps * 1.5)
if(alert(src, "You are setting fps to a high value:\n\t[new_fps] frames-per-second\n\tconfig.fps = [cfg_fps]","Warning!","Confirm","ABORT-ABORT-ABORT") != "Confirm")
return
var/msg = "[key_name(src)] has modified world.fps to [new_fps]"
@@ -21,4 +22,5 @@
message_admins(msg, 0)
SSblackbox.add_details("admin_toggle","Set Server FPS|[new_fps]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
CONFIG_SET(number/fps, new_fps)
world.fps = new_fps
+13 -13
View File
@@ -31,10 +31,10 @@
/datum/admins/proc/makeTraitors()
var/datum/game_mode/traitor/temp = new
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
temp.restricted_jobs += temp.protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
temp.restricted_jobs += "Assistant"
var/list/mob/living/carbon/human/candidates = list()
@@ -67,10 +67,10 @@
/datum/admins/proc/makeChanglings()
var/datum/game_mode/changeling/temp = new
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
temp.restricted_jobs += temp.protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
temp.restricted_jobs += "Assistant"
var/list/mob/living/carbon/human/candidates = list()
@@ -100,10 +100,10 @@
/datum/admins/proc/makeRevs()
var/datum/game_mode/revolution/temp = new
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
temp.restricted_jobs += temp.protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
temp.restricted_jobs += "Assistant"
var/list/mob/living/carbon/human/candidates = list()
@@ -142,10 +142,10 @@
/datum/admins/proc/makeCult()
var/datum/game_mode/cult/temp = new
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
temp.restricted_jobs += temp.protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
temp.restricted_jobs += "Assistant"
var/list/mob/living/carbon/human/candidates = list()
@@ -175,10 +175,10 @@
/datum/admins/proc/makeClockCult()
var/datum/game_mode/clockwork_cult/temp = new
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
temp.restricted_jobs += temp.protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
temp.restricted_jobs += "Assistant"
var/list/mob/living/carbon/human/candidates = list()
@@ -340,7 +340,7 @@
missiondesc += "<BR><B>Your Mission</B>: [mission]"
to_chat(Commando, missiondesc)
if(config.enforce_human_authority)
if(CONFIG_GET(flag/enforce_human_authority))
Commando.set_species(/datum/species/human)
//Logging and cleanup
@@ -382,7 +382,7 @@
missionobj.completed = 1
newmob.mind.objectives += missionobj
if(config.enforce_human_authority)
if(CONFIG_GET(flag/enforce_human_authority))
newmob.set_species(/datum/species/human)
//Greet the official
@@ -497,7 +497,7 @@
missiondesc += "<BR><B>Your Mission</B>: [mission]"
to_chat(ERTOperative, missiondesc)
if(config.enforce_human_authority)
if(CONFIG_GET(flag/enforce_human_authority))
ERTOperative.set_species(/datum/species/human)
//Logging and cleanup
+7 -6
View File
@@ -1,15 +1,16 @@
/client/proc/panicbunker()
set category = "Server"
set name = "Toggle Panic Bunker"
if (!config.sql_enabled)
if (!CONFIG_GET(flag/sql_enabled))
to_chat(usr, "<span class='adminnotice'>The Database is not enabled!</span>")
return
config.panic_bunker = (!config.panic_bunker)
var/new_pb = !CONFIG_GET(flag/panic_bunker)
CONFIG_SET(flag/panic_bunker, new_pb)
log_admin("[key_name(usr)] has toggled the Panic Bunker, it is now [(config.panic_bunker?"on":"off")]")
message_admins("[key_name_admin(usr)] has toggled the Panic Bunker, it is now [(config.panic_bunker?"enabled":"disabled")].")
if (config.panic_bunker && (!SSdbcore || !SSdbcore.IsConnected()))
log_admin("[key_name(usr)] has toggled the Panic Bunker, it is now [new_pb ? "on" : "off"]")
message_admins("[key_name_admin(usr)] has toggled the Panic Bunker, it is now [new_pb ? "enabled" : "disabled"].")
if (new_pb && !SSdbcore.Connect())
message_admins("The Database is not connected! Panic bunker will not work until the connection is reestablished.")
SSblackbox.add_details("admin_toggle","Toggle Panic Bunker|[config.panic_bunker]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
SSblackbox.add_details("admin_toggle","Toggle Panic Bunker|[new_pb]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+3 -2
View File
@@ -62,7 +62,8 @@
if(!check_rights(R_SOUNDS))
return
if(!config.invoke_youtubedl)
var/ytdl = CONFIG_GET(string/invoke_youtubedl)
if(!ytdl)
to_chat(src, "<span class='boldwarning'>Youtube-dl was not configured, action unavailable</span>") //Check config.txt for the INVOKE_YOUTUBEDL value
return
@@ -79,7 +80,7 @@
to_chat(src, "<span class='warning'>For youtube-dl shortcuts like ytsearch: please use the appropriate full url from the website.</span>")
return
var/shell_scrubbed_input = shell_url_scrub(web_sound_input)
var/list/output = world.shelleo("[config.invoke_youtubedl] --format \"bestaudio\[ext=mp3]/best\[ext=mp4]\[height<=360]/bestaudio\[ext=m4a]/bestaudio\[ext=aac]\" --get-url \"[shell_scrubbed_input]\"")
var/list/output = world.shelleo("[ytdl] --format \"bestaudio\[ext=mp3]/best\[ext=mp4]\[height<=360]/bestaudio\[ext=m4a]/bestaudio\[ext=aac]\" --get-url \"[shell_scrubbed_input]\"")
var/errorlevel = output[SHELLEO_ERRORLEVEL]
var/stdout = output[SHELLEO_STDOUT]
var/stderr = output[SHELLEO_STDERR]
+1 -1
View File
@@ -2,7 +2,7 @@
set name = "Possess Obj"
set category = "Object"
if(O.dangerous_possession && config.forbid_singulo_possession)
if(O.dangerous_possession && CONFIG_GET(flag/forbid_singulo_possession))
to_chat(usr, "[O] is too powerful for you to possess.")
return
File diff suppressed because it is too large Load Diff
@@ -1,7 +1,7 @@
/client/proc/reestablish_db_connection()
set category = "Special Verbs"
set name = "Reestablish DB Connection"
if (!config.sql_enabled)
if (!CONFIG_GET(flag/sql_enabled))
to_chat(usr, "<span class='adminnotice'>The Database is not enabled!</span>")
return
+1 -1
View File
@@ -80,7 +80,7 @@ GLOBAL_DATUM(the_gateway, /obj/machinery/gateway/centerstation)
if(!GLOB.the_gateway)
GLOB.the_gateway = src
update_icon()
wait = world.time + config.gateway_delay //+ thirty minutes default
wait = world.time + CONFIG_GET(number/gateway_delay) //+ thirty minutes default
awaygate = locate(/obj/machinery/gateway/centeraway)
/obj/machinery/gateway/centerstation/Destroy()
+42 -37
View File
@@ -42,7 +42,8 @@
to_chat(src, "<span class='danger'>An error has been detected in how your client is receiving resources. Attempting to correct.... (If you keep seeing these messages you might want to close byond and reconnect)</span>")
src << browse("...", "window=asset_cache_browser")
if (!holder && config.minutetopiclimit)
var/mtl = CONFIG_GET(number/minute_topic_limit)
if (!holder && mtl)
var/minute = round(world.time, 600)
if (!topiclimiter)
topiclimiter = new(LIMITER_SIZE)
@@ -50,17 +51,18 @@
topiclimiter[CURRENT_MINUTE] = minute
topiclimiter[MINUTE_COUNT] = 0
topiclimiter[MINUTE_COUNT] += 1
if (topiclimiter[MINUTE_COUNT] > config.minutetopiclimit)
if (topiclimiter[MINUTE_COUNT] > mtl)
var/msg = "Your previous action was ignored because you've done too many in a minute."
if (minute != topiclimiter[ADMINSWARNED_AT]) //only one admin message per-minute. (if they spam the admins can just boot/ban them)
topiclimiter[ADMINSWARNED_AT] = minute
msg += " Administrators have been informed."
log_game("[key_name(src)] Has hit the per-minute topic limit of [config.minutetopiclimit] topic calls in a given game minute")
message_admins("[key_name_admin(src)] [ADMIN_FLW(usr)] [ADMIN_KICK(usr)] Has hit the per-minute topic limit of [config.minutetopiclimit] topic calls in a given game minute")
log_game("[key_name(src)] Has hit the per-minute topic limit of [mtl] topic calls in a given game minute")
message_admins("[key_name_admin(src)] [ADMIN_FLW(usr)] [ADMIN_KICK(usr)] Has hit the per-minute topic limit of [mtl] topic calls in a given game minute")
to_chat(src, "<span class='danger'>[msg]</span>")
return
if (!holder && config.secondtopiclimit)
var/stl = CONFIG_GET(number/second_topic_limit)
if (!holder && stl)
var/second = round(world.time, 10)
if (!topiclimiter)
topiclimiter = new(LIMITER_SIZE)
@@ -68,7 +70,7 @@
topiclimiter[CURRENT_SECOND] = second
topiclimiter[SECOND_COUNT] = 0
topiclimiter[SECOND_COUNT] += 1
if (topiclimiter[SECOND_COUNT] > config.secondtopiclimit)
if (topiclimiter[SECOND_COUNT] > stl)
to_chat(src, "<span class='danger'>Your previous action was ignored because you've done too many in a second</span>")
return
@@ -110,7 +112,7 @@
return 1
/client/proc/handle_spam_prevention(message, mute_type)
if(config.automute_on && !holder && src.last_message == message)
if(CONFIG_GET(flag/automute_on) && !holder && last_message == message)
src.last_message_count++
if(src.last_message_count >= SPAM_TRIGGER_AUTOMUTE)
to_chat(src, "<span class='danger'>You have exceeded the spam filter limit for identical messages. An auto-mute was applied.</span>")
@@ -174,11 +176,11 @@ GLOBAL_LIST(external_rsc_urls)
if(localhost_rank)
var/datum/admins/localhost_holder = new(localhost_rank, ckey)
localhost_holder.associate(src)
if(config.autoadmin)
if(CONFIG_GET(flag/autoadmin))
if(!GLOB.admin_datums[ckey])
var/datum/admin_rank/autorank
for(var/datum/admin_rank/R in GLOB.admin_ranks)
if(R.name == config.autoadmin_rank)
if(R.name == CONFIG_GET(string/autoadmin_rank))
autorank = R
break
if(!autorank)
@@ -206,7 +208,7 @@ GLOBAL_LIST(external_rsc_urls)
log_access("Login: [key_name(src)] from [address ? address : "localhost"]-[computer_id] || BYOND v[byond_version]")
var/alert_mob_dupe_login = FALSE
if(config.log_access)
if(CONFIG_GET(flag/log_access))
for(var/I in GLOB.clients)
if(!I || I == src)
continue
@@ -240,30 +242,32 @@ GLOBAL_LIST(external_rsc_urls)
connection_realtime = world.realtime
connection_timeofday = world.timeofday
winset(src, null, "command=\".configure graphics-hwmode on\"")
if (byond_version < config.client_error_version) //Out of date client.
var/cev = CONFIG_GET(number/client_error_version)
var/cwv = CONFIG_GET(number/client_warn_version)
if (byond_version < cev) //Out of date client.
to_chat(src, "<span class='danger'><b>Your version of byond is too old:</b></span>")
to_chat(src, config.client_error_message)
to_chat(src, CONFIG_GET(string/client_error_message))
to_chat(src, "Your version: [byond_version]")
to_chat(src, "Required version: [config.client_error_version] or later")
to_chat(src, "Required version: [cev] or later")
to_chat(src, "Visit http://www.byond.com/download/ to get the latest version of byond.")
if (holder)
to_chat(src, "Because you are an admin, you are being allowed to walk past this limitation, But it is still STRONGLY suggested you upgrade")
else
qdel(src)
return 0
else if (byond_version < config.client_warn_version) //We have words for this client.
else if (byond_version < cwv) //We have words for this client.
to_chat(src, "<span class='danger'><b>Your version of byond may be getting out of date:</b></span>")
to_chat(src, config.client_warn_message)
to_chat(src, CONFIG_GET(string/client_warn_message))
to_chat(src, "Your version: [byond_version]")
to_chat(src, "Required version to remove this message: [config.client_warn_version] or later")
to_chat(src, "Required version to remove this message: [cwv] or later")
to_chat(src, "Visit http://www.byond.com/download/ to get the latest version of byond.")
if (connection == "web" && !holder)
if (!config.allowwebclient)
if (!CONFIG_GET(flag/allow_webclient))
to_chat(src, "Web client is disabled")
qdel(src)
return 0
if (config.webclientmembersonly && !IsByondMember())
if (CONFIG_GET(flag/webclient_only_byond_members) && !IsByondMember())
to_chat(src, "Sorry, but the web client is restricted to byond members only.")
qdel(src)
return 0
@@ -276,25 +280,24 @@ GLOBAL_LIST(external_rsc_urls)
add_admin_verbs()
to_chat(src, get_message_output("memo"))
adminGreet()
if((global.comms_key == "default_pwd" || length(global.comms_key) <= 6) && global.comms_allowed) //It's the default value or less than 6 characters long, but it somehow didn't disable comms.
to_chat(src, "<span class='danger'>The server's API key is either too short or is the default value! Consider changing it immediately!</span>")
add_verbs_from_config()
var/cached_player_age = set_client_age_from_db(tdata) //we have to cache this because other shit may change it and we need it's current value now down below.
if (isnum(cached_player_age) && cached_player_age == -1) //first connection
player_age = 0
var/nnpa = CONFIG_GET(number/notify_new_player_age)
if (isnum(cached_player_age) && cached_player_age == -1) //first connection
if (config.notify_new_player_age >= 0)
if (nnpa >= 0)
message_admins("New user: [key_name_admin(src)] is connecting here for the first time.")
if (config.irc_first_connection_alert)
if (CONFIG_GET(flag/irc_first_connection_alert))
send2irc_adminless_only("New-user", "[key_name(src)] is connecting for the first time!")
else if (isnum(cached_player_age) && cached_player_age < config.notify_new_player_age)
else if (isnum(cached_player_age) && cached_player_age < nnpa)
message_admins("New user: [key_name_admin(src)] just connected with an age of [cached_player_age] day[(player_age==1?"":"s")]")
if(config.use_account_age_for_jobs && account_age >= 0)
if(CONFIG_GET(flag/use_account_age_for_jobs) && account_age >= 0)
player_age = account_age
if(account_age >= 0 && account_age < config.notify_new_player_account_age)
if(account_age >= 0 && account_age < nnpa)
message_admins("[key_name_admin(src)] (IP: [address], ID: [computer_id]) is a new BYOND account [account_age] day[(account_age==1?"":"s")] old, created on [account_join_date].")
if (config.irc_first_connection_alert)
if (CONFIG_GET(flag/irc_first_connection_alert))
send2irc_adminless_only("new_byond_user", "[key_name(src)] (IP: [address], ID: [computer_id]) is a new BYOND account [account_age] day[(account_age==1?"":"s")] old, created on [account_join_date].")
get_message_output("watchlist entry", ckey)
check_ip_intel()
@@ -306,7 +309,7 @@ GLOBAL_LIST(external_rsc_urls)
if(prefs.lastchangelog != GLOB.changelog_hash) //bolds the changelog button on the interface so we know there are updates.
to_chat(src, "<span class='info'>You have unread updates in the changelog.</span>")
if(config.aggressive_changelog)
if(CONFIG_GET(flag/aggressive_changelog))
changelog()
else
winset(src, "infowindow.changelog", "font-style=bold")
@@ -316,7 +319,7 @@ GLOBAL_LIST(external_rsc_urls)
to_chat(src, message)
GLOB.clientmessages.Remove(ckey)
if(config && config.autoconvert_notes)
if(CONFIG_GET(flag/autoconvert_notes))
convert_notes_sql(ckey)
to_chat(src, get_message_output("message", ckey))
if(!winexists(src, "asset_cache_browser")) // The client is using a custom skin, tell them.
@@ -432,15 +435,17 @@ GLOBAL_LIST(external_rsc_urls)
if(!query_client_in_db.Execute())
return
if(!query_client_in_db.NextRow())
if (config.panic_bunker && !holder && !(ckey in GLOB.deadmins))
if (CONFIG_GET(flag/panic_bunker) && !holder && !(ckey in GLOB.deadmins))
log_access("Failed Login: [key] - New account attempting to connect during panic bunker")
message_admins("<span class='adminnotice'>Failed Login: [key] - New account attempting to connect during panic bunker</span>")
to_chat(src, "Sorry but the server is currently not accepting connections from never before seen players.")
var/list/connectiontopic_a = params2list(connectiontopic)
if(config.panic_address && !connectiontopic_a["redirect"])
to_chat(src, "<span class='notice'>Sending you to [config.panic_server_name ? config.panic_server_name : config.panic_address].</span>")
var/list/panic_addr = CONFIG_GET(string/panic_address)
if(panic_addr && !connectiontopic_a["redirect"])
var/panic_name = CONFIG_GET(string/panic_server_name)
to_chat(src, "<span class='notice'>Sending you to [panic_name ? panic_name : panic_addr].</span>")
winset(src, null, "command=.options")
src << link("[config.panic_address]?redirect=1")
src << link("[panic_addr]?redirect=1")
qdel(src)
return
@@ -501,7 +506,7 @@ GLOBAL_LIST(external_rsc_urls)
if (connection != "seeker")
return
topic = params2list(topic)
if (!config.check_randomizer)
if (!CONFIG_GET(flag/check_randomizer))
return
var/static/cidcheck = list()
var/static/tokens = list()
@@ -594,15 +599,15 @@ GLOBAL_LIST(external_rsc_urls)
/client/proc/check_ip_intel()
set waitfor = 0 //we sleep when getting the intel, no need to hold up the client connection while we sleep
if (config.ipintel_email)
if (CONFIG_GET(string/ipintel_email))
var/datum/ipintel/res = get_ip_intel(address)
if (res.intel >= config.ipintel_rating_bad)
if (res.intel >= CONFIG_GET(number/ipintel_rating_bad))
message_admins("<span class='adminnotice'>Proxy Detection: [key_name_admin(src)] IP intel rated [res.intel*100]% likely to be a Proxy/VPN.</span>")
ip_intel = res.intel
/client/proc/add_verbs_from_config()
if(config.see_own_notes)
if(CONFIG_GET(flag/see_own_notes))
verbs += /client/proc/self_notes
@@ -612,7 +617,7 @@ GLOBAL_LIST(external_rsc_urls)
//checks if a client is afk
//3000 frames = 5 minutes
/client/proc/is_afk(duration = config.inactivity_period)
/client/proc/is_afk(duration = CONFIG_GET(number/inactivity_period))
if(inactivity > duration)
return inactivity
return FALSE
+171 -9
View File
@@ -277,6 +277,168 @@ GLOBAL_LIST_EMPTY(preferences_datums)
// dat += "<b>Size:</b> <a href='?_src_=prefs;preference=character_size;task=input'>[character_size]</a><BR>"
dat += "<br>"
dat += "<h2>Body</h2>"
dat += "<a href='?_src_=prefs;preference=all;task=random'>Random Body</A> "
dat += "<a href='?_src_=prefs;preference=all'>Always Random Body: [be_random_body ? "Yes" : "No"]</A><br>"
dat += "<table width='100%'><tr><td width='24%' valign='top'>"
if(CONFIG_GET(flag/join_with_mutant_race))
dat += "<b>Species:</b><BR><a href='?_src_=prefs;preference=species;task=input'>[pref_species.name]</a><BR>"
else
dat += "<b>Species:</b> Human<BR>"
dat += "<b>Underwear:</b><BR><a href ='?_src_=prefs;preference=underwear;task=input'>[underwear]</a><BR>"
dat += "<b>Undershirt:</b><BR><a href ='?_src_=prefs;preference=undershirt;task=input'>[undershirt]</a><BR>"
dat += "<b>Socks:</b><BR><a href ='?_src_=prefs;preference=socks;task=input'>[socks]</a><BR>"
dat += "<b>Backpack:</b><BR><a href ='?_src_=prefs;preference=bag;task=input'>[backbag]</a><BR>"
dat += "<b>Uplink Spawn Location:</b><BR><a href ='?_src_=prefs;preference=uplink_loc;task=input'>[uplink_spawn_loc]</a><BR></td>"
if(pref_species.use_skintones)
dat += "<td valign='top' width='21%'>"
dat += "<h3>Skin Tone</h3>"
dat += "<a href='?_src_=prefs;preference=s_tone;task=input'>[skin_tone]</a><BR>"
dat += "</td>"
if(HAIR in pref_species.species_traits)
dat += "<td valign='top' width='21%'>"
dat += "<h3>Hair Style</h3>"
dat += "<a href='?_src_=prefs;preference=hair_style;task=input'>[hair_style]</a><BR>"
dat += "<a href='?_src_=prefs;preference=previous_hair_style;task=input'>&lt;</a> <a href='?_src_=prefs;preference=next_hair_style;task=input'>&gt;</a><BR>"
dat += "<span style='border:1px solid #161616; background-color: #[hair_color];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=hair;task=input'>Change</a><BR>"
dat += "</td><td valign='top' width='21%'>"
dat += "<h3>Facial Hair Style</h3>"
dat += "<a href='?_src_=prefs;preference=facial_hair_style;task=input'>[facial_hair_style]</a><BR>"
dat += "<a href='?_src_=prefs;preference=previous_facehair_style;task=input'>&lt;</a> <a href='?_src_=prefs;preference=next_facehair_style;task=input'>&gt;</a><BR>"
dat += "<span style='border: 1px solid #161616; background-color: #[facial_hair_color];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=facial;task=input'>Change</a><BR>"
dat += "</td>"
if(EYECOLOR in pref_species.species_traits)
dat += "<td valign='top' width='21%'>"
dat += "<h3>Eye Color</h3>"
dat += "<span style='border: 1px solid #161616; background-color: #[eye_color];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=eyes;task=input'>Change</a><BR>"
dat += "</td>"
if(CONFIG_GET(flag/join_with_mutant_race)) //We don't allow mutant bodyparts for humans either unless this is true.
if((MUTCOLORS in pref_species.species_traits) || (MUTCOLORS_PARTSONLY in pref_species.species_traits))
dat += "<td valign='top' width='14%'>"
dat += "<h3>Mutant Color</h3>"
dat += "<span style='border: 1px solid #161616; background-color: #[features["mcolor"]];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=mutant_color;task=input'>Change</a><BR>"
dat += "</td>"
if("tail_lizard" in pref_species.mutant_bodyparts)
dat += "<td valign='top' width='7%'>"
dat += "<h3>Tail</h3>"
dat += "<a href='?_src_=prefs;preference=tail_lizard;task=input'>[features["tail_lizard"]]</a><BR>"
dat += "</td>"
if("snout" in pref_species.mutant_bodyparts)
dat += "<td valign='top' width='7%'>"
dat += "<h3>Snout</h3>"
dat += "<a href='?_src_=prefs;preference=snout;task=input'>[features["snout"]]</a><BR>"
dat += "</td>"
if("horns" in pref_species.mutant_bodyparts)
dat += "<td valign='top' width='7%'>"
dat += "<h3>Horns</h3>"
dat += "<a href='?_src_=prefs;preference=horns;task=input'>[features["horns"]]</a><BR>"
dat += "</td>"
if("frills" in pref_species.mutant_bodyparts)
dat += "<td valign='top' width='7%'>"
dat += "<h3>Frills</h3>"
dat += "<a href='?_src_=prefs;preference=frills;task=input'>[features["frills"]]</a><BR>"
dat += "</td>"
if("spines" in pref_species.mutant_bodyparts)
dat += "<td valign='top' width='7%'>"
dat += "<h3>Spines</h3>"
dat += "<a href='?_src_=prefs;preference=spines;task=input'>[features["spines"]]</a><BR>"
dat += "</td>"
if("body_markings" in pref_species.mutant_bodyparts)
dat += "<td valign='top' width='7%'>"
dat += "<h3>Body Markings</h3>"
dat += "<a href='?_src_=prefs;preference=body_markings;task=input'>[features["body_markings"]]</a><BR>"
dat += "</td>"
if("legs" in pref_species.mutant_bodyparts)
dat += "<td valign='top' width='7%'>"
dat += "<h3>Legs</h3>"
dat += "<a href='?_src_=prefs;preference=legs;task=input'>[features["legs"]]</a><BR>"
dat += "</td>"
if(CONFIG_GET(flag/join_with_mutant_humans))
if("tail_human" in pref_species.mutant_bodyparts)
dat += "<td valign='top' width='7%'>"
dat += "<h3>Tail</h3>"
dat += "<a href='?_src_=prefs;preference=tail_human;task=input'>[features["tail_human"]]</a><BR>"
dat += "</td>"
if("ears" in pref_species.mutant_bodyparts)
dat += "<td valign='top' width='7%'>"
dat += "<h3>Ears</h3>"
dat += "<a href='?_src_=prefs;preference=ears;task=input'>[features["ears"]]</a><BR>"
dat += "</td>"
if("wings" in pref_species.mutant_bodyparts && GLOB.r_wings_list.len >1)
dat += "<td valign='top' width='7%'>"
dat += "<h3>Wings</h3>"
dat += "<a href='?_src_=prefs;preference=wings;task=input'>[features["wings"]]</a><BR>"
dat += "</td>"
dat += "</tr></table>"
if (1) // Game Preferences
dat += "<table><tr><td width='340px' height='300px' valign='top'>"
dat += "<h2>General Settings</h2>"
@@ -295,7 +457,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<b>Ghost pda:</b> <a href='?_src_=prefs;preference=ghost_pda'>[(chat_toggles & CHAT_GHOSTPDA) ? "All Messages" : "Nearest Creatures"]</a><br>"
dat += "<b>Pull requests:</b> <a href='?_src_=prefs;preference=pull_requests'>[(chat_toggles & CHAT_PULLR) ? "Yes" : "No"]</a><br>"
dat += "<b>Midround Antagonist:</b> <a href='?_src_=prefs;preference=allow_midround_antag'>[(toggles & MIDROUND_ANTAG) ? "Yes" : "No"]</a><br>"
if(config.allow_Metadata)
if(CONFIG_GET(flag/allow_metadata))
dat += "<b>OOC Notes:</b> <a href='?_src_=prefs;preference=metadata;task=input'>Edit </a><br>"
if(user.client)
@@ -332,7 +494,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<b>Ghosts of Others:</b> <a href='?_src_=prefs;task=input;preference=ghostothers'>[button_name]</a><br>"
if (config.maprotation)
if (CONFIG_GET(flag/maprotation))
var/p_map = preferred_map
if (!p_map)
p_map = "Default"
@@ -347,7 +509,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
p_map = VM.map_name
else
p_map += " (No longer exists)"
if(config.allow_map_voting)
if(CONFIG_GET(flag/allow_map_voting))
dat += "<b>Preferred Map:</b> <a href='?_src_=prefs;preference=preferred_map;task=input'>[p_map]</a><br>"
dat += "<b>FPS:</b> <a href='?_src_=prefs;preference=clientfps;task=input'>[clientfps]</a><br>"
@@ -385,7 +547,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<b>Be [capitalize(i)]:</b> <a href='?_src_=prefs;jobbancheck=[i]'>BANNED</a><br>"
else
var/days_remaining = null
if(config.use_age_restriction_for_jobs && ispath(GLOB.special_roles[i])) //If it's a game mode antag, check if the player meets the minimum age
if(ispath(GLOB.special_roles[i]) && CONFIG_GET(flag/use_age_restriction_for_jobs)) //If it's a game mode antag, check if the player meets the minimum age
var/mode_path = GLOB.special_roles[i]
var/datum/game_mode/temp_mode = new mode_path
days_remaining = temp_mode.get_remaining_days(user.client)
@@ -599,7 +761,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if((job_civilian_low & ASSISTANT) && (rank != "Assistant") && !jobban_isbanned(user, "Assistant"))
HTML += "<font color=orange>[rank]</font></td><td></td></tr>"
continue
if(config.enforce_human_authority && !user.client.prefs.pref_species.qualifies_for_rank(rank, user.client.prefs.features))
if(CONFIG_GET(flag/enforce_human_authority) && !user.client.prefs.pref_species.qualifies_for_rank(rank, user.client.prefs.features))
if(user.client.prefs.pref_species.id == "human")
HTML += "<font color=red>[rank]</font></td><td><font color=red><b> \[MUTANT\]</b></font></td></tr>"
else
@@ -1023,10 +1185,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("species")
var/result = input(user, "Select a species", "Species Selection") as null|anything in GLOB.roundstart_species
var/result = input(user, "Select a species", "Species Selection") as null|anything in CONFIG_GET(keyed_flag_list/roundstart_races)
if(result)
var/newtype = GLOB.roundstart_species[result]
var/newtype = GLOB.species_list[result]
pref_species = new newtype()
//Now that we changed our species, we must verify that the mutant colour is still allowed.
var/temp_hsv = RGBtoHSV(features["mcolor"])
@@ -1622,7 +1784,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(be_random_body)
random_character(gender)
if(config.humans_need_surnames)
if(CONFIG_GET(flag/humans_need_surnames))
var/firstspace = findtext(real_name, " ")
var/name_length = length(real_name)
if(!firstspace) //we need a surname
@@ -1657,7 +1819,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
character.dna.features = features.Copy() //Flavor text is now a DNA feature
character.dna.real_name = character.real_name
var/datum/species/chosen_species
if(pref_species != /datum/species/human && config.mutant_races)
if(pref_species != /datum/species/human && CONFIG_GET(flag/join_with_mutant_race))
chosen_species = pref_species.type
else
chosen_species = /datum/species/human
+11 -6
View File
@@ -290,11 +290,12 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
//Species
var/species_id
S["species"] >> species_id
if(config.mutant_races && species_id && (species_id in GLOB.roundstart_species))
var/newtype = GLOB.roundstart_species[species_id]
var/list/roundstart_races = CONFIG_GET(keyed_flag_list/roundstart_races)
if(species_id && (species_id in roundstart_races) && CONFIG_GET(flag/join_with_mutant_race))
var/newtype = GLOB.species_list[species_id]
pref_species = new newtype()
else if (config.roundstart_races.len)
var/rando_race = pick(config.roundstart_races)
else if (roundstart_races.len)
var/rando_race = pick(roundstart_races)
if (rando_race)
pref_species = new rando_race()
@@ -327,8 +328,12 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["feature_lizard_spines"] >> features["spines"]
S["feature_lizard_body_markings"] >> features["body_markings"]
S["feature_lizard_legs"] >> features["legs"]
S["feature_human_tail"] >> features["tail_human"]
S["feature_human_ears"] >> features["ears"]
if(!CONFIG_GET(flag/join_with_mutant_humans))
features["tail_human"] = "none"
features["ears"] = "none"
else
S["feature_human_tail"] >> features["tail_human"]
S["feature_human_ears"] >> features["ears"]
S["clown_name"] >> custom_names["clown"]
S["mime_name"] >> custom_names["mime"]
S["ai_name"] >> custom_names["ai"]
+2 -2
View File
@@ -62,7 +62,7 @@
if(holder)
if(!holder.fakekey || C.holder)
if(check_rights_for(src, R_ADMIN))
to_chat(C, "<span class='adminooc'>[config.allow_admin_ooccolor && prefs.ooccolor ? "<font color=[prefs.ooccolor]>" :"" ]<span class='prefix'>OOC:</span> <EM>[keyname][holder.fakekey ? "/([holder.fakekey])" : ""]:</EM> <span class='message'>[msg]</span></span></font>")
to_chat(C, "<span class='adminooc'>[CONFIG_GET(flag/allow_admin_ooccolor) && prefs.ooccolor ? "<font color=[prefs.ooccolor]>" :"" ]<span class='prefix'>OOC:</span> <EM>[keyname][holder.fakekey ? "/([holder.fakekey])" : ""]:</EM> <span class='message'>[msg]</span></span></font>")
else
to_chat(C, "<span class='adminobserverooc'><span class='prefix'>OOC:</span> <EM>[keyname][holder.fakekey ? "/([holder.fakekey])" : ""]:</EM> <span class='message'>[msg]</span></span>")
else
@@ -239,7 +239,7 @@ GLOBAL_VAR_INIT(normal_ooc_colour, OOC_COLOR)
set category = "OOC"
set desc = "View the notes that admins have written about you"
if(!config.see_own_notes)
if(!CONFIG_GET(flag/see_own_notes))
to_chat(usr, "<span class='notice'>Sorry, that function is not enabled on this server.</span>")
return
+1 -1
View File
@@ -1,6 +1,6 @@
/proc/emoji_parse(text)
. = text
if(!config.emojis)
if(!CONFIG_GET(flag/emojis))
return
var/static/list/emojis = icon_states(icon('icons/emoji.dmi'))
var/parsed = ""
+13 -7
View File
@@ -33,14 +33,20 @@ GLOBAL_VAR_INIT(total_runtimes_skipped, 0)
// We can runtime before config is initialized because BYOND initialize objs/map before a bunch of other stuff happens.
// This is a bunch of workaround code for that. Hooray!
var/configured_error_cooldown = initial(config.error_cooldown)
var/configured_error_limit = initial(config.error_limit)
var/configured_error_silence_time = initial(config.error_silence_time)
var/configured_error_cooldown
var/configured_error_limit
var/configured_error_silence_time
if(config)
configured_error_cooldown = config.error_cooldown
configured_error_limit = config.error_limit
configured_error_silence_time = config.error_silence_time
configured_error_cooldown = CONFIG_GET(number/error_cooldown)
configured_error_limit = CONFIG_GET(number/error_limit)
configured_error_silence_time = CONFIG_GET(number/error_silence_time)
else
var/datum/config_entry/CE = /datum/config_entry/number/error_cooldown
configured_error_cooldown = initial(CE.value)
CE = /datum/config_entry/number/error_limit
configured_error_limit = initial(CE.value)
CE = /datum/config_entry/number/error_silence_time
configured_error_silence_time = initial(CE.value)
//Each occurence of a unique error adds to its cooldown time...
+3 -2
View File
@@ -119,9 +119,10 @@ GLOBAL_DATUM(error_cache, /datum/error_viewer/error_cache)
//log_debug("Runtime in <b>[e.file]</b>, line <b>[e.line]</b>: <b>[html_encode(e.name)]</b> [error_entry.make_link(viewtext)]")
var/err_msg_delay
if(config)
err_msg_delay = config.error_msg_delay
err_msg_delay = CONFIG_GET(number/error_msg_delay)
else
err_msg_delay = initial(config.error_msg_delay)
var/datum/config_entry/CE = /datum/config_entry/number/error_msg_delay
err_msg_delay = initial(CE.value)
error_source.next_message_at = world.time + err_msg_delay
/datum/error_viewer/error_source
+2 -2
View File
@@ -29,8 +29,8 @@
/datum/round_event_control/New()
if(config && !wizardevent) // Magic is unaffected by configs
earliest_start = Ceiling(earliest_start * config.events_min_time_mul)
min_players = Ceiling(min_players * config.events_min_players_mul)
earliest_start = Ceiling(earliest_start * CONFIG_GET(number/events_min_time_mul))
min_players = Ceiling(min_players * CONFIG_GET(number/events_min_players_mul))
/datum/round_event_control/wizard
wizardevent = 1
+2 -2
View File
@@ -6,7 +6,7 @@
earliest_start = 0
/datum/round_event_control/wizard/summonguns/New()
if(config.no_summon_guns)
if(CONFIG_GET(flag/no_summon_guns))
weight = 0
..()
@@ -21,7 +21,7 @@
earliest_start = 0
/datum/round_event_control/wizard/summonmagic/New()
if(config.no_summon_magic)
if(CONFIG_GET(flag/no_summon_magic))
weight = 0
..()
+1 -1
View File
@@ -55,7 +55,7 @@
var/obj/machinery/hydroponics/parent = loc
var/make_podman = 0
var/ckey_holder = null
if(config.revival_pod_plants)
if(CONFIG_GET(flag/revival_pod_plants))
if(ckey)
for(var/mob/M in GLOB.player_list)
if(isobserver(M))
+12 -11
View File
@@ -6,13 +6,13 @@ GLOBAL_PROTECT(exp_to_update)
/datum/job/proc/required_playtime_remaining(client/C)
if(!C)
return 0
if(!config.use_exp_tracking)
if(!CONFIG_GET(flag/use_exp_tracking))
return 0
if(!exp_requirements || !exp_type)
return 0
if(!job_is_xp_locked(src.title))
return 0
if(config.use_exp_restrictions_admin_bypass && check_rights(R_ADMIN, FALSE, C.mob))
if(CONFIG_GET(flag/use_exp_restrictions_admin_bypass) && check_rights(R_ADMIN, FALSE, C.mob))
return 0
var/isexempt = C.prefs.db_flags & DB_FLAG_EXEMPT
if(isexempt)
@@ -26,20 +26,21 @@ GLOBAL_PROTECT(exp_to_update)
/datum/job/proc/get_exp_req_amount()
if(title in GLOB.command_positions)
if(config.use_exp_restrictions_heads_hours)
return config.use_exp_restrictions_heads_hours * 60
var/uerhh = CONFIG_GET(number/use_exp_restrictions_heads_hours)
if(uerhh)
return uerhh * 60
return exp_requirements
/datum/job/proc/get_exp_req_type()
if(title in GLOB.command_positions)
if(config.use_exp_restrictions_heads_department && exp_type_department)
if(CONFIG_GET(flag/use_exp_restrictions_heads_department) && exp_type_department)
return exp_type_department
return exp_type
/proc/job_is_xp_locked(jobtitle)
if(!config.use_exp_restrictions_heads && jobtitle in GLOB.command_positions)
if(!CONFIG_GET(flag/use_exp_restrictions_heads) && jobtitle in GLOB.command_positions)
return FALSE
if(!config.use_exp_restrictions_other && !(jobtitle in GLOB.command_positions))
if(!CONFIG_GET(flag/use_exp_restrictions_other) && !(jobtitle in GLOB.command_positions))
return FALSE
return TRUE
@@ -55,7 +56,7 @@ GLOBAL_PROTECT(exp_to_update)
return amount
/client/proc/get_exp_report()
if(!config.use_exp_tracking)
if(!CONFIG_GET(flag/use_exp_tracking))
return "Tracking is disabled in the server configuration file."
var/list/play_records = prefs.exp
if(!play_records.len)
@@ -86,7 +87,7 @@ GLOBAL_PROTECT(exp_to_update)
return_text += "<LI>[dep] [get_exp_format(exp_data[dep])] ([percentage]%)</LI>"
else
return_text += "<LI>[dep] [get_exp_format(exp_data[dep])] </LI>"
if(config.use_exp_restrictions_admin_bypass && check_rights(R_ADMIN, 0, mob))
if(CONFIG_GET(flag/use_exp_restrictions_admin_bypass) && check_rights(R_ADMIN, 0, mob))
return_text += "<LI>Admin (all jobs auto-unlocked)</LI>"
return_text += "</UL>"
var/list/jobs_locked = list()
@@ -139,7 +140,7 @@ GLOBAL_PROTECT(exp_to_update)
//resets a client's exp to what was in the db.
/client/proc/set_exp_from_db()
if(!config.use_exp_tracking)
if(!CONFIG_GET(flag/use_exp_tracking))
return -1
if(!SSdbcore.Connect())
return -1
@@ -181,7 +182,7 @@ GLOBAL_PROTECT(exp_to_update)
/client/proc/update_exp_list(minutes, announce_changes = FALSE)
if(!config.use_exp_tracking)
if(!CONFIG_GET(flag/use_exp_tracking))
return -1
if(!SSdbcore.Connect())
return -1
+42 -41
View File
@@ -1,42 +1,43 @@
/*
Assistant
*/
/datum/job/assistant
title = "Assistant"
flag = ASSISTANT
department_flag = CIVILIAN
faction = "Station"
total_positions = -1
spawn_positions = -1
supervisors = "absolutely everyone"
selection_color = "#dddddd"
access = list() //See /datum/job/assistant/get_access()
minimal_access = list() //See /datum/job/assistant/get_access()
outfit = /datum/outfit/job/assistant
/datum/job/assistant/get_access()
if((config.jobs_have_maint_access & ASSISTANTS_HAVE_MAINT_ACCESS) || !config.jobs_have_minimal_access) //Config has assistant maint access set
. = ..()
/*
Assistant
*/
/datum/job/assistant
title = "Assistant"
flag = ASSISTANT
department_flag = CIVILIAN
faction = "Station"
total_positions = -1
spawn_positions = -1
supervisors = "absolutely everyone"
selection_color = "#dddddd"
access = list() //See /datum/job/assistant/get_access()
minimal_access = list() //See /datum/job/assistant/get_access()
outfit = /datum/outfit/job/assistant
/datum/job/assistant/get_access()
if(CONFIG_GET(flag/assistants_have_maint_access) || !CONFIG_GET(flag/jobs_have_minimal_access)) //Config has assistant maint access set
. = ..()
. |= list(ACCESS_MAINT_TUNNELS)
else
return ..()
/datum/job/assistant/config_check()
if(config && !(config.assistant_cap == 0))
total_positions = config.assistant_cap
spawn_positions = config.assistant_cap
return 1
return 0
/datum/outfit/job/assistant
name = "Assistant"
jobtype = /datum/job/assistant
/datum/outfit/job/assistant/pre_equip(mob/living/carbon/human/H)
..()
if (config.grey_assistants)
uniform = /obj/item/clothing/under/color/grey
else
uniform = /obj/item/clothing/under/color/random
else
return ..()
/datum/job/assistant/config_check()
var/ac = CONFIG_GET(number/assistant_cap)
if(ac != 0)
total_positions = ac
spawn_positions = ac
return 1
return 0
/datum/outfit/job/assistant
name = "Assistant"
jobtype = /datum/job/assistant
/datum/outfit/job/assistant/pre_equip(mob/living/carbon/human/H)
..()
if (CONFIG_GET(flag/grey_assistants))
uniform = /obj/item/clothing/under/color/grey
else
uniform = /obj/item/clothing/under/color/random

Some files were not shown because too many files have changed in this diff Show More