Merge remote-tracking branch 'refs/remotes/origin/master' into upstream-merge-35475
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
#define R_SOUNDS 0x800
|
||||
#define R_SPAWN 0x1000
|
||||
#define R_AUTOLOGIN 0x2000
|
||||
#define R_DBRANKS 0x4000
|
||||
|
||||
#define R_DEFAULT R_AUTOLOGIN
|
||||
|
||||
|
||||
@@ -81,6 +81,9 @@
|
||||
#define ABOVE_LIGHTING_PLANE 16
|
||||
#define ABOVE_LIGHTING_LAYER 16
|
||||
|
||||
#define BYOND_LIGHTING_PLANE 17
|
||||
#define BYOND_LIGHTING_LAYER 17
|
||||
|
||||
//HUD layer defines
|
||||
|
||||
#define FULLSCREEN_PLANE 18
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
#define LIGHT_RANGE_FIRE 3 //How many tiles standard fires glow.
|
||||
|
||||
#define LIGHTING_PLANE_ALPHA_VISIBLE 255
|
||||
#define LIGHTING_PLANE_ALPHA_NV_TRAIT 250
|
||||
#define LIGHTING_PLANE_ALPHA_NV_TRAIT 245
|
||||
#define LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE 192
|
||||
#define LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE 128 //For lighting alpha, small amounts lead to big changes. even at 128 its hard to figure out what is dark and what is light, at 64 you almost can't even tell.
|
||||
#define LIGHTING_PLANE_ALPHA_INVISIBLE 0
|
||||
|
||||
@@ -26,7 +26,6 @@ require only minor tweaks.
|
||||
#define MAP_REMOVE_JOB(jobpath) /datum/job/##jobpath/map_check() { return (SSmapping.config.map_name != JOB_MODIFICATION_MAP_NAME) && ..() }
|
||||
|
||||
#define SPACERUIN_MAP_EDGE_PAD 15
|
||||
#define ZLEVEL_SPACE_RUIN_COUNT 7
|
||||
|
||||
// traits
|
||||
// boolean - marks a level as having that property if present
|
||||
|
||||
@@ -22,3 +22,4 @@
|
||||
#define QDELING(X) (X.gc_destroyed)
|
||||
#define QDELETED(X) (!X || QDELING(X))
|
||||
#define QDESTROYING(X) (!X || X.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//Update this whenever the db schema changes
|
||||
//make sure you add an update to the schema_version stable in the db changelog
|
||||
#define DB_MAJOR_VERSION 4
|
||||
#define DB_MINOR_VERSION 0
|
||||
#define DB_MINOR_VERSION 1
|
||||
|
||||
//Timing subsystem
|
||||
//Don't run if there is an identical unique timer active
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
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)
|
||||
//bodypart accessories (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)
|
||||
@@ -29,7 +29,7 @@
|
||||
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)
|
||||
//moffs
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/caps, GLOB.caps_list)
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_wings, GLOB.moth_wings_list)
|
||||
|
||||
//CIT CHANGES START HERE, ADDS SNOWFLAKE BODYPARTS AND MORE
|
||||
|
||||
@@ -111,6 +111,7 @@
|
||||
"spines" = pick(GLOB.spines_list),
|
||||
"body_markings" = pick(GLOB.body_markings_list),
|
||||
"legs" = "Normal Legs",
|
||||
"caps" = pick(GLOB.caps_list),
|
||||
"moth_wings" = pick(GLOB.moth_wings_list),
|
||||
"taur" = "None",
|
||||
"mam_body_markings" = "None",
|
||||
@@ -166,6 +167,7 @@
|
||||
"womb_efficiency" = CUM_EFFICIENCY,
|
||||
"womb_fluid" = "femcum",
|
||||
"flavor_text" = ""))
|
||||
|
||||
/proc/random_hair_style(gender)
|
||||
switch(gender)
|
||||
if(MALE)
|
||||
|
||||
@@ -500,3 +500,28 @@
|
||||
objective_parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
|
||||
count++
|
||||
return objective_parts.Join("<br>")
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/save_admin_data()
|
||||
if(CONFIG_GET(flag/admin_legacy_system)) //we're already using legacy system so there's nothing to save
|
||||
return
|
||||
else if(load_admins()) //returns true if there was a database failure and the backup was loaded from
|
||||
return
|
||||
var/datum/DBQuery/query_admin_rank_update = SSdbcore.NewQuery("UPDATE [format_table_name("player")] p INNER JOIN [format_table_name("admin")] a ON p.ckey = a.ckey SET p.lastadminrank = a.rank")
|
||||
query_admin_rank_update.Execute()
|
||||
//json format backup file generation stored per server
|
||||
var/json_file = file("data/admins_backup.json")
|
||||
var/list/file_data = list("ranks" = list(), "admins" = list())
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
file_data["ranks"]["[R.name]"] = list()
|
||||
file_data["ranks"]["[R.name]"]["include rights"] = R.include_rights
|
||||
file_data["ranks"]["[R.name]"]["exclude rights"] = R.exclude_rights
|
||||
file_data["ranks"]["[R.name]"]["can edit rights"] = R.can_edit_rights
|
||||
for(var/i in GLOB.admin_datums+GLOB.deadmins)
|
||||
var/datum/admins/A = GLOB.admin_datums[i]
|
||||
if(!A)
|
||||
A = GLOB.deadmins[i]
|
||||
if (!A)
|
||||
continue
|
||||
file_data["admins"]["[i]"] = A.rank.name
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
+21
-19
@@ -182,38 +182,40 @@
|
||||
return ICON_OVERLAY
|
||||
|
||||
//Converts a rights bitfield into a string
|
||||
/proc/rights2text(rights, seperator="", list/adds, list/subs)
|
||||
/proc/rights2text(rights, seperator="", prefix = "+")
|
||||
seperator += prefix
|
||||
if(rights & R_BUILDMODE)
|
||||
. += "[seperator]+BUILDMODE"
|
||||
. += "[seperator]BUILDMODE"
|
||||
if(rights & R_ADMIN)
|
||||
. += "[seperator]+ADMIN"
|
||||
. += "[seperator]ADMIN"
|
||||
if(rights & R_BAN)
|
||||
. += "[seperator]+BAN"
|
||||
. += "[seperator]BAN"
|
||||
if(rights & R_FUN)
|
||||
. += "[seperator]+FUN"
|
||||
. += "[seperator]FUN"
|
||||
if(rights & R_SERVER)
|
||||
. += "[seperator]+SERVER"
|
||||
. += "[seperator]SERVER"
|
||||
if(rights & R_DEBUG)
|
||||
. += "[seperator]+DEBUG"
|
||||
. += "[seperator]DEBUG"
|
||||
if(rights & R_POSSESS)
|
||||
. += "[seperator]+POSSESS"
|
||||
. += "[seperator]POSSESS"
|
||||
if(rights & R_PERMISSIONS)
|
||||
. += "[seperator]+PERMISSIONS"
|
||||
. += "[seperator]PERMISSIONS"
|
||||
if(rights & R_STEALTH)
|
||||
. += "[seperator]+STEALTH"
|
||||
. += "[seperator]STEALTH"
|
||||
if(rights & R_POLL)
|
||||
. += "[seperator]+POLL"
|
||||
. += "[seperator]POLL"
|
||||
if(rights & R_VAREDIT)
|
||||
. += "[seperator]+VAREDIT"
|
||||
. += "[seperator]VAREDIT"
|
||||
if(rights & R_SOUNDS)
|
||||
. += "[seperator]+SOUND"
|
||||
. += "[seperator]SOUND"
|
||||
if(rights & R_SPAWN)
|
||||
. += "[seperator]+SPAWN"
|
||||
|
||||
for(var/verbpath in adds)
|
||||
. += "[seperator]+[verbpath]"
|
||||
for(var/verbpath in subs)
|
||||
. += "[seperator]-[verbpath]"
|
||||
. += "[seperator]SPAWN"
|
||||
if(rights & R_AUTOLOGIN)
|
||||
. += "[seperator]AUTOLOGIN"
|
||||
if(rights & R_DBRANKS)
|
||||
. += "[seperator]DBRANKS"
|
||||
if(!.)
|
||||
. = "NONE"
|
||||
return .
|
||||
|
||||
/proc/ui_style2icon(ui_style)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#define DEBUG //Enables byond profiling and full runtime logs - note, this may also be defined in your .dme file
|
||||
//Enables in-depth debug messages to runtime log (used for debugging)
|
||||
//#define TESTING //By using the testing("message") proc you can create debug-feedback for people with this
|
||||
//uncommented, but not visible in the release version)
|
||||
|
||||
|
||||
@@ -1,130 +1,131 @@
|
||||
//Preferences stuff
|
||||
//Hairstyles
|
||||
GLOBAL_LIST_EMPTY(hair_styles_list) //stores /datum/sprite_accessory/hair indexed by name
|
||||
GLOBAL_LIST_EMPTY(hair_styles_male_list) //stores only hair names
|
||||
GLOBAL_LIST_EMPTY(hair_styles_female_list) //stores only hair names
|
||||
GLOBAL_LIST_EMPTY(facial_hair_styles_list) //stores /datum/sprite_accessory/facial_hair indexed by name
|
||||
GLOBAL_LIST_EMPTY(facial_hair_styles_male_list) //stores only hair names
|
||||
GLOBAL_LIST_EMPTY(facial_hair_styles_female_list) //stores only hair names
|
||||
//Underwear
|
||||
GLOBAL_LIST_EMPTY(underwear_list) //stores /datum/sprite_accessory/underwear indexed by name
|
||||
GLOBAL_LIST_EMPTY(underwear_m) //stores only underwear name
|
||||
GLOBAL_LIST_EMPTY(underwear_f) //stores only underwear name
|
||||
//Undershirts
|
||||
GLOBAL_LIST_EMPTY(undershirt_list) //stores /datum/sprite_accessory/undershirt indexed by name
|
||||
GLOBAL_LIST_EMPTY(undershirt_m) //stores only undershirt name
|
||||
GLOBAL_LIST_EMPTY(undershirt_f) //stores only undershirt name
|
||||
//Socks
|
||||
GLOBAL_LIST_EMPTY(socks_list) //stores /datum/sprite_accessory/socks indexed by name
|
||||
//Lizard Bits (all datum lists indexed by name)
|
||||
GLOBAL_LIST_EMPTY(body_markings_list)
|
||||
GLOBAL_LIST_EMPTY(tails_list_lizard)
|
||||
GLOBAL_LIST_EMPTY(animated_tails_list_lizard)
|
||||
GLOBAL_LIST_EMPTY(snouts_list)
|
||||
GLOBAL_LIST_EMPTY(horns_list)
|
||||
GLOBAL_LIST_EMPTY(frills_list)
|
||||
GLOBAL_LIST_EMPTY(spines_list)
|
||||
GLOBAL_LIST_EMPTY(legs_list)
|
||||
GLOBAL_LIST_EMPTY(animated_spines_list)
|
||||
|
||||
//Mutant Human bits
|
||||
GLOBAL_LIST_EMPTY(tails_list_human)
|
||||
GLOBAL_LIST_EMPTY(animated_tails_list_human)
|
||||
GLOBAL_LIST_EMPTY(ears_list)
|
||||
GLOBAL_LIST_EMPTY(wings_list)
|
||||
GLOBAL_LIST_EMPTY(wings_open_list)
|
||||
GLOBAL_LIST_EMPTY(r_wings_list)
|
||||
GLOBAL_LIST_EMPTY(moth_wings_list)
|
||||
|
||||
GLOBAL_LIST_INIT(ghost_forms_with_directions_list, list("ghost")) //stores the ghost forms that support directional sprites
|
||||
GLOBAL_LIST_INIT(ghost_forms_with_accessories_list, list("ghost")) //stores the ghost forms that support hair and other such things
|
||||
|
||||
GLOBAL_LIST_INIT(security_depts_prefs, list(SEC_DEPT_RANDOM, SEC_DEPT_NONE, SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, SEC_DEPT_SCIENCE, SEC_DEPT_SUPPLY))
|
||||
|
||||
//Backpacks
|
||||
#define GBACKPACK "Grey Backpack"
|
||||
#define GSATCHEL "Grey Satchel"
|
||||
#define GDUFFELBAG "Grey Duffel Bag"
|
||||
#define LSATCHEL "Leather Satchel"
|
||||
#define DBACKPACK "Department Backpack"
|
||||
#define DSATCHEL "Department Satchel"
|
||||
#define DDUFFELBAG "Department Duffel Bag"
|
||||
GLOBAL_LIST_INIT(backbaglist, list(DBACKPACK, DSATCHEL, DDUFFELBAG, GBACKPACK, GSATCHEL, GDUFFELBAG, LSATCHEL))
|
||||
|
||||
//Uplink spawn loc
|
||||
#define UPLINK_PDA "PDA"
|
||||
#define UPLINK_RADIO "Radio"
|
||||
#define UPLINK_PEN "Pen" //like a real spy!
|
||||
GLOBAL_LIST_INIT(uplink_spawn_loc_list, list(UPLINK_PDA, UPLINK_RADIO, UPLINK_PEN))
|
||||
|
||||
//Female Uniforms
|
||||
GLOBAL_LIST_EMPTY(female_clothing_icons)
|
||||
|
||||
//radical shit
|
||||
GLOBAL_LIST_INIT(hit_appends, list("-OOF", "-ACK", "-UGH", "-HRNK", "-HURGH", "-GLORF"))
|
||||
|
||||
GLOBAL_LIST_INIT(scarySounds, list('sound/weapons/thudswoosh.ogg','sound/weapons/taser.ogg','sound/weapons/armbomb.ogg','sound/voice/hiss1.ogg','sound/voice/hiss2.ogg','sound/voice/hiss3.ogg','sound/voice/hiss4.ogg','sound/voice/hiss5.ogg','sound/voice/hiss6.ogg','sound/effects/glassbr1.ogg','sound/effects/glassbr2.ogg','sound/effects/glassbr3.ogg','sound/items/welder.ogg','sound/items/welder2.ogg','sound/machines/airlock.ogg','sound/effects/clownstep1.ogg','sound/effects/clownstep2.ogg'))
|
||||
|
||||
|
||||
// Reference list for disposal sort junctions. Set the sortType variable on disposal sort junctions to
|
||||
// the index of the sort department that you want. For example, sortType set to 2 will reroute all packages
|
||||
// tagged for the Cargo Bay.
|
||||
|
||||
/* List of sortType codes for mapping reference
|
||||
0 Waste
|
||||
1 Disposals
|
||||
2 Cargo Bay
|
||||
3 QM Office
|
||||
4 Engineering
|
||||
5 CE Office
|
||||
6 Atmospherics
|
||||
7 Security
|
||||
8 HoS Office
|
||||
9 Medbay
|
||||
10 CMO Office
|
||||
11 Chemistry
|
||||
12 Research
|
||||
13 RD Office
|
||||
14 Robotics
|
||||
15 HoP Office
|
||||
16 Library
|
||||
17 Chapel
|
||||
18 Theatre
|
||||
19 Bar
|
||||
20 Kitchen
|
||||
21 Hydroponics
|
||||
22 Janitor
|
||||
23 Genetics
|
||||
*/
|
||||
|
||||
GLOBAL_LIST_INIT(TAGGERLOCATIONS, list("Disposals",
|
||||
"Cargo Bay", "QM Office", "Engineering", "CE Office",
|
||||
"Atmospherics", "Security", "HoS Office", "Medbay",
|
||||
"CMO Office", "Chemistry", "Research", "RD Office",
|
||||
"Robotics", "HoP Office", "Library", "Chapel", "Theatre",
|
||||
"Bar", "Kitchen", "Hydroponics", "Janitor Closet","Genetics"))
|
||||
|
||||
GLOBAL_LIST_INIT(guitar_notes, flist("sound/guitar/"))
|
||||
|
||||
GLOBAL_LIST_INIT(station_prefixes, world.file2list("strings/station_prefixes.txt") + "")
|
||||
|
||||
GLOBAL_LIST_INIT(station_names, world.file2list("strings/station_names.txt" + ""))
|
||||
|
||||
GLOBAL_LIST_INIT(station_suffixes, world.file2list("strings/station_suffixes.txt"))
|
||||
|
||||
GLOBAL_LIST_INIT(greek_letters, world.file2list("strings/greek_letters.txt"))
|
||||
|
||||
GLOBAL_LIST_INIT(phonetic_alphabet, world.file2list("strings/phonetic_alphabet.txt"))
|
||||
|
||||
GLOBAL_LIST_INIT(numbers_as_words, world.file2list("strings/numbers_as_words.txt"))
|
||||
|
||||
/proc/generate_number_strings()
|
||||
var/list/L[198]
|
||||
for(var/i in 1 to 99)
|
||||
L += "[i]"
|
||||
L += "\Roman[i]"
|
||||
return L
|
||||
|
||||
GLOBAL_LIST_INIT(station_numerals, greek_letters + phonetic_alphabet + numbers_as_words + generate_number_strings())
|
||||
|
||||
GLOBAL_LIST_INIT(admiral_messages, list("Do you know how expensive these stations are?","Stop wasting my time.","I was sleeping, thanks a lot.","Stand and fight you cowards!","You knew the risks coming in.","Stop being paranoid.","Whatever's broken just build a new one.","No.", "<i>null</i>","<i>Error: No comment given.</i>", "It's a good day to die!"))
|
||||
//Preferences stuff
|
||||
//Hairstyles
|
||||
GLOBAL_LIST_EMPTY(hair_styles_list) //stores /datum/sprite_accessory/hair indexed by name
|
||||
GLOBAL_LIST_EMPTY(hair_styles_male_list) //stores only hair names
|
||||
GLOBAL_LIST_EMPTY(hair_styles_female_list) //stores only hair names
|
||||
GLOBAL_LIST_EMPTY(facial_hair_styles_list) //stores /datum/sprite_accessory/facial_hair indexed by name
|
||||
GLOBAL_LIST_EMPTY(facial_hair_styles_male_list) //stores only hair names
|
||||
GLOBAL_LIST_EMPTY(facial_hair_styles_female_list) //stores only hair names
|
||||
//Underwear
|
||||
GLOBAL_LIST_EMPTY(underwear_list) //stores /datum/sprite_accessory/underwear indexed by name
|
||||
GLOBAL_LIST_EMPTY(underwear_m) //stores only underwear name
|
||||
GLOBAL_LIST_EMPTY(underwear_f) //stores only underwear name
|
||||
//Undershirts
|
||||
GLOBAL_LIST_EMPTY(undershirt_list) //stores /datum/sprite_accessory/undershirt indexed by name
|
||||
GLOBAL_LIST_EMPTY(undershirt_m) //stores only undershirt name
|
||||
GLOBAL_LIST_EMPTY(undershirt_f) //stores only undershirt name
|
||||
//Socks
|
||||
GLOBAL_LIST_EMPTY(socks_list) //stores /datum/sprite_accessory/socks indexed by name
|
||||
//Lizard Bits (all datum lists indexed by name)
|
||||
GLOBAL_LIST_EMPTY(body_markings_list)
|
||||
GLOBAL_LIST_EMPTY(tails_list_lizard)
|
||||
GLOBAL_LIST_EMPTY(animated_tails_list_lizard)
|
||||
GLOBAL_LIST_EMPTY(snouts_list)
|
||||
GLOBAL_LIST_EMPTY(horns_list)
|
||||
GLOBAL_LIST_EMPTY(frills_list)
|
||||
GLOBAL_LIST_EMPTY(spines_list)
|
||||
GLOBAL_LIST_EMPTY(legs_list)
|
||||
GLOBAL_LIST_EMPTY(animated_spines_list)
|
||||
|
||||
//Mutant Human bits
|
||||
GLOBAL_LIST_EMPTY(tails_list_human)
|
||||
GLOBAL_LIST_EMPTY(animated_tails_list_human)
|
||||
GLOBAL_LIST_EMPTY(ears_list)
|
||||
GLOBAL_LIST_EMPTY(wings_list)
|
||||
GLOBAL_LIST_EMPTY(wings_open_list)
|
||||
GLOBAL_LIST_EMPTY(r_wings_list)
|
||||
GLOBAL_LIST_EMPTY(moth_wings_list)
|
||||
GLOBAL_LIST_EMPTY(caps_list)
|
||||
|
||||
GLOBAL_LIST_INIT(ghost_forms_with_directions_list, list("ghost")) //stores the ghost forms that support directional sprites
|
||||
GLOBAL_LIST_INIT(ghost_forms_with_accessories_list, list("ghost")) //stores the ghost forms that support hair and other such things
|
||||
|
||||
GLOBAL_LIST_INIT(security_depts_prefs, list(SEC_DEPT_RANDOM, SEC_DEPT_NONE, SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, SEC_DEPT_SCIENCE, SEC_DEPT_SUPPLY))
|
||||
|
||||
//Backpacks
|
||||
#define GBACKPACK "Grey Backpack"
|
||||
#define GSATCHEL "Grey Satchel"
|
||||
#define GDUFFELBAG "Grey Duffel Bag"
|
||||
#define LSATCHEL "Leather Satchel"
|
||||
#define DBACKPACK "Department Backpack"
|
||||
#define DSATCHEL "Department Satchel"
|
||||
#define DDUFFELBAG "Department Duffel Bag"
|
||||
GLOBAL_LIST_INIT(backbaglist, list(DBACKPACK, DSATCHEL, DDUFFELBAG, GBACKPACK, GSATCHEL, GDUFFELBAG, LSATCHEL))
|
||||
|
||||
//Uplink spawn loc
|
||||
#define UPLINK_PDA "PDA"
|
||||
#define UPLINK_RADIO "Radio"
|
||||
#define UPLINK_PEN "Pen" //like a real spy!
|
||||
GLOBAL_LIST_INIT(uplink_spawn_loc_list, list(UPLINK_PDA, UPLINK_RADIO, UPLINK_PEN))
|
||||
|
||||
//Female Uniforms
|
||||
GLOBAL_LIST_EMPTY(female_clothing_icons)
|
||||
|
||||
//radical shit
|
||||
GLOBAL_LIST_INIT(hit_appends, list("-OOF", "-ACK", "-UGH", "-HRNK", "-HURGH", "-GLORF"))
|
||||
|
||||
GLOBAL_LIST_INIT(scarySounds, list('sound/weapons/thudswoosh.ogg','sound/weapons/taser.ogg','sound/weapons/armbomb.ogg','sound/voice/hiss1.ogg','sound/voice/hiss2.ogg','sound/voice/hiss3.ogg','sound/voice/hiss4.ogg','sound/voice/hiss5.ogg','sound/voice/hiss6.ogg','sound/effects/glassbr1.ogg','sound/effects/glassbr2.ogg','sound/effects/glassbr3.ogg','sound/items/welder.ogg','sound/items/welder2.ogg','sound/machines/airlock.ogg','sound/effects/clownstep1.ogg','sound/effects/clownstep2.ogg'))
|
||||
|
||||
|
||||
// Reference list for disposal sort junctions. Set the sortType variable on disposal sort junctions to
|
||||
// the index of the sort department that you want. For example, sortType set to 2 will reroute all packages
|
||||
// tagged for the Cargo Bay.
|
||||
|
||||
/* List of sortType codes for mapping reference
|
||||
0 Waste
|
||||
1 Disposals
|
||||
2 Cargo Bay
|
||||
3 QM Office
|
||||
4 Engineering
|
||||
5 CE Office
|
||||
6 Atmospherics
|
||||
7 Security
|
||||
8 HoS Office
|
||||
9 Medbay
|
||||
10 CMO Office
|
||||
11 Chemistry
|
||||
12 Research
|
||||
13 RD Office
|
||||
14 Robotics
|
||||
15 HoP Office
|
||||
16 Library
|
||||
17 Chapel
|
||||
18 Theatre
|
||||
19 Bar
|
||||
20 Kitchen
|
||||
21 Hydroponics
|
||||
22 Janitor
|
||||
23 Genetics
|
||||
*/
|
||||
|
||||
GLOBAL_LIST_INIT(TAGGERLOCATIONS, list("Disposals",
|
||||
"Cargo Bay", "QM Office", "Engineering", "CE Office",
|
||||
"Atmospherics", "Security", "HoS Office", "Medbay",
|
||||
"CMO Office", "Chemistry", "Research", "RD Office",
|
||||
"Robotics", "HoP Office", "Library", "Chapel", "Theatre",
|
||||
"Bar", "Kitchen", "Hydroponics", "Janitor Closet","Genetics"))
|
||||
|
||||
GLOBAL_LIST_INIT(guitar_notes, flist("sound/guitar/"))
|
||||
|
||||
GLOBAL_LIST_INIT(station_prefixes, world.file2list("strings/station_prefixes.txt") + "")
|
||||
|
||||
GLOBAL_LIST_INIT(station_names, world.file2list("strings/station_names.txt" + ""))
|
||||
|
||||
GLOBAL_LIST_INIT(station_suffixes, world.file2list("strings/station_suffixes.txt"))
|
||||
|
||||
GLOBAL_LIST_INIT(greek_letters, world.file2list("strings/greek_letters.txt"))
|
||||
|
||||
GLOBAL_LIST_INIT(phonetic_alphabet, world.file2list("strings/phonetic_alphabet.txt"))
|
||||
|
||||
GLOBAL_LIST_INIT(numbers_as_words, world.file2list("strings/numbers_as_words.txt"))
|
||||
|
||||
/proc/generate_number_strings()
|
||||
var/list/L[198]
|
||||
for(var/i in 1 to 99)
|
||||
L += "[i]"
|
||||
L += "\Roman[i]"
|
||||
return L
|
||||
|
||||
GLOBAL_LIST_INIT(station_numerals, greek_letters + phonetic_alphabet + numbers_as_words + generate_number_strings())
|
||||
|
||||
GLOBAL_LIST_INIT(admiral_messages, list("Do you know how expensive these stations are?","Stop wasting my time.","I was sleeping, thanks a lot.","Stand and fight you cowards!","You knew the risks coming in.","Stop being paranoid.","Whatever's broken just build a new one.","No.", "<i>null</i>","<i>Error: No comment given.</i>", "It's a good day to die!"))
|
||||
|
||||
@@ -22,5 +22,6 @@ GLOBAL_LIST_EMPTY(player_details) // ckey -> /datum/player_details
|
||||
GLOBAL_LIST_INIT(bitfields, list(
|
||||
"obj_flags" = list("EMAGGED" = EMAGGED, "IN_USE" = IN_USE, "CAN_BE_HIT" = CAN_BE_HIT, "BEING_SHOCKED" = BEING_SHOCKED, "DANGEROUS_POSSESSION" = DANGEROUS_POSSESSION, "ON_BLUEPRINTS" = ON_BLUEPRINTS, "UNIQUE_RENAME" = UNIQUE_RENAME),
|
||||
"datum_flags" = list("DF_USE_TAG" = DF_USE_TAG, "DF_VAR_EDITED" = DF_VAR_EDITED),
|
||||
"item_flags" = list("BEING_REMOVED" = BEING_REMOVED, "IN_INVENTORY" = IN_INVENTORY, "FORCE_STRING_OVERRIDE" = FORCE_STRING_OVERRIDE, "NEEDS_PERMIT" = NEEDS_PERMIT)
|
||||
"item_flags" = list("BEING_REMOVED" = BEING_REMOVED, "IN_INVENTORY" = IN_INVENTORY, "FORCE_STRING_OVERRIDE" = FORCE_STRING_OVERRIDE, "NEEDS_PERMIT" = NEEDS_PERMIT),
|
||||
"admin_flags" = list("BUILDMODE" = R_BUILDMODE, "ADMIN" = R_ADMIN, "BAN" = R_BAN, "FUN" = R_FUN, "SERVER" = R_SERVER, "DEBUG" = R_DEBUG, "POSSESS" = R_POSSESS, "PERMISSIONS" = R_PERMISSIONS, "STEALTH" = R_STEALTH, "POLL" = R_POLL, "VAREDIT" = R_VAREDIT, "SOUNDS" = R_SOUNDS, "SPAWN" = R_SPAWN, "AUTOLOGIN" = R_AUTOLOGIN, "DBRANKS" = R_DBRANKS)
|
||||
))
|
||||
|
||||
@@ -346,7 +346,11 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
|
||||
icon_state = "runed_sense2"
|
||||
desc = "You can no longer sense your target's presence."
|
||||
return
|
||||
desc = "You are currently tracking [blood_target] in [get_area_name(blood_target)]."
|
||||
if(isliving(blood_target))
|
||||
var/mob/living/real_target = blood_target
|
||||
desc = "You are currently tracking [real_target.real_name] in [get_area_name(blood_target)]."
|
||||
else
|
||||
desc = "You are currently tracking [blood_target] in [get_area_name(blood_target)]."
|
||||
var/target_angle = Get_Angle(Q, P)
|
||||
var/target_dist = get_dist(P, Q)
|
||||
cut_overlays()
|
||||
|
||||
@@ -394,4 +394,4 @@
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/string/default_view
|
||||
config_entry_value = "15x15"
|
||||
config_entry_value = "15x15"
|
||||
|
||||
@@ -3,7 +3,7 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
|
||||
/datum/controller/global_vars
|
||||
name = "Global Variables"
|
||||
|
||||
var/list/gvars_datum_protected_varlist
|
||||
var/static/list/gvars_datum_protected_varlist
|
||||
var/list/gvars_datum_in_built_vars
|
||||
var/list/gvars_datum_init_order
|
||||
|
||||
@@ -20,18 +20,9 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
|
||||
|
||||
Initialize()
|
||||
|
||||
/datum/controller/global_vars/Destroy(force)
|
||||
stack_trace("Some fucker qdel'd the global holder!")
|
||||
if(!force)
|
||||
return QDEL_HINT_LETMELIVE
|
||||
|
||||
QDEL_NULL(statclick)
|
||||
gvars_datum_protected_varlist.Cut()
|
||||
gvars_datum_in_built_vars.Cut()
|
||||
|
||||
GLOB = null
|
||||
|
||||
return ..()
|
||||
/datum/controller/global_vars/Destroy()
|
||||
//fuck off kevinz
|
||||
return QDEL_HINT_IWILLGC
|
||||
|
||||
/datum/controller/global_vars/stat_entry()
|
||||
if(!statclick)
|
||||
|
||||
@@ -50,11 +50,13 @@ SUBSYSTEM_DEF(mapping)
|
||||
preloadTemplates()
|
||||
#ifndef LOWMEMORYMODE
|
||||
// Create space ruin levels
|
||||
while (space_levels_so_far < ZLEVEL_SPACE_RUIN_COUNT)
|
||||
while (space_levels_so_far < config.space_ruin_levels)
|
||||
++space_levels_so_far
|
||||
add_new_zlevel("Empty Area [space_levels_so_far]", ZTRAITS_SPACE)
|
||||
// and one level with no ruins
|
||||
empty_space = add_new_zlevel("Empty Area [1 + space_levels_so_far]", list(ZTRAIT_LINKAGE = CROSSLINKED))
|
||||
for (var/i in 1 to config.space_empty_levels)
|
||||
++space_levels_so_far
|
||||
empty_space = add_new_zlevel("Empty Area [space_levels_so_far]", list(ZTRAIT_LINKAGE = CROSSLINKED))
|
||||
// and the transit level
|
||||
transit = add_new_zlevel("Transit", list(ZTRAIT_TRANSIT = TRUE))
|
||||
|
||||
@@ -175,7 +177,7 @@ SUBSYSTEM_DEF(mapping)
|
||||
|
||||
#ifndef LOWMEMORYMODE
|
||||
// TODO: remove this when the DB is prepared for the z-levels getting reordered
|
||||
while (world.maxz < (5 - 1) && space_levels_so_far < ZLEVEL_SPACE_RUIN_COUNT)
|
||||
while (world.maxz < (5 - 1) && space_levels_so_far < config.space_ruin_levels)
|
||||
++space_levels_so_far
|
||||
add_new_zlevel("Empty Area [space_levels_so_far]", ZTRAITS_SPACE)
|
||||
|
||||
|
||||
@@ -171,6 +171,8 @@ SUBSYSTEM_DEF(persistence)
|
||||
/datum/controller/subsystem/persistence/proc/SetUpTrophies(list/trophy_items)
|
||||
for(var/A in GLOB.trophy_cases)
|
||||
var/obj/structure/displaycase/trophy/T = A
|
||||
if (T.showpiece)
|
||||
continue
|
||||
T.added_roundstart = TRUE
|
||||
|
||||
var/trophy_data = pick_n_take(trophy_items)
|
||||
|
||||
@@ -9,7 +9,7 @@ PROCESSING_SUBSYSTEM_DEF(traits)
|
||||
wait = 10
|
||||
runlevels = RUNLEVEL_GAME
|
||||
|
||||
var/list/traits = list() //Assoc. list of all roundstart trait datums; "name" = /path/
|
||||
var/list/traits = list() //Assoc. list of all roundstart trait datum types; "name" = /path/
|
||||
var/list/trait_points = list() //Assoc. list of trait names and their "point cost"; positive numbers are good traits, and negative ones are bad
|
||||
var/list/trait_objects = list() //A list of all trait objects in the game, since some may process
|
||||
|
||||
@@ -24,11 +24,10 @@ PROCESSING_SUBSYSTEM_DEF(traits)
|
||||
traits[initial(T.name)] = T
|
||||
trait_points[initial(T.name)] = initial(T.value)
|
||||
|
||||
/datum/controller/subsystem/processing/traits/proc/AssignTraits(mob/living/user, client/cli)
|
||||
if(!isnewplayer(user))
|
||||
GenerateTraits(cli)
|
||||
/datum/controller/subsystem/processing/traits/proc/AssignTraits(mob/living/user, client/cli, spawn_effects)
|
||||
GenerateTraits(cli)
|
||||
for(var/V in cli.prefs.character_traits)
|
||||
user.add_trait_datum(V)
|
||||
user.add_trait_datum(V, spawn_effects)
|
||||
|
||||
/datum/controller/subsystem/processing/traits/proc/GenerateTraits(client/user)
|
||||
if(user.prefs.character_traits.len)
|
||||
|
||||
@@ -387,6 +387,8 @@ SUBSYSTEM_DEF(ticker)
|
||||
captainless=0
|
||||
if(player.mind.assigned_role != player.mind.special_role)
|
||||
SSjob.EquipRank(N, player.mind.assigned_role, 0)
|
||||
if(CONFIG_GET(flag/roundstart_traits))
|
||||
SStraits.AssignTraits(player, N.client, TRUE)
|
||||
CHECK_TICK
|
||||
if(captainless)
|
||||
for(var/mob/dead/new_player/N in GLOB.player_list)
|
||||
|
||||
@@ -458,7 +458,7 @@ SUBSYSTEM_DEF(timer)
|
||||
if (wait >= 1 && callback && callback.object && callback.object != GLOBAL_PROC && QDELETED(callback.object))
|
||||
stack_trace("addtimer called with a callback assigned to a qdeleted object")
|
||||
|
||||
wait = max(wait, world.tick_lag)
|
||||
wait = max(wait, 0)
|
||||
|
||||
if(wait >= INFINITY)
|
||||
CRASH("Attempted to create timer with INFINITY delay")
|
||||
|
||||
+21
-17
@@ -223,25 +223,27 @@
|
||||
/datum/browser/modal/listpicker
|
||||
var/valueslist = list()
|
||||
|
||||
/datum/browser/modal/listpicker/New(User,Message,Title,Button1="Ok",Button2,Button3,StealFocus = 1, Timeout = FALSE,list/values,inputtype="checkbox")
|
||||
/datum/browser/modal/listpicker/New(User,Message,Title,Button1="Ok",Button2,Button3,StealFocus = 1, Timeout = FALSE,list/values,inputtype="checkbox", width, height, slidecolor)
|
||||
if (!User)
|
||||
return
|
||||
|
||||
var/output = {"<form><input type="hidden" name="src" value="[REF(src)]"><ul class="sparse">"}
|
||||
|
||||
if (inputtype == "checkbox" || inputtype == "radio")
|
||||
for (var/i in values)
|
||||
var/div_slider = slidecolor
|
||||
if(!i["allowed_edit"])
|
||||
div_slider = "locked"
|
||||
output += {"<li>
|
||||
<label class="switch">
|
||||
<input type="[inputtype]" value="1" name="[i["name"]]"[i["checked"] ? " checked" : ""]>
|
||||
<div class="slider"></div>
|
||||
<span>[i["name"]]</span>
|
||||
</label>
|
||||
</li>"}
|
||||
<label class="switch">
|
||||
<input type="[inputtype]" value="1" name="[i["name"]]"[i["checked"] ? " checked" : ""][i["allowed_edit"] ? "" : " onclick='return false' onkeydown='return false'"]>
|
||||
<div class="slider [div_slider ? "[div_slider]" : ""]"></div>
|
||||
<span>[i["name"]]</span>
|
||||
</label>
|
||||
</li>"}
|
||||
else
|
||||
for (var/i in values)
|
||||
output += {"<li><input id="name="[i["name"]]"" style="width: 50px" type="[type]" name="[i["name"]]" value="[i["value"]]">
|
||||
<label for="[i["name"]]">[i["name"]]</label></li>"}
|
||||
<label for="[i["name"]]">[i["name"]]</label></li>"}
|
||||
output += {"</ul><div style="text-align:center">
|
||||
<button type="submit" name="button" value="1" style="font-size:large;float:[( Button2 ? "left" : "right" )]">[Button1]</button>"}
|
||||
|
||||
@@ -252,7 +254,7 @@
|
||||
output += {"<button type="submit" name="button" value="3" style="font-size:large;float:right">[Button3]</button>"}
|
||||
|
||||
output += {"</form></div>"}
|
||||
..(User, ckey("[User]-[Message]-[Title]-[world.time]-[rand(1,10000)]"), Title, 350, 350, src, StealFocus, Timeout)
|
||||
..(User, ckey("[User]-[Message]-[Title]-[world.time]-[rand(1,10000)]"), Title, width, height, src, StealFocus, Timeout)
|
||||
set_content(output)
|
||||
|
||||
/datum/browser/modal/listpicker/Topic(href,href_list)
|
||||
@@ -272,30 +274,32 @@
|
||||
opentime = 0
|
||||
close()
|
||||
|
||||
/proc/presentpicker(var/mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1,Timeout = 6000,list/values, inputtype = "checkbox")
|
||||
/proc/presentpicker(var/mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1,Timeout = 6000,list/values, inputtype = "checkbox", width, height, slidecolor)
|
||||
if (!istype(User))
|
||||
if (istype(User, /client/))
|
||||
var/client/C = User
|
||||
User = C.mob
|
||||
else
|
||||
return
|
||||
var/datum/browser/modal/listpicker/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus,Timeout, values, inputtype)
|
||||
var/datum/browser/modal/listpicker/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus,Timeout, values, inputtype, width, height, slidecolor)
|
||||
A.open()
|
||||
A.wait()
|
||||
if (A.selectedbutton)
|
||||
return list("button" = A.selectedbutton, "values" = A.valueslist)
|
||||
|
||||
/proc/input_bitfield(var/mob/User, title, bitfield, current_value)
|
||||
/proc/input_bitfield(var/mob/User, title, bitfield, current_value, nwidth = 350, nheight = 350, nslidecolor, allowed_edit_list = null)
|
||||
if (!User || !(bitfield in GLOB.bitfields))
|
||||
return
|
||||
var/list/pickerlist = list()
|
||||
for (var/i in GLOB.bitfields[bitfield])
|
||||
var/can_edit = 1
|
||||
if(!isnull(allowed_edit_list) && !(allowed_edit_list & GLOB.bitfields[bitfield][i]))
|
||||
can_edit = 0
|
||||
if (current_value & GLOB.bitfields[bitfield][i])
|
||||
pickerlist += list(list("checked" = 1, "value" = GLOB.bitfields[bitfield][i], "name" = i))
|
||||
pickerlist += list(list("checked" = 1, "value" = GLOB.bitfields[bitfield][i], "name" = i, "allowed_edit" = can_edit))
|
||||
else
|
||||
pickerlist += list(list("checked" = 0, "value" = GLOB.bitfields[bitfield][i], "name" = i))
|
||||
var/list/result = presentpicker(User, "", title, Button1="Save", Button2 = "Cancel", Timeout=FALSE, values = pickerlist)
|
||||
|
||||
pickerlist += list(list("checked" = 0, "value" = GLOB.bitfields[bitfield][i], "name" = i, "allowed_edit" = can_edit))
|
||||
var/list/result = presentpicker(User, "", title, Button1="Save", Button2 = "Cancel", Timeout=FALSE, values = pickerlist, width = nwidth, height = nheight, slidecolor = nslidecolor)
|
||||
if (islist(result))
|
||||
if (result["button"] == 2) // If the user pressed the cancel button
|
||||
return
|
||||
|
||||
@@ -109,6 +109,7 @@
|
||||
return
|
||||
..()
|
||||
|
||||
|
||||
//Proc to use when you 100% want to try to infect someone (ignoreing protective clothing and such), as long as they aren't immune
|
||||
/mob/living/proc/ForceContractDisease(datum/disease/D, make_copy = TRUE, del_on_fail = FALSE)
|
||||
if(!CanContractDisease(D))
|
||||
|
||||
@@ -109,6 +109,7 @@
|
||||
A.symptoms += S.Copy()
|
||||
A.properties = properties.Copy()
|
||||
A.id = id
|
||||
A.mutable = mutable
|
||||
//this is a new disease starting over at stage 1, so processing is not copied
|
||||
return A
|
||||
|
||||
@@ -166,13 +167,10 @@
|
||||
|
||||
var/the_id = GetDiseaseID()
|
||||
if(!SSdisease.archive_diseases[the_id])
|
||||
if(new_name)
|
||||
AssignName()
|
||||
SSdisease.archive_diseases[the_id] = src // So we don't infinite loop
|
||||
SSdisease.archive_diseases[the_id] = Copy()
|
||||
|
||||
var/datum/disease/advance/A = SSdisease.archive_diseases[the_id]
|
||||
name = A.name
|
||||
if(new_name)
|
||||
AssignName()
|
||||
|
||||
//Generate disease properties based on the effects. Returns an associated list.
|
||||
/datum/disease/advance/proc/GenerateProperties()
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
var/map_file = "BoxStation.dmm"
|
||||
|
||||
var/traits = null
|
||||
var/space_ruin_levels = 7
|
||||
var/space_empty_levels = 1
|
||||
|
||||
var/minetype = "lavaland"
|
||||
|
||||
@@ -106,6 +108,20 @@
|
||||
log_world("map_config traits is not a list!")
|
||||
return
|
||||
|
||||
var/temp = json["space_ruin_levels"]
|
||||
if (isnum(temp))
|
||||
space_ruin_levels = temp
|
||||
else if (!isnull(temp))
|
||||
log_world("map_config space_ruin_levels is not a number!")
|
||||
return
|
||||
|
||||
temp = json["space_empty_levels"]
|
||||
if (isnum(temp))
|
||||
space_empty_levels = temp
|
||||
else if (!isnull(temp))
|
||||
log_world("map_config space_empty_levels is not a number!")
|
||||
return
|
||||
|
||||
if ("minetype" in json)
|
||||
minetype = json["minetype"]
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/datum/martial_art/mushpunch
|
||||
name = "Mushroom Punch"
|
||||
|
||||
/datum/martial_art/mushpunch/basic_hit(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
var/atk_verb
|
||||
to_chat(A, "<span class='spider'>You begin to wind up an attack...</span>")
|
||||
if(do_after(A, 25, target = D))
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
atk_verb = pick("punches", "smashes", "ruptures", "cracks")
|
||||
D.visible_message("<span class='danger'>[A] [atk_verb] [D] with inhuman strength, sending [D.p_them()] flying backwards!</span>", \
|
||||
"<span class='userdanger'>[A] [atk_verb] you with inhuman strength, sending you flying backwards!</span>")
|
||||
D.apply_damage(rand(15,30), BRUTE)
|
||||
playsound(get_turf(D), 'sound/effects/meteorimpact.ogg', 25, 1, -1)
|
||||
var/throwtarget = get_edge_target_turf(A, get_dir(A, get_step_away(D, A)))
|
||||
D.throw_at(throwtarget, 4, 2, A)//So stuff gets tossed around at the same time.
|
||||
D.Knockdown(20)
|
||||
if(atk_verb)
|
||||
add_logs(A, D, "[atk_verb] (Mushroom Punch)")
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/mushpunch
|
||||
name = "mysterious mushroom"
|
||||
desc = "<I>Sapienza Ophioglossoides</I>:An odd mushroom from the flesh of a mushroom person. it has apparently retained some innate power of it's owner, as it quivers with barely-contained POWER!"
|
||||
icon = 'icons/obj/hydroponics/growing_mushrooms.dmi'
|
||||
icon_state = "mycelium-angel"
|
||||
|
||||
/obj/item/mushpunch/attack_self(mob/living/carbon/human/user)
|
||||
if(!istype(user) || !user)
|
||||
return
|
||||
var/message = "<span class='spider'>You devour [src], and a confluence of skill and power from the mushroom enhances your punches! You do need a short moment to charge these powerful punches.</span>"
|
||||
to_chat(user, message)
|
||||
var/datum/martial_art/mushpunch/mush = new(null)
|
||||
mush.teach(user)
|
||||
qdel(src)
|
||||
visible_message("<span class='warning'>[user] devours [src].</span>")
|
||||
@@ -85,6 +85,8 @@
|
||||
if(backpack_contents)
|
||||
for(var/path in backpack_contents)
|
||||
var/number = backpack_contents[path]
|
||||
if(!isnum(number))//Default to 1
|
||||
number = 1
|
||||
for(var/i=0,i<number,i++)
|
||||
H.equip_to_slot_or_del(new path(H),slot_in_backpack)
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
var/mob_trait //if applicable, apply and remove this mob trait
|
||||
var/mob/living/trait_holder
|
||||
|
||||
/datum/trait/New(mob/living/trait_mob)
|
||||
/datum/trait/New(mob/living/trait_mob, spawn_effects)
|
||||
..()
|
||||
if(!trait_mob || (human_only && !ishuman(trait_mob)) || trait_mob.has_trait_datum(type))
|
||||
qdel(src)
|
||||
@@ -23,9 +23,9 @@
|
||||
trait_holder.add_trait(mob_trait, ROUNDSTART_TRAIT)
|
||||
START_PROCESSING(SStraits, src)
|
||||
add()
|
||||
if(!SSticker.HasRoundStarted()) //on roundstart or on latejoin; latejoin code is in new_player.dm
|
||||
if(spawn_effects)
|
||||
on_spawn()
|
||||
addtimer(CALLBACK(src, .proc/post_add), 30)
|
||||
addtimer(CALLBACK(src, .proc/post_add), 30)
|
||||
|
||||
/datum/trait/Destroy()
|
||||
STOP_PROCESSING(SStraits, src)
|
||||
@@ -38,16 +38,25 @@
|
||||
SStraits.trait_objects -= src
|
||||
return ..()
|
||||
|
||||
/datum/trait/proc/transfer_mob(mob/living/to_mob)
|
||||
trait_holder.roundstart_traits -= src
|
||||
to_mob.roundstart_traits += src
|
||||
trait_holder = to_mob
|
||||
on_transfer()
|
||||
|
||||
/datum/trait/proc/add() //special "on add" effects
|
||||
/datum/trait/proc/on_spawn() //these should only trigger when the character is being created for the first time, i.e. roundstart/latejoin
|
||||
/datum/trait/proc/remove() //special "on remove" effects
|
||||
/datum/trait/proc/on_process() //process() has some special checks, so this is the actual process
|
||||
/datum/trait/proc/post_add() //for text, disclaimers etc. given after you spawn in with the trait
|
||||
/datum/trait/proc/on_transfer() //code called when the trait is transferred to a new mob
|
||||
|
||||
/datum/trait/process()
|
||||
if(QDELETED(trait_holder))
|
||||
qdel(src)
|
||||
return
|
||||
if(trait_holder.stat == DEAD)
|
||||
return
|
||||
on_process()
|
||||
|
||||
/mob/living/proc/get_trait_string(medical) //helper string. gets a string of all the traits the mob has
|
||||
@@ -67,6 +76,16 @@
|
||||
return "None"
|
||||
return dat.Join("<br>")
|
||||
|
||||
/mob/living/proc/cleanse_trait_datums() //removes all trait datums
|
||||
for(var/V in roundstart_traits)
|
||||
var/datum/trait/T = V
|
||||
qdel(T)
|
||||
|
||||
/mob/living/proc/transfer_trait_datums(mob/living/to_mob)
|
||||
for(var/V in roundstart_traits)
|
||||
var/datum/trait/T = V
|
||||
T.transfer_mob(to_mob)
|
||||
|
||||
/*
|
||||
|
||||
Commented version of Nearsighted to help you add your own traits
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
desc = "You walk with a gentle step, making stepping on sharp objects quieter and less painful."
|
||||
value = 1
|
||||
mob_trait = TRAIT_LIGHT_STEP
|
||||
gain_text = "<span class='notice'>You walk with a little more lithenessk.</span>"
|
||||
gain_text = "<span class='notice'>You walk with a little more litheness.</span>"
|
||||
lose_text = "<span class='danger'>You start tromping around like a barbarian.</span>"
|
||||
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
if(trait_holder.reagents.has_reagent("mindbreaker"))
|
||||
trait_holder.hallucination = 0
|
||||
return
|
||||
if(prob(1)) //we'll all be mad soon enough
|
||||
if(prob(2)) //we'll all be mad soon enough
|
||||
madness()
|
||||
|
||||
/datum/trait/insanity/proc/madness(mad_fools)
|
||||
|
||||
@@ -542,4 +542,4 @@
|
||||
if(EMERGENCY_ESCAPED_OR_ENDGAMED)
|
||||
SSticker.news_report = STATION_EVACUATED
|
||||
if(SSshuttle.emergency.is_hijacked())
|
||||
SSticker.news_report = SHUTTLE_HIJACK
|
||||
SSticker.news_report = SHUTTLE_HIJACK
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
anchored = TRUE
|
||||
use_power = IDLE_POWER_USE
|
||||
idle_power_usage = 0
|
||||
var/obj/item/device/radio/beacon/Beacon
|
||||
var/obj/item/device/beacon/Beacon
|
||||
|
||||
/obj/machinery/bluespace_beacon/Initialize()
|
||||
. = ..()
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
return examine(user)
|
||||
|
||||
//Start growing a human clone in the pod!
|
||||
/obj/machinery/clonepod/proc/growclone(ckey, clonename, ui, se, mindref, datum/species/mrace, list/features, factions)
|
||||
/obj/machinery/clonepod/proc/growclone(ckey, clonename, ui, se, mindref, datum/species/mrace, list/features, factions, list/traits)
|
||||
if(panel_open)
|
||||
return FALSE
|
||||
if(mess || attempting)
|
||||
@@ -198,6 +198,9 @@
|
||||
if(H)
|
||||
H.faction |= factions
|
||||
|
||||
for(var/V in traits)
|
||||
new V(H)
|
||||
|
||||
H.set_cloned_appearance()
|
||||
|
||||
H.suiciding = FALSE
|
||||
@@ -316,6 +319,7 @@
|
||||
SPEAK("An emergency ejection of [clonemind.name] has occurred. Survival not guaranteed.")
|
||||
to_chat(user, "<span class='notice'>You force an emergency ejection. </span>")
|
||||
go_out()
|
||||
mob_occupant.apply_vore_prefs()
|
||||
else
|
||||
return ..()
|
||||
|
||||
@@ -405,6 +409,7 @@
|
||||
connected_message(Gibberish("EMP-caused Accidental Ejection", 0))
|
||||
SPEAK(Gibberish("Exposure to electromagnetic fields has caused the ejection of [mob_occupant.real_name] prematurely." ,0))
|
||||
go_out()
|
||||
mob_occupant.apply_vore_prefs()
|
||||
..()
|
||||
|
||||
/obj/machinery/clonepod/ex_act(severity, target)
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
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"]))
|
||||
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"], R.fields["traits"]))
|
||||
temp = "[R.fields["name"]] => <font class='good'>Cloning cycle in progress...</font>"
|
||||
records -= R
|
||||
|
||||
@@ -409,7 +409,7 @@
|
||||
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"]))
|
||||
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"], C.fields["traits"]))
|
||||
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)
|
||||
@@ -482,6 +482,10 @@
|
||||
R.fields["blood_type"] = dna.blood_type
|
||||
R.fields["features"] = dna.features
|
||||
R.fields["factions"] = mob_occupant.faction
|
||||
R.fields["traits"] = list()
|
||||
for(var/V in mob_occupant.roundstart_traits)
|
||||
var/datum/trait/T = V
|
||||
R.fields["traits"] += T.type
|
||||
|
||||
if (!isnull(mob_occupant.mind)) //Save that mind so traitors can continue traitoring after cloning.
|
||||
R.fields["mind"] = "[REF(mob_occupant.mind)]"
|
||||
|
||||
@@ -75,4 +75,4 @@
|
||||
return 0
|
||||
if(B.scrambledcodes || B.emagged)
|
||||
return 0
|
||||
return ..()
|
||||
return ..()
|
||||
@@ -160,7 +160,7 @@
|
||||
var/list/L = list()
|
||||
var/list/areaindex = list()
|
||||
if(regime_set == "Teleporter")
|
||||
for(var/obj/item/device/radio/beacon/R in GLOB.teleportbeacons)
|
||||
for(var/obj/item/device/beacon/R in GLOB.teleportbeacons)
|
||||
if(is_eligible(R))
|
||||
var/area/A = get_area(R)
|
||||
L[avoid_assoc_duplicate_keys(A.name, areaindex)] = R
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
/obj/machinery/door/airlock/Initialize()
|
||||
. = ..()
|
||||
wires = new /datum/wires/airlock(src)
|
||||
if (cyclelinkeddir)
|
||||
cyclelinkairlock()
|
||||
if(frequency)
|
||||
set_frequency(frequency)
|
||||
|
||||
@@ -127,6 +125,8 @@
|
||||
|
||||
/obj/machinery/door/airlock/LateInitialize()
|
||||
. = ..()
|
||||
if (cyclelinkeddir)
|
||||
cyclelinkairlock()
|
||||
if(abandoned)
|
||||
var/outcome = rand(1,100)
|
||||
switch(outcome)
|
||||
@@ -178,6 +178,7 @@
|
||||
limit--
|
||||
while(!FoundDoor && limit)
|
||||
if (!FoundDoor)
|
||||
log_world("### MAP WARNING, [src] at [get_area_name(src, TRUE)] [COORD(src)] failed to find a valid airlock to cyclelink with!")
|
||||
return
|
||||
FoundDoor.cyclelinkedairlock = src
|
||||
cyclelinkedairlock = FoundDoor
|
||||
|
||||
@@ -68,4 +68,4 @@
|
||||
|
||||
/obj/machinery/door/poddoor/try_to_crowbar(obj/item/I, mob/user)
|
||||
if(stat & NOPOWER)
|
||||
open(1)
|
||||
open(1)
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
// SINGULO BEACON SPAWNER
|
||||
/obj/item/device/sbeacondrop
|
||||
name = "suspicious beacon"
|
||||
icon = 'icons/obj/radio.dmi'
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "beacon"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
|
||||
@@ -178,3 +178,4 @@
|
||||
priority = "Extreme"
|
||||
else
|
||||
priority = "Undetermined"
|
||||
|
||||
|
||||
@@ -850,7 +850,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
|
||||
product_ads = "Go save some lives!;The best stuff for your medbay.;Only the finest tools.;Natural chemicals!;This stuff saves lives.;Don't you want some?;Ping!"
|
||||
req_access_txt = "5"
|
||||
products = list(/obj/item/reagent_containers/syringe = 12, /obj/item/reagent_containers/dropper = 3, /obj/item/stack/medical/gauze = 8, /obj/item/reagent_containers/pill/patch/styptic = 5, /obj/item/reagent_containers/pill/insulin = 10,
|
||||
/obj/item/reagent_containers/pill/patch/silver_sulf = 5, /obj/item/reagent_containers/glass/bottle/charcoal = 4, /obj/item/reagent_containers/spray/medical/sterilizer = 1,
|
||||
/obj/item/reagent_containers/pill/patch/silver_sulf = 5, /obj/item/reagent_containers/medspray/styptic = 2, /obj/item/reagent_containers/medspray/silver_sulf = 2, /obj/item/reagent_containers/glass/bottle/charcoal = 4, /obj/item/reagent_containers/medspray/sterilizine = 1,
|
||||
/obj/item/reagent_containers/glass/bottle/epinephrine = 4, /obj/item/reagent_containers/glass/bottle/morphine = 4, /obj/item/reagent_containers/glass/bottle/salglu_solution = 3,
|
||||
/obj/item/reagent_containers/glass/bottle/toxin = 3, /obj/item/reagent_containers/syringe/antiviral = 6, /obj/item/reagent_containers/pill/salbutamol = 2, /obj/item/device/healthanalyzer = 4, /obj/item/device/sensor_device = 2, /obj/item/pinpointer/crew = 2)
|
||||
contraband = list(/obj/item/reagent_containers/pill/tox = 3, /obj/item/reagent_containers/pill/morphine = 4, /obj/item/reagent_containers/pill/charcoal = 6)
|
||||
@@ -876,7 +876,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
|
||||
density = FALSE
|
||||
products = list(/obj/item/reagent_containers/syringe = 3, /obj/item/reagent_containers/pill/patch/styptic = 5,
|
||||
/obj/item/reagent_containers/pill/patch/silver_sulf = 5, /obj/item/reagent_containers/pill/charcoal = 2,
|
||||
/obj/item/reagent_containers/spray/medical/sterilizer = 1)
|
||||
/obj/item/reagent_containers/medspray/sterilizine = 1)
|
||||
contraband = list(/obj/item/reagent_containers/pill/tox = 2, /obj/item/reagent_containers/pill/morphine = 2)
|
||||
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
|
||||
resistance_flags = FIRE_PROOF
|
||||
|
||||
@@ -19,3 +19,4 @@
|
||||
/obj/mecha/combat/durand/RemoveActions(mob/living/user, human_occupant = 0)
|
||||
..()
|
||||
defense_action.Remove(user)
|
||||
|
||||
|
||||
@@ -27,3 +27,4 @@
|
||||
..()
|
||||
switch_damtype_action.Remove(user)
|
||||
phasing_action.Remove(user)
|
||||
|
||||
|
||||
@@ -193,9 +193,9 @@
|
||||
var/turf/T = safepick(get_area_turfs(impact_area))
|
||||
if(T)
|
||||
// Calculate new position (searches through beacons in world)
|
||||
var/obj/item/device/radio/beacon/chosen
|
||||
var/obj/item/device/beacon/chosen
|
||||
var/list/possible = list()
|
||||
for(var/obj/item/device/radio/beacon/W in GLOB.teleportbeacons)
|
||||
for(var/obj/item/device/beacon/W in GLOB.teleportbeacons)
|
||||
possible += W
|
||||
|
||||
if(possible.len > 0)
|
||||
@@ -218,7 +218,7 @@
|
||||
var/y_distance = TO.y - FROM.y
|
||||
var/x_distance = TO.x - FROM.x
|
||||
for (var/atom/movable/A in urange(12, FROM )) // iterate thru list of mobs in the area
|
||||
if(istype(A, /obj/item/device/radio/beacon))
|
||||
if(istype(A, /obj/item/device/beacon))
|
||||
continue // don't teleport beacons because that's just insanely stupid
|
||||
if(A.anchored)
|
||||
continue
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
/obj/item/reagent_containers/food/snacks/egg)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/gladiator
|
||||
name = "gladitator costume spawner"
|
||||
name = "gladiator costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/under/gladiator,
|
||||
/obj/item/clothing/head/helmet/gladiator)
|
||||
|
||||
@@ -547,7 +547,6 @@
|
||||
/obj/item/circuitboard/machine/tesla_coil/Initialize()
|
||||
. = ..()
|
||||
if(build_path)
|
||||
name = "Tesla Coil (Machine Board)"
|
||||
build_path = PATH_POWERCOIL
|
||||
|
||||
/obj/item/circuitboard/machine/tesla_coil/attackby(obj/item/I, mob/user, params)
|
||||
|
||||
@@ -648,4 +648,4 @@
|
||||
item_state = "defibpaddles0"
|
||||
req_defib = FALSE
|
||||
|
||||
#undef HALFWAYCRITDEATH
|
||||
#undef HALFWAYCRITDEATH
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/obj/item/device/beacon
|
||||
name = "\improper tracking beacon"
|
||||
desc = "A beacon used by a teleporter."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "beacon"
|
||||
item_state = "beacon"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
var/enabled = TRUE
|
||||
var/renamed = FALSE
|
||||
|
||||
/obj/item/device/beacon/Initialize()
|
||||
. = ..()
|
||||
if (enabled)
|
||||
GLOB.teleportbeacons += src
|
||||
else
|
||||
icon_state = "beacon-off"
|
||||
|
||||
/obj/item/device/beacon/Destroy()
|
||||
GLOB.teleportbeacons.Remove(src)
|
||||
return ..()
|
||||
|
||||
/obj/item/device/beacon/attack_self(mob/user)
|
||||
enabled = !enabled
|
||||
if (enabled)
|
||||
icon_state = "beacon"
|
||||
GLOB.teleportbeacons += src
|
||||
else
|
||||
icon_state = "beacon-off"
|
||||
GLOB.teleportbeacons.Remove(src)
|
||||
to_chat(user, "<span class='notice'>You [enabled ? "enable" : "disable"] the beacon.</span>")
|
||||
return
|
||||
|
||||
/obj/item/device/beacon/attackby(obj/item/W, mob/user)
|
||||
if(istype(W, /obj/item/pen)) // needed for things that use custom names like the locator
|
||||
var/new_name = stripped_input(user, "What would you like the name to be?")
|
||||
if(!user.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
if(new_name)
|
||||
name = new_name
|
||||
renamed = TRUE
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
@@ -1,32 +0,0 @@
|
||||
/obj/item/device/radio/beacon
|
||||
name = "tracking beacon"
|
||||
desc = "A beacon used by a teleporter."
|
||||
icon_state = "beacon"
|
||||
item_state = "beacon"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
var/code = "electronic"
|
||||
dog_fashion = null
|
||||
|
||||
/obj/item/device/radio/beacon/Initialize()
|
||||
. = ..()
|
||||
GLOB.teleportbeacons += src
|
||||
|
||||
/obj/item/device/radio/beacon/Destroy()
|
||||
GLOB.teleportbeacons.Remove(src)
|
||||
return ..()
|
||||
|
||||
/obj/item/device/radio/beacon/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans, message_mode)
|
||||
return
|
||||
|
||||
/obj/item/device/radio/beacon/verb/alter_signal(t as text)
|
||||
set name = "Alter Beacon's Signal"
|
||||
set category = "Object"
|
||||
set src in usr
|
||||
|
||||
if ((usr.canmove && !( usr.restrained() )))
|
||||
src.code = t
|
||||
if (!( src.code ))
|
||||
src.code = "beacon"
|
||||
src.add_fingerprint(usr)
|
||||
return
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
//CREATOR'S NOTE: DO NOT FUCKING GIVE THIS TO BOTANY!
|
||||
/obj/item/hot_potato
|
||||
name = "hot potato"
|
||||
|
||||
@@ -192,6 +192,14 @@
|
||||
for(var/i in 1 to 7)
|
||||
new /obj/item/reagent_containers/glass/beaker( src )
|
||||
|
||||
/obj/item/storage/box/medsprays
|
||||
name = "box of medical sprayers"
|
||||
desc = "A box full of medical sprayers, with unscrewable caps and precision spray heads."
|
||||
|
||||
/obj/item/storage/box/medsprays/PopulateContents()
|
||||
for(var/i in 1 to 7)
|
||||
new /obj/item/reagent_containers/medspray( src )
|
||||
|
||||
/obj/item/storage/box/injectors
|
||||
name = "box of DNA injectors"
|
||||
desc = "This box contains injectors, it seems."
|
||||
|
||||
@@ -17,9 +17,6 @@
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "locator"
|
||||
var/temp = null
|
||||
var/frequency = FREQ_LOCATOR_IMPLANT
|
||||
var/broadcasting = null
|
||||
var/listening = 1
|
||||
flags_1 = CONDUCT_1
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
item_state = "electronic"
|
||||
@@ -32,17 +29,11 @@
|
||||
/obj/item/locator/attack_self(mob/user)
|
||||
user.set_machine(src)
|
||||
var/dat
|
||||
if (src.temp)
|
||||
dat = "[src.temp]<BR><BR><A href='byond://?src=[REF(src)];temp=1'>Clear</A>"
|
||||
if (temp)
|
||||
dat = "[temp]<BR><BR><A href='byond://?src=[REF(src)];temp=1'>Clear</A>"
|
||||
else
|
||||
dat = {"
|
||||
<B>Persistent Signal Locator</B><HR>
|
||||
Frequency:
|
||||
<A href='byond://?src=[REF(src)];freq=-10'>-</A>
|
||||
<A href='byond://?src=[REF(src)];freq=-2'>-</A> [format_frequency(src.frequency)]
|
||||
<A href='byond://?src=[REF(src)];freq=2'>+</A>
|
||||
<A href='byond://?src=[REF(src)];freq=10'>+</A><BR>
|
||||
|
||||
<A href='?src=[REF(src)];refresh=1'>Refresh</A>"}
|
||||
user << browse(dat, "window=radio")
|
||||
onclose(user, "radio")
|
||||
@@ -59,30 +50,30 @@ Frequency:
|
||||
if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)))
|
||||
usr.set_machine(src)
|
||||
if (href_list["refresh"])
|
||||
src.temp = "<B>Persistent Signal Locator</B><HR>"
|
||||
temp = "<B>Persistent Signal Locator</B><HR>"
|
||||
var/turf/sr = get_turf(src)
|
||||
|
||||
if (sr)
|
||||
src.temp += "<B>Located Beacons:</B><BR>"
|
||||
|
||||
for(var/obj/item/device/radio/beacon/W in GLOB.teleportbeacons)
|
||||
if (W.frequency == src.frequency)
|
||||
var/turf/tr = get_turf(W)
|
||||
if (tr.z == sr.z && tr)
|
||||
var/direct = max(abs(tr.x - sr.x), abs(tr.y - sr.y))
|
||||
if (direct < 5)
|
||||
direct = "very strong"
|
||||
temp += "<B>Beacon Signals:</B><BR>"
|
||||
for(var/obj/item/device/beacon/W in GLOB.teleportbeacons)
|
||||
if (!W.renamed)
|
||||
continue
|
||||
var/turf/tr = get_turf(W)
|
||||
if (tr.z == sr.z && tr)
|
||||
var/direct = max(abs(tr.x - sr.x), abs(tr.y - sr.y))
|
||||
if (direct < 5)
|
||||
direct = "very strong"
|
||||
else
|
||||
if (direct < 10)
|
||||
direct = "strong"
|
||||
else
|
||||
if (direct < 10)
|
||||
direct = "strong"
|
||||
if (direct < 20)
|
||||
direct = "weak"
|
||||
else
|
||||
if (direct < 20)
|
||||
direct = "weak"
|
||||
else
|
||||
direct = "very weak"
|
||||
src.temp += "[W.code]-[dir2text(get_dir(sr, tr))]-[direct]<BR>"
|
||||
direct = "very weak"
|
||||
temp += "[W.name]-[dir2text(get_dir(sr, tr))]-[direct]<BR>"
|
||||
|
||||
src.temp += "<B>Extranneous Signals:</B><BR>"
|
||||
temp += "<B>Implant Signals:</B><BR>"
|
||||
for (var/obj/item/implant/tracking/W in GLOB.tracked_implants)
|
||||
if (!W.imp_in || !isliving(W.loc))
|
||||
continue
|
||||
@@ -103,18 +94,14 @@ Frequency:
|
||||
direct = "strong"
|
||||
else
|
||||
direct = "weak"
|
||||
src.temp += "[W.imp_in.name]-[dir2text(get_dir(sr, tr))]-[direct]<BR>"
|
||||
temp += "[W.imp_in.name]-[dir2text(get_dir(sr, tr))]-[direct]<BR>"
|
||||
|
||||
src.temp += "<B>You are at \[[sr.x],[sr.y],[sr.z]\]</B> in orbital coordinates.<BR><BR><A href='byond://?src=[REF(src)];refresh=1'>Refresh</A><BR>"
|
||||
temp += "<B>You are at \[[sr.x],[sr.y],[sr.z]\]</B> in orbital coordinates.<BR><BR><A href='byond://?src=[REF(src)];refresh=1'>Refresh</A><BR>"
|
||||
else
|
||||
src.temp += "<B><FONT color='red'>Processing Error:</FONT></B> Unable to locate orbital position.<BR>"
|
||||
temp += "<B><FONT color='red'>Processing Error:</FONT></B> Unable to locate orbital position.<BR>"
|
||||
else
|
||||
if (href_list["freq"])
|
||||
src.frequency += text2num(href_list["freq"])
|
||||
src.frequency = sanitize_frequency(src.frequency)
|
||||
else
|
||||
if (href_list["temp"])
|
||||
src.temp = null
|
||||
if (href_list["temp"])
|
||||
temp = null
|
||||
if (ismob(src.loc))
|
||||
attack_self(src.loc)
|
||||
else
|
||||
|
||||
@@ -357,5 +357,5 @@
|
||||
if(get_fuel() < max_fuel && nextrefueltick < world.time)
|
||||
nextrefueltick = world.time + 10
|
||||
reagents.add_reagent("welding_fuel", 1)
|
||||
|
||||
#undef WELDER_FUEL_BURN_INTERVAL
|
||||
|
||||
#undef WELDER_FUEL_BURN_INTERVAL
|
||||
@@ -42,6 +42,7 @@
|
||||
icon_state = "waterballoon-e"
|
||||
item_state = "balloon-empty"
|
||||
|
||||
|
||||
/obj/item/toy/balloon/New()
|
||||
create_reagents(10)
|
||||
..()
|
||||
@@ -286,6 +287,7 @@
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
|
||||
/obj/item/toy/windupToolbox
|
||||
name = "windup toolbox"
|
||||
desc = "A replica toolbox that rumbles when you turn the key."
|
||||
@@ -332,7 +334,7 @@
|
||||
|
||||
/obj/item/toy/katana
|
||||
name = "replica katana"
|
||||
desc = "Woefully underpowered in D20. Almost has a sharp edge."
|
||||
desc = "Woefully underpowered in D20."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "katana"
|
||||
item_state = "katana"
|
||||
|
||||
@@ -62,4 +62,4 @@
|
||||
new /obj/item/gun/energy/laser/bluetag(src)
|
||||
for(var/i in 1 to 3)
|
||||
new /obj/item/clothing/suit/bluetag(src)
|
||||
new /obj/item/clothing/head/helmet/bluetaghelm(src)
|
||||
new /obj/item/clothing/head/helmet/bluetaghelm(src)
|
||||
|
||||
@@ -96,3 +96,5 @@
|
||||
..()
|
||||
new /obj/item/storage/box/pillbottles(src)
|
||||
new /obj/item/storage/box/pillbottles(src)
|
||||
new /obj/item/storage/box/medsprays(src)
|
||||
new /obj/item/storage/box/medsprays(src)
|
||||
@@ -15,9 +15,17 @@
|
||||
var/openable = TRUE
|
||||
var/obj/item/electronics/airlock/electronics
|
||||
var/start_showpiece_type = null //add type for items on display
|
||||
var/list/start_showpieces = list() //Takes sublists in the form of list("type" = /obj/item/bikehorn, "trophy_message" = "henk")
|
||||
var/trophy_message = ""
|
||||
|
||||
/obj/structure/displaycase/Initialize()
|
||||
. = ..()
|
||||
if(start_showpieces.len && !start_showpiece_type)
|
||||
var/list/showpiece_entry = pick(start_showpieces)
|
||||
if (showpiece_entry && showpiece_entry["type"])
|
||||
start_showpiece_type = showpiece_entry["type"]
|
||||
if (showpiece_entry["trophy_message"])
|
||||
trophy_message = showpiece_entry["trophy_message"]
|
||||
if(start_showpiece_type)
|
||||
showpiece = new start_showpiece_type (src)
|
||||
update_icon()
|
||||
@@ -35,6 +43,9 @@
|
||||
to_chat(user, "<span class='notice'>Hooked up with an anti-theft system.</span>")
|
||||
if(showpiece)
|
||||
to_chat(user, "<span class='notice'>There's [showpiece] inside.</span>")
|
||||
if(trophy_message)
|
||||
to_chat(user, "The plaque reads:")
|
||||
to_chat(user, trophy_message)
|
||||
|
||||
|
||||
/obj/structure/displaycase/proc/dump()
|
||||
@@ -213,7 +224,7 @@
|
||||
//The captains display case requiring specops ID access is intentional.
|
||||
//The lab cage and captains display case do not spawn with electronics, which is why req_access is needed.
|
||||
/obj/structure/displaycase/captain
|
||||
alert = 1
|
||||
alert = TRUE
|
||||
start_showpiece_type = /obj/item/gun/energy/laser/captain
|
||||
req_access = list(ACCESS_CENT_SPECOPS)
|
||||
|
||||
@@ -223,12 +234,9 @@
|
||||
start_showpiece_type = /obj/item/clothing/mask/facehugger/lamarr
|
||||
req_access = list(ACCESS_RD)
|
||||
|
||||
|
||||
|
||||
/obj/structure/displaycase/trophy
|
||||
name = "trophy display case"
|
||||
desc = "Store your trophies of accomplishment in here, and they will stay forever."
|
||||
var/trophy_message = ""
|
||||
var/placer_key = ""
|
||||
var/added_roundstart = TRUE
|
||||
var/is_locked = TRUE
|
||||
@@ -245,12 +253,6 @@
|
||||
GLOB.trophy_cases -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/displaycase/trophy/examine(mob/user)
|
||||
..()
|
||||
if(trophy_message)
|
||||
to_chat(user, "The plaque reads:")
|
||||
to_chat(user, trophy_message)
|
||||
|
||||
/obj/structure/displaycase/trophy/attackby(obj/item/W, mob/user, params)
|
||||
|
||||
if(!user.Adjacent(src)) //no TK museology
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
name = "magic mirror"
|
||||
desc = "Turn and face the strange... face."
|
||||
icon_state = "magic_mirror"
|
||||
var/list/races_blacklist = list("skeleton", "agent", "angel", "military_synth", "memezombies", "clockwork golem servant", "android", "synth")
|
||||
var/list/races_blacklist = list("skeleton", "agent", "angel", "military_synth", "memezombies", "clockwork golem servant", "android", "synth", "mush")
|
||||
var/list/choosable_races = list()
|
||||
|
||||
/obj/structure/mirror/magic/New()
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
|
||||
|
||||
|
||||
/obj/structure/statue
|
||||
name = "statue"
|
||||
desc = "Placeholder. Yell at Firecage if you SOMEHOW see this."
|
||||
@@ -16,47 +13,21 @@
|
||||
/obj/structure/statue/attackby(obj/item/W, mob/living/user, params)
|
||||
add_fingerprint(user)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
if(istype(W, /obj/item/wrench))
|
||||
if(anchored)
|
||||
user.visible_message("[user] is loosening the [name]'s bolts.", \
|
||||
"<span class='notice'>You are loosening the [name]'s bolts...</span>")
|
||||
if(W.use_tool(src, user, 40, volume=100))
|
||||
if(!anchored)
|
||||
return
|
||||
user.visible_message("[user] loosened the [name]'s bolts!", \
|
||||
"<span class='notice'>You loosen the [name]'s bolts!</span>")
|
||||
anchored = FALSE
|
||||
else
|
||||
if(!isfloorturf(src.loc))
|
||||
user.visible_message("<span class='warning'>A floor must be present to secure the [name]!</span>")
|
||||
return
|
||||
user.visible_message("[user] is securing the [name]'s bolts...", \
|
||||
"<span class='notice'>You are securing the [name]'s bolts...</span>")
|
||||
if(W.use_tool(src, user, 40, volume=100))
|
||||
if(anchored)
|
||||
return
|
||||
user.visible_message("[user] has secured the [name]'s bolts.", \
|
||||
"<span class='notice'>You have secured the [name]'s bolts.</span>")
|
||||
anchored = TRUE
|
||||
if(!(flags_1 & NODECONSTRUCT_1))
|
||||
if(default_unfasten_wrench(user, W))
|
||||
return
|
||||
if(istype(W, /obj/item/weldingtool) || istype(W, /obj/item/gun/energy/plasmacutter))
|
||||
if(!W.tool_start_check(user, amount=0))
|
||||
return FALSE
|
||||
|
||||
else if(istype(W, /obj/item/pickaxe/drill/jackhammer))
|
||||
user.visible_message("[user] destroys the [name]!",
|
||||
"<span class='notice'>You destroy the [name].</span>")
|
||||
W.play_tool_sound(src)
|
||||
qdel(src)
|
||||
|
||||
else if(istype(W, /obj/item/weldingtool) || istype(W, /obj/item/gun/energy/plasmacutter))
|
||||
if(!W.tool_start_check(user, amount=0))
|
||||
return FALSE
|
||||
|
||||
user.visible_message("[user] is slicing apart the [name].", \
|
||||
"<span class='notice'>You are slicing apart the [name]...</span>")
|
||||
if(W.use_tool(src, user, 40, volume=50))
|
||||
user.visible_message("[user] slices apart the [name].", \
|
||||
"<span class='notice'>You slice apart the [name]!</span>")
|
||||
deconstruct(TRUE)
|
||||
else
|
||||
return ..()
|
||||
user.visible_message("[user] is slicing apart the [name].", \
|
||||
"<span class='notice'>You are slicing apart the [name]...</span>")
|
||||
if(W.use_tool(src, user, 40, volume=50))
|
||||
user.visible_message("[user] slices apart the [name].", \
|
||||
"<span class='notice'>You slice apart the [name]!</span>")
|
||||
deconstruct(TRUE)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/structure/statue/attack_hand(mob/living/user)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
|
||||
@@ -826,7 +826,7 @@
|
||||
|
||||
//returns 1 to let the dragdrop code know we are trapping this event
|
||||
//returns 0 if we don't plan to trap the event
|
||||
/datum/admins/proc/cmd_ghost_drag(mob/dead/observer/frommob, mob/living/tomob)
|
||||
/datum/admins/proc/cmd_ghost_drag(mob/dead/observer/frommob, mob/tomob)
|
||||
|
||||
//this is the exact two check rights checks required to edit a ckey with vv.
|
||||
if (!check_rights(R_VAREDIT,0) || !check_rights(R_SPAWN|R_DEBUG,0))
|
||||
|
||||
+128
-270
@@ -1,13 +1,17 @@
|
||||
GLOBAL_LIST_EMPTY(admin_ranks) //list of all admin_rank datums
|
||||
GLOBAL_PROTECT(admin_ranks)
|
||||
|
||||
GLOBAL_LIST_EMPTY(protected_ranks) //admin ranks loaded from txt
|
||||
GLOBAL_PROTECT(protected_ranks)
|
||||
|
||||
/datum/admin_rank
|
||||
var/name = "NoRank"
|
||||
var/rights = R_DEFAULT
|
||||
var/list/adds
|
||||
var/list/subs
|
||||
var/exclude_rights = 0
|
||||
var/include_rights = 0
|
||||
var/can_edit_rights = 0
|
||||
|
||||
/datum/admin_rank/New(init_name, init_rights, list/init_adds, list/init_subs)
|
||||
/datum/admin_rank/New(init_name, init_rights, init_exclude_rights, init_edit_rights)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
@@ -17,19 +21,18 @@ GLOBAL_PROTECT(admin_ranks)
|
||||
CRASH("Admin proc call creation of admin datum")
|
||||
return
|
||||
name = init_name
|
||||
switch(name)
|
||||
if("Removed",null,"")
|
||||
QDEL_IN(src, 0)
|
||||
throw EXCEPTION("invalid admin-rank name")
|
||||
return
|
||||
if(!name)
|
||||
qdel(src)
|
||||
throw EXCEPTION("Admin rank created without name.")
|
||||
return
|
||||
if(init_rights)
|
||||
rights = init_rights
|
||||
if(!init_adds)
|
||||
init_adds = list()
|
||||
if(!init_subs)
|
||||
init_subs = list()
|
||||
adds = init_adds
|
||||
subs = init_subs
|
||||
include_rights = rights
|
||||
if(init_exclude_rights)
|
||||
exclude_rights = init_exclude_rights
|
||||
rights &= ~exclude_rights
|
||||
if(init_edit_rights)
|
||||
can_edit_rights = init_edit_rights
|
||||
|
||||
/datum/admin_rank/Destroy()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
@@ -39,6 +42,9 @@ GLOBAL_PROTECT(admin_ranks)
|
||||
return QDEL_HINT_LETMELIVE
|
||||
. = ..()
|
||||
|
||||
/datum/admin_rank/can_vv_get(var_name)
|
||||
return FALSE
|
||||
|
||||
/datum/admin_rank/vv_edit_var(var_name, var_value)
|
||||
return FALSE
|
||||
|
||||
@@ -75,13 +81,12 @@ GLOBAL_PROTECT(admin_ranks)
|
||||
flag = R_SPAWN
|
||||
if("autologin", "autoadmin")
|
||||
flag = R_AUTOLOGIN
|
||||
if("dbranks")
|
||||
flag = R_DBRANKS
|
||||
if("@","prev")
|
||||
flag = previous_rights
|
||||
return flag
|
||||
|
||||
/proc/admin_keyword_to_path(word) //use this with verb keywords eg +/client/proc/blah
|
||||
return text2path(copytext(word, 2, findtext(word, " ", 2, 0)))
|
||||
|
||||
// Adds/removes rights to this admin_rank
|
||||
/datum/admin_rank/proc/process_keyword(word, previous_rights=0)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
@@ -94,157 +99,156 @@ GLOBAL_PROTECT(admin_ranks)
|
||||
switch(text2ascii(word,1))
|
||||
if(43)
|
||||
rights |= flag //+
|
||||
include_rights |= flag
|
||||
if(45)
|
||||
rights &= ~flag //-
|
||||
else
|
||||
//isn't a keyword so maybe it's a verbpath?
|
||||
var/path = admin_keyword_to_path(word)
|
||||
if(path)
|
||||
switch(text2ascii(word,1))
|
||||
if(43)
|
||||
if(!subs.Remove(path))
|
||||
adds += path //+
|
||||
if(45)
|
||||
if(!adds.Remove(path))
|
||||
subs += path //-
|
||||
|
||||
exclude_rights |= flag
|
||||
if(42)
|
||||
can_edit_rights |= flag //*
|
||||
|
||||
// Checks for (keyword-formatted) rights on this admin
|
||||
/datum/admins/proc/check_keyword(word)
|
||||
var/flag = admin_keyword_to_flag(word)
|
||||
if(flag)
|
||||
return ((rank.rights & flag) == flag) //true only if right has everything in flag
|
||||
else
|
||||
var/path = admin_keyword_to_path(word)
|
||||
for(var/i in owner.verbs) //this needs to be a foreach loop for some reason. in operator and verbs.Find() don't work
|
||||
if(i == path)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//load our rank - > rights associations
|
||||
/proc/load_admin_ranks()
|
||||
/proc/load_admin_ranks(dbfail)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='admin prefix'>Admin Reload blocked: Advanced ProcCall detected.</span>")
|
||||
return
|
||||
GLOB.admin_ranks.Cut()
|
||||
|
||||
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("[global.config.directory]/admin_ranks.txt"))
|
||||
if(!line)
|
||||
continue
|
||||
if(findtextEx(line,"#",1,2))
|
||||
continue
|
||||
|
||||
var/next = findtext(line, "=")
|
||||
var/datum/admin_rank/R = new(ckeyEx(copytext(line, 1, next)))
|
||||
if(!R)
|
||||
continue
|
||||
GLOB.admin_ranks += R
|
||||
|
||||
var/prev = findchar(line, "+-", next, 0)
|
||||
while(prev)
|
||||
next = findchar(line, "+-", prev + 1, 0)
|
||||
R.process_keyword(copytext(line, prev, next), previous_rights)
|
||||
prev = next
|
||||
|
||||
previous_rights = R.rights
|
||||
else
|
||||
if(!SSdbcore.Connect())
|
||||
if(CONFIG_GET(flag/sql_enabled))
|
||||
var/msg = "Failed to connect to database in load_admin_ranks(). Reverting to legacy system."
|
||||
log_world(msg)
|
||||
WRITE_FILE(GLOB.world_game_log, msg)
|
||||
CONFIG_SET(flag/admin_legacy_system, TRUE)
|
||||
load_admin_ranks()
|
||||
return
|
||||
|
||||
var/datum/DBQuery/query_load_admin_ranks = SSdbcore.NewQuery("SELECT rank, flags FROM [format_table_name("admin_ranks")]")
|
||||
GLOB.protected_ranks.Cut()
|
||||
var/previous_rights = 0
|
||||
//load text from file and process each line separately
|
||||
for(var/line in world.file2list("[global.config.directory]/admin_ranks.txt"))
|
||||
if(!line || findtextEx(line,"#",1,2))
|
||||
continue
|
||||
var/next = findtext(line, "=")
|
||||
var/datum/admin_rank/R = new(ckeyEx(copytext(line, 1, next)))
|
||||
if(!R)
|
||||
continue
|
||||
GLOB.admin_ranks += R
|
||||
GLOB.protected_ranks += R
|
||||
var/prev = findchar(line, "+-*", next, 0)
|
||||
while(prev)
|
||||
next = findchar(line, "+-*", prev + 1, 0)
|
||||
R.process_keyword(copytext(line, prev, next), previous_rights)
|
||||
prev = next
|
||||
previous_rights = R.rights
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) || dbfail)
|
||||
var/datum/DBQuery/query_load_admin_ranks = SSdbcore.NewQuery("SELECT rank, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")]")
|
||||
if(!query_load_admin_ranks.Execute())
|
||||
message_admins("Error loading admin ranks from database. Loading from backup.")
|
||||
log_sql("Error loading admin ranks from database. Loading from backup.")
|
||||
dbfail = 1
|
||||
else
|
||||
while(query_load_admin_ranks.NextRow())
|
||||
var/skip
|
||||
var/rank_name = query_load_admin_ranks.item[1]
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
if(R.name == rank_name) //this rank was already loaded from txt override
|
||||
skip = 1
|
||||
break
|
||||
if(!skip)
|
||||
var/rank_flags = text2num(query_load_admin_ranks.item[2])
|
||||
var/rank_exclude_flags = text2num(query_load_admin_ranks.item[3])
|
||||
var/rank_can_edit_flags = text2num(query_load_admin_ranks.item[4])
|
||||
var/datum/admin_rank/R = new(rank_name, rank_flags, rank_exclude_flags, rank_can_edit_flags)
|
||||
if(!R)
|
||||
continue
|
||||
GLOB.admin_ranks += R
|
||||
//load ranks from backup file
|
||||
if(dbfail)
|
||||
var/backup_file = file("data/admins_backup.json")
|
||||
if(!fexists(backup_file))
|
||||
log_world("Unable to locate admins backup file.")
|
||||
return
|
||||
while(query_load_admin_ranks.NextRow())
|
||||
var/rank_name = ckeyEx(query_load_admin_ranks.item[1])
|
||||
var/flags = query_load_admin_ranks.item[2]
|
||||
if(istext(flags))
|
||||
flags = text2num(flags)
|
||||
var/datum/admin_rank/R = new(rank_name, flags)
|
||||
var/list/json = json_decode(file2text(backup_file))
|
||||
for(var/J in json["ranks"])
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
if(R.name == "[J]") //this rank was already loaded from txt override
|
||||
continue
|
||||
var/datum/admin_rank/R = new("[J]", json["ranks"]["[J]"]["include rights"], json["ranks"]["[J]"]["exclude rights"], json["ranks"]["[J]"]["can edit rights"])
|
||||
if(!R)
|
||||
continue
|
||||
GLOB.admin_ranks += R
|
||||
|
||||
return 1
|
||||
#ifdef TESTING
|
||||
var/msg = "Permission Sets Built:\n"
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
msg += "\t[R.name]"
|
||||
var/rights = rights2text(R.rights,"\n\t\t",R.adds,R.subs)
|
||||
var/rights = rights2text(R.rights,"\n\t\t")
|
||||
if(rights)
|
||||
msg += "\t\t[rights]\n"
|
||||
testing(msg)
|
||||
#endif
|
||||
|
||||
|
||||
/proc/load_admins()
|
||||
var/dbfail
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && !SSdbcore.Connect())
|
||||
message_admins("Failed to connect to database while loading admins. Loading from backup.")
|
||||
log_sql("Failed to connect to database while loading admins. Loading from backup.")
|
||||
dbfail = 1
|
||||
//clear the datums references
|
||||
|
||||
GLOB.admin_datums.Cut()
|
||||
for(var/client/C in GLOB.admins)
|
||||
C.remove_admin_verbs()
|
||||
C.holder = null
|
||||
GLOB.admins.Cut()
|
||||
GLOB.protected_admins.Cut()
|
||||
GLOB.deadmins.Cut()
|
||||
load_admin_ranks()
|
||||
dbfail = load_admin_ranks(dbfail)
|
||||
//Clear profile access
|
||||
for(var/A in world.GetConfig("admin"))
|
||||
world.SetConfig("APP/admin", A, null)
|
||||
|
||||
var/list/rank_names = list()
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
rank_names[R.name] = R
|
||||
|
||||
if(CONFIG_GET(flag/admin_legacy_system))
|
||||
//load text from file
|
||||
var/list/lines = world.file2list("[global.config.directory]/admins.txt")
|
||||
|
||||
//process each line separately
|
||||
for(var/line in lines)
|
||||
if(!length(line))
|
||||
continue
|
||||
if(findtextEx(line, "#", 1, 2))
|
||||
continue
|
||||
|
||||
var/list/entry = splittext(line, "=")
|
||||
if(entry.len < 2)
|
||||
continue
|
||||
|
||||
var/ckey = ckey(entry[1])
|
||||
var/rank = ckeyEx(entry[2])
|
||||
if(!ckey || !rank)
|
||||
continue
|
||||
|
||||
new /datum/admins(rank_names[rank], ckey)
|
||||
|
||||
else
|
||||
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_SET(flag/admin_legacy_system, TRUE)
|
||||
load_admins()
|
||||
return
|
||||
|
||||
//ckeys listed in admins.txt are always made admins before sql loading is attempted
|
||||
var/list/lines = world.file2list("[global.config.directory]/admins.txt")
|
||||
for(var/line in lines)
|
||||
if(!length(line) || findtextEx(line, "#", 1, 2))
|
||||
continue
|
||||
var/list/entry = splittext(line, "=")
|
||||
if(entry.len < 2)
|
||||
continue
|
||||
var/ckey = ckey(entry[1])
|
||||
var/rank = ckeyEx(entry[2])
|
||||
if(!ckey || !rank)
|
||||
continue
|
||||
new /datum/admins(rank_names[rank], ckey, 0, 1)
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) || dbfail)
|
||||
var/datum/DBQuery/query_load_admins = SSdbcore.NewQuery("SELECT ckey, rank FROM [format_table_name("admin")]")
|
||||
if(!query_load_admins.Execute())
|
||||
message_admins("Error loading admins from database. Loading from backup.")
|
||||
log_sql("Error loading admins from database. Loading from backup.")
|
||||
dbfail = 1
|
||||
else
|
||||
while(query_load_admins.NextRow())
|
||||
var/admin_ckey = query_load_admins.item[1]
|
||||
var/admin_rank = query_load_admins.item[2]
|
||||
var/skip
|
||||
if(rank_names[admin_rank] == null)
|
||||
message_admins("[admin_ckey] loaded with invalid admin rank [admin_rank].")
|
||||
log_sql("[admin_ckey] loaded with invalid admin rank [admin_rank].")
|
||||
skip = 1
|
||||
if(GLOB.admin_datums[admin_ckey] || GLOB.deadmins[admin_ckey])
|
||||
skip = 1
|
||||
if(!skip)
|
||||
new /datum/admins(rank_names[admin_rank], admin_ckey)
|
||||
//load admins from backup file
|
||||
if(dbfail)
|
||||
var/backup_file = file("data/admins_backup.json")
|
||||
if(!fexists(backup_file))
|
||||
log_world("Unable to locate admins backup file.")
|
||||
return
|
||||
while(query_load_admins.NextRow())
|
||||
var/ckey = ckey(query_load_admins.item[1])
|
||||
var/rank = ckeyEx(query_load_admins.item[2])
|
||||
|
||||
if(rank_names[rank] == null)
|
||||
WARNING("Admin rank ([rank]) does not exist.")
|
||||
continue
|
||||
|
||||
new /datum/admins(rank_names[rank], ckey)
|
||||
|
||||
var/list/json = json_decode(file2text(backup_file))
|
||||
for(var/J in json["admins"])
|
||||
for(var/A in GLOB.admin_datums + GLOB.deadmins)
|
||||
if(A == "[J]") //this admin was already loaded from txt override
|
||||
continue
|
||||
new /datum/admins(rank_names[json["admins"]["[J]"]], "[J]")
|
||||
#ifdef TESTING
|
||||
var/msg = "Admins Built:\n"
|
||||
for(var/ckey in GLOB.admin_datums)
|
||||
@@ -252,7 +256,7 @@ GLOBAL_PROTECT(admin_ranks)
|
||||
msg += "\t[ckey] - [D.rank.name]\n"
|
||||
testing(msg)
|
||||
#endif
|
||||
|
||||
return dbfail
|
||||
|
||||
#ifdef TESTING
|
||||
/client/verb/changerank(newrank in GLOB.admin_ranks)
|
||||
@@ -271,149 +275,3 @@ GLOBAL_PROTECT(admin_ranks)
|
||||
remove_admin_verbs()
|
||||
holder.associate(src)
|
||||
#endif
|
||||
|
||||
/datum/admins/proc/edit_rights_topic(list/href_list)
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
message_admins("[key_name_admin(usr)] attempted to edit the admin permissions without sufficient rights.")
|
||||
log_admin("[key_name(usr)] attempted to edit the admin permissions without sufficient rights.")
|
||||
return
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='admin prefix'>Admin Edit blocked: Advanced ProcCall detected.</span>")
|
||||
return
|
||||
|
||||
var/adm_ckey
|
||||
var/task = href_list["editrights"]
|
||||
switch(task)
|
||||
if("add")
|
||||
var/new_ckey = ckey(input(usr,"New admin's ckey","Admin ckey", null) as text|null)
|
||||
if(!new_ckey)
|
||||
return
|
||||
if(new_ckey in GLOB.admin_datums)
|
||||
to_chat(usr, "<font color='red'>Error: Topic 'editrights': [new_ckey] is already an admin</font>")
|
||||
return
|
||||
adm_ckey = new_ckey
|
||||
task = "rank"
|
||||
else
|
||||
adm_ckey = ckey(href_list["ckey"])
|
||||
if(!adm_ckey)
|
||||
to_chat(usr, "<font color='red'>Error: Topic 'editrights': No valid ckey</font>")
|
||||
return
|
||||
|
||||
var/datum/admins/D = GLOB.admin_datums[adm_ckey]
|
||||
if (!D)
|
||||
D = GLOB.deadmins[adm_ckey]
|
||||
|
||||
switch(task)
|
||||
if("remove")
|
||||
if(alert("Are you sure you want to remove [adm_ckey]?","Message","Yes","Cancel") == "Yes")
|
||||
if(!D)
|
||||
return
|
||||
if(!check_if_greater_rights_than_holder(D))
|
||||
message_admins("[key_name_admin(usr)] attempted to remove [adm_ckey] from the admins list without sufficient rights.")
|
||||
log_admin("[key_name(usr)] attempted to remove [adm_ckey] from the admins list without sufficient rights.")
|
||||
return
|
||||
GLOB.admin_datums -= adm_ckey
|
||||
GLOB.deadmins -= adm_ckey
|
||||
D.disassociate()
|
||||
|
||||
updateranktodb(adm_ckey, "player")
|
||||
message_admins("[key_name_admin(usr)] removed [adm_ckey] from the admins list")
|
||||
log_admin("[key_name(usr)] removed [adm_ckey] from the admins list")
|
||||
log_admin_rank_modification(adm_ckey, "Removed")
|
||||
|
||||
if("rank")
|
||||
var/datum/admin_rank/R
|
||||
|
||||
var/list/rank_names = list("*New Rank*")
|
||||
for(R in GLOB.admin_ranks)
|
||||
rank_names[R.name] = R
|
||||
|
||||
var/new_rank = input("Please select a rank", "New rank", null, null) as null|anything in rank_names
|
||||
|
||||
switch(new_rank)
|
||||
if(null)
|
||||
return
|
||||
if("*New Rank*")
|
||||
new_rank = ckeyEx(input("Please input a new rank", "New custom rank", null, null) as null|text)
|
||||
if(!new_rank)
|
||||
return
|
||||
|
||||
if(D)
|
||||
if(!check_if_greater_rights_than_holder(D))
|
||||
message_admins("[key_name_admin(usr)] attempted to change the rank of [adm_ckey] to [new_rank] without sufficient rights.")
|
||||
log_admin("[key_name(usr)] attempted to change the rank of [adm_ckey] to [new_rank] without sufficient rights.")
|
||||
return
|
||||
|
||||
R = rank_names[new_rank]
|
||||
if(!R) //rank with that name doesn't exist yet - make it
|
||||
if(D)
|
||||
R = new(new_rank, D.rank.rights, D.rank.adds, D.rank.subs) //duplicate our previous admin_rank but with a new name
|
||||
else
|
||||
R = new(new_rank) //blank new admin_rank
|
||||
GLOB.admin_ranks += R
|
||||
|
||||
if(D) //they were previously an admin
|
||||
D.disassociate() //existing admin needs to be disassociated
|
||||
D.rank = R //set the admin_rank as our rank
|
||||
D.associate()
|
||||
else
|
||||
D = new(R, adm_ckey, TRUE) //new admin
|
||||
|
||||
updateranktodb(adm_ckey, new_rank)
|
||||
message_admins("[key_name_admin(usr)] edited the admin rank of [adm_ckey] to [new_rank]")
|
||||
log_admin("[key_name(usr)] edited the admin rank of [adm_ckey] to [new_rank]")
|
||||
log_admin_rank_modification(adm_ckey, new_rank)
|
||||
|
||||
if("permissions")
|
||||
if(!D)
|
||||
return //they're not an admin!
|
||||
|
||||
var/keyword = input("Input permission keyword (one at a time):\ne.g. +BAN or -FUN or +/client/proc/someverb", "Permission toggle", null, null) as null|text
|
||||
if(!keyword)
|
||||
return
|
||||
|
||||
if(!check_keyword(keyword) || !check_if_greater_rights_than_holder(D))
|
||||
message_admins("[key_name_admin(usr)] attempted to give [adm_ckey] the keyword [keyword] without sufficient rights.")
|
||||
log_admin("[key_name(usr)] attempted to give [adm_ckey] the keyword [keyword] without sufficient rights.")
|
||||
return
|
||||
|
||||
D.disassociate()
|
||||
|
||||
if(!findtext(D.rank.name, "([adm_ckey])")) //not a modified subrank, need to duplicate the admin_rank datum to prevent modifying others too
|
||||
D.rank = new("[D.rank.name]([adm_ckey])", D.rank.rights, D.rank.adds, D.rank.subs) //duplicate our previous admin_rank but with a new name
|
||||
//we don't add this clone to the admin_ranks list, as it is unique to that ckey
|
||||
D.rank.process_keyword(keyword)
|
||||
|
||||
var/client/C = GLOB.directory[adm_ckey] //find the client with the specified ckey (if they are logged in)
|
||||
D.associate(C) //link up with the client and add verbs
|
||||
|
||||
message_admins("[key_name(usr)] added keyword [keyword] to permission of [adm_ckey]")
|
||||
log_admin("[key_name(usr)] added keyword [keyword] to permission of [adm_ckey]")
|
||||
log_admin_permission_modification(adm_ckey, D.rank.rights)
|
||||
if("activate") //forcefully readmin
|
||||
if(!D || !D.deadmined)
|
||||
return
|
||||
|
||||
D.activate()
|
||||
|
||||
message_admins("[key_name_admin(usr)] forcefully readmined [adm_ckey]")
|
||||
log_admin("[key_name(usr)] forcefully readmined [adm_ckey]")
|
||||
if("deactivate") //forcefully deadmin
|
||||
if(!D || D.deadmined)
|
||||
return
|
||||
|
||||
message_admins("[key_name_admin(usr)] forcefully deadmined [adm_ckey]")
|
||||
log_admin("[key_name(usr)] forcefully deadmined [adm_ckey]")
|
||||
|
||||
D.deactivate() //after logs so the deadmined admin can see the message.
|
||||
|
||||
edit_admin_permissions()
|
||||
|
||||
/datum/admins/proc/updateranktodb(ckey,newrank)
|
||||
if(!SSdbcore.Connect())
|
||||
return
|
||||
var/sql_ckey = sanitizeSQL(ckey)
|
||||
var/sql_admin_rank = sanitizeSQL(newrank)
|
||||
|
||||
var/datum/DBQuery/query_admin_rank_update = SSdbcore.NewQuery("UPDATE [format_table_name("player")] SET lastadminrank = '[sql_admin_rank]' WHERE ckey = '[sql_ckey]'")
|
||||
query_admin_rank_update.Execute()
|
||||
|
||||
@@ -157,7 +157,7 @@ GLOBAL_LIST_INIT(admin_verbs_debug, world.AVerbsDebug())
|
||||
/client/proc/pump_random_event,
|
||||
/client/proc/cmd_display_init_log,
|
||||
/client/proc/cmd_display_overlay_log,
|
||||
/datum/admins/proc/create_or_modify_area
|
||||
/datum/admins/proc/create_or_modify_area,
|
||||
)
|
||||
GLOBAL_PROTECT(admin_verbs_possess)
|
||||
GLOBAL_LIST_INIT(admin_verbs_possess, list(/proc/possess, /proc/release))
|
||||
@@ -267,11 +267,6 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
|
||||
if(rights & R_SPAWN)
|
||||
verbs += GLOB.admin_verbs_spawn
|
||||
|
||||
for(var/path in holder.rank.adds)
|
||||
verbs += path
|
||||
for(var/path in holder.rank.subs)
|
||||
verbs -= path
|
||||
|
||||
/client/proc/remove_admin_verbs()
|
||||
verbs.Remove(
|
||||
GLOB.admin_verbs_default,
|
||||
@@ -306,8 +301,6 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
|
||||
/client/proc/cmd_admin_areatest_station,
|
||||
/client/proc/readmin
|
||||
)
|
||||
if(holder)
|
||||
verbs.Remove(holder.rank.adds)
|
||||
|
||||
/client/proc/hide_most_verbs()//Allows you to keep some functionality while hiding some verbs
|
||||
set name = "Adminverbs - Hide Most"
|
||||
@@ -528,8 +521,10 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
|
||||
set desc = "Get the estimated range of a bomb, using explosive power."
|
||||
|
||||
var/ex_power = input("Explosive Power:") as null|num
|
||||
if (isnull(ex_power))
|
||||
return
|
||||
var/range = round((2 * ex_power)**GLOB.DYN_EX_SCALE)
|
||||
to_chat(usr, "Estimated Explosive Range: (Devestation: [round(range*0.25)], Heavy: [round(range*0.5)], Light: [round(range)])")
|
||||
to_chat(usr, "Estimated Explosive Range: (Devastation: [round(range*0.25)], Heavy: [round(range*0.5)], Light: [round(range)])")
|
||||
|
||||
/client/proc/get_dynex_power()
|
||||
set category = "Debug"
|
||||
@@ -537,6 +532,8 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
|
||||
set desc = "Get the estimated required power of a bomb, to reach a specific range."
|
||||
|
||||
var/ex_range = input("Light Explosion Range:") as null|num
|
||||
if (isnull(ex_range))
|
||||
return
|
||||
var/power = (0.5 * ex_range)**(1/GLOB.DYN_EX_SCALE)
|
||||
to_chat(usr, "Estimated Explosive Power: [power]")
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
GLOBAL_LIST_EMPTY(admin_datums)
|
||||
GLOBAL_PROTECT(admin_datums)
|
||||
GLOBAL_LIST_EMPTY(protected_admins)
|
||||
GLOBAL_PROTECT(protected_admins)
|
||||
|
||||
GLOBAL_VAR_INIT(href_token, GenerateToken())
|
||||
GLOBAL_PROTECT(href_token)
|
||||
@@ -26,7 +28,7 @@ GLOBAL_PROTECT(href_token)
|
||||
|
||||
var/deadmined
|
||||
|
||||
/datum/admins/New(datum/admin_rank/R, ckey, force_active = FALSE)
|
||||
/datum/admins/New(datum/admin_rank/R, ckey, force_active = FALSE, protected)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
@@ -51,6 +53,8 @@ GLOBAL_PROTECT(href_token)
|
||||
if(R.rights & R_DEBUG) //grant profile access
|
||||
world.SetConfig("APP/admin", ckey, "role=admin")
|
||||
//only admins with +ADMIN start admined
|
||||
if(protected)
|
||||
GLOB.protected_admins[target] = src
|
||||
if (force_active || (R.rights & R_AUTOLOGIN))
|
||||
activate()
|
||||
else
|
||||
@@ -142,6 +146,9 @@ GLOBAL_PROTECT(href_token)
|
||||
return 1 //we have all the rights they have and more
|
||||
return 0
|
||||
|
||||
/datum/admins/can_vv_get(var_name, var_value)
|
||||
return FALSE //nice try trialmin
|
||||
|
||||
/datum/admins/vv_edit_var(var_name, var_value)
|
||||
return FALSE //nice try trialmin
|
||||
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
/client/proc/edit_admin_permissions()
|
||||
set category = "Admin"
|
||||
set name = "Permissions Panel"
|
||||
set desc = "Edit admin permissions"
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
return
|
||||
usr.client.holder.edit_admin_permissions()
|
||||
|
||||
/datum/admins/proc/edit_admin_permissions()
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
return
|
||||
|
||||
var/list/output = list({"<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Permissions Panel</title>
|
||||
<script type='text/javascript' src='search.js'></script>
|
||||
<link rel='stylesheet' type='text/css' href='panels.css'>
|
||||
</head>
|
||||
<body onload='selectTextField();updateSearch();'>
|
||||
<div id='main'><table id='searchable' cellspacing='0'>
|
||||
<tr class='title'>
|
||||
<th style='width:150px;text-align:right;'>CKEY <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=add'>\[+\]</a></th>
|
||||
<th style='width:125px;'>RANK</th>
|
||||
<th style='width:40%;'>PERMISSIONS</th>
|
||||
<th style='width:20%;'>DENIED</th>
|
||||
<th style='width:40%;'>ALLOWED TO EDIT</th>
|
||||
</tr>
|
||||
"})
|
||||
|
||||
for(var/adm_ckey in GLOB.admin_datums+GLOB.deadmins)
|
||||
var/datum/admins/D = GLOB.admin_datums[adm_ckey]
|
||||
if(!D)
|
||||
D = GLOB.deadmins[adm_ckey]
|
||||
if (!D)
|
||||
continue
|
||||
|
||||
var/deadminlink = ""
|
||||
if (D.deadmined)
|
||||
deadminlink = " <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=activate;ckey=[adm_ckey]'>\[RA\]</a>"
|
||||
else
|
||||
deadminlink = " <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=deactivate;ckey=[adm_ckey]'>\[DA\]</a>"
|
||||
|
||||
output += "<tr>"
|
||||
output += "<td style='text-align:right;'>[adm_ckey] [deadminlink]<a class='small' href='?src=[REF(src)];[HrefToken()];editrights=remove;ckey=[adm_ckey]'>\[-\]</a></td>"
|
||||
output += "<td><a href='?src=[REF(src)];[HrefToken()];editrights=rank;ckey=[adm_ckey]'>[D.rank.name]</a></td>"
|
||||
output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;ckey=[adm_ckey]'>[rights2text(D.rank.include_rights," ")]</a></td>"
|
||||
output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;ckey=[adm_ckey]'>[rights2text(D.rank.exclude_rights," ", "-")]</a></td>"
|
||||
output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;ckey=[adm_ckey]'>[rights2text(D.rank.can_edit_rights," ", "*")]</a></td>"
|
||||
output += "</tr>"
|
||||
|
||||
output += {"
|
||||
</table></div>
|
||||
<div id='top'><b>Search:</b> <input type='text' id='filter' value='' style='width:70%;' onkeyup='updateSearch();'></div>
|
||||
</body>
|
||||
</html>"}
|
||||
|
||||
usr << browse(jointext(output, ""),"window=editrights;size=1000x650")
|
||||
|
||||
/datum/admins/proc/edit_rights_topic(list/href_list)
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
message_admins("[key_name_admin(usr)] attempted to edit admin permissions without sufficient rights.")
|
||||
log_admin("[key_name(usr)] attempted to edit admin permissions without sufficient rights.")
|
||||
return
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='admin prefix'>Admin Edit blocked: Advanced ProcCall detected.</span>")
|
||||
return
|
||||
var/datum/asset/permissions_assets = get_asset_datum(/datum/asset/simple/permissions)
|
||||
permissions_assets.send(src)
|
||||
var/admin_ckey = ckey(href_list["ckey"])
|
||||
var/datum/admins/D = GLOB.admin_datums[admin_ckey]
|
||||
var/use_db
|
||||
var/task = href_list["editrights"]
|
||||
var/skip
|
||||
if(task == "activate" || task == "deactivate")
|
||||
skip = 1
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_admins) && task == "rank")
|
||||
if(admin_ckey in GLOB.protected_admins)
|
||||
to_chat(usr, "<span class='admin prefix'>Editing the rank of this admin is blocked by server configuration.</span>")
|
||||
return
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_ranks) && task == "permissions")
|
||||
if(D.rank in GLOB.protected_ranks)
|
||||
to_chat(usr, "<span class='admin prefix'>Editing the flags of this rank is blocked by server configuration.</span>")
|
||||
return
|
||||
if(check_rights(R_DBRANKS, 0))
|
||||
if(!skip)
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Unable to connect to database, changes are temporary only.</span>")
|
||||
use_db = "Temporary"
|
||||
if(!use_db)
|
||||
use_db = alert("Permanent changes are saved to the database for future rounds, temporary changes will affect only the current round", "Permanent or Temporary?", "Permanent", "Temporary", "Cancel")
|
||||
if(use_db == "Cancel")
|
||||
return
|
||||
if(use_db == "Permanent")
|
||||
use_db = 1
|
||||
admin_ckey = sanitizeSQL(admin_ckey)
|
||||
else
|
||||
use_db = 0
|
||||
if(task != "add")
|
||||
D = GLOB.admin_datums[admin_ckey]
|
||||
if(!D)
|
||||
D = GLOB.deadmins[admin_ckey]
|
||||
if(!D)
|
||||
return
|
||||
if(!check_if_greater_rights_than_holder(D))
|
||||
message_admins("[key_name_admin(usr)] attempted to change the rank of [admin_ckey] without sufficient rights.")
|
||||
log_admin("[key_name(usr)] attempted to change the rank of [admin_ckey] without sufficient rights.")
|
||||
switch(task)
|
||||
if("add")
|
||||
admin_ckey = add_admin(use_db)
|
||||
if(!admin_ckey)
|
||||
return
|
||||
change_admin_rank(admin_ckey, use_db)
|
||||
if("remove")
|
||||
remove_admin(admin_ckey, use_db, D)
|
||||
if("rank")
|
||||
change_admin_rank(admin_ckey, use_db, D)
|
||||
if("permissions")
|
||||
change_admin_flags(admin_ckey, use_db, D)
|
||||
if("activate")
|
||||
force_readmin(admin_ckey, D)
|
||||
if("deactivate")
|
||||
force_deadmin(admin_ckey, D)
|
||||
edit_admin_permissions()
|
||||
|
||||
/datum/admins/proc/add_admin(use_db)
|
||||
. = sanitizeSQL(ckey(input("New admin's ckey","Admin ckey") as text|null))
|
||||
if(!.)
|
||||
return 0
|
||||
if(. in GLOB.admin_datums+GLOB.deadmins)
|
||||
to_chat(usr, "<span class='danger'>[.] is already an admin.</span>")
|
||||
return 0
|
||||
if(use_db)
|
||||
var/datum/DBQuery/query_add_admin = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin")] (ckey, rank) VALUES ('[.]', 'NEW ADMIN')")
|
||||
if(!query_add_admin.warn_execute())
|
||||
return 0
|
||||
var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'add admin', 'New admin added: [.]')")
|
||||
if(!query_add_admin_log.warn_execute())
|
||||
return 0
|
||||
|
||||
/datum/admins/proc/remove_admin(admin_ckey, use_db, datum/admins/D)
|
||||
if(alert("Are you sure you want to remove [admin_ckey]?","Confirm Removal","Do it","Cancel") == "Do it")
|
||||
GLOB.admin_datums -= admin_ckey
|
||||
GLOB.deadmins -= admin_ckey
|
||||
D.disassociate()
|
||||
if(use_db)
|
||||
var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("DELETE FROM [format_table_name("admin")] WHERE ckey = '[admin_ckey]'")
|
||||
if(!query_add_rank.warn_execute())
|
||||
return
|
||||
var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'remove admin', 'Admin removed: [admin_ckey]')")
|
||||
if(!query_add_rank_log.warn_execute())
|
||||
return
|
||||
message_admins("[key_name_admin(usr)] removed [admin_ckey] from the admins list [use_db ? "permanently" : "temporarily"]")
|
||||
log_admin("[key_name(usr)] removed [admin_ckey] from the admins list [use_db ? "permanently" : "temporarily"]")
|
||||
|
||||
/datum/admins/proc/force_readmin(admin_ckey, datum/admins/D)
|
||||
if(!D || !D.deadmined)
|
||||
return
|
||||
D.activate()
|
||||
message_admins("[key_name_admin(usr)] forcefully readmined [admin_ckey]")
|
||||
log_admin("[key_name(usr)] forcefully readmined [admin_ckey]")
|
||||
|
||||
/datum/admins/proc/force_deadmin(admin_ckey, datum/admins/D)
|
||||
if(!D || D.deadmined)
|
||||
return
|
||||
message_admins("[key_name_admin(usr)] forcefully deadmined [admin_ckey]")
|
||||
log_admin("[key_name(usr)] forcefully deadmined [admin_ckey]")
|
||||
D.deactivate() //after logs so the deadmined admin can see the message.
|
||||
|
||||
/datum/admins/proc/change_admin_rank(admin_ckey, use_db, datum/admins/D)
|
||||
var/datum/admin_rank/R
|
||||
var/list/rank_names = list("*New Rank*")
|
||||
for(R in GLOB.admin_ranks)
|
||||
if((R.rights & usr.client.holder.rank.can_edit_rights) == R.rights)
|
||||
rank_names[R.name] = R
|
||||
var/new_rank = input("Please select a rank", "New rank") as null|anything in rank_names
|
||||
if(new_rank == "*New Rank*")
|
||||
new_rank = sanitizeSQL(ckeyEx(input("Please input a new rank", "New custom rank") as text|null))
|
||||
if(!new_rank)
|
||||
return
|
||||
R = rank_names[new_rank]
|
||||
if(!R) //rank with that name doesn't exist yet - make it
|
||||
if(D)
|
||||
R = new(new_rank, D.rank.rights) //duplicate our previous admin_rank but with a new name
|
||||
else
|
||||
R = new(new_rank) //blank new admin_rank
|
||||
GLOB.admin_ranks += R
|
||||
if(use_db)
|
||||
if(!R)
|
||||
var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_ranks")] (rank, flags, exclude_flags, can_edit_rights) VALUES ('[new_rank]', '0', '0', '0')")
|
||||
if(!query_add_rank.warn_execute())
|
||||
return
|
||||
var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'add rank', 'New rank added: [admin_ckey]')")
|
||||
if(!query_add_rank_log.warn_execute())
|
||||
return
|
||||
var/old_rank
|
||||
var/datum/DBQuery/query_get_rank = SSdbcore.NewQuery("SELECT rank FROM [format_table_name("admin")] WHERE ckey = '[admin_ckey]'")
|
||||
if(!query_get_rank.warn_execute())
|
||||
return
|
||||
if(query_get_rank.NextRow())
|
||||
old_rank = query_get_rank.item[1]
|
||||
var/datum/DBQuery/query_change_rank = SSdbcore.NewQuery("UPDATE [format_table_name("admin")] SET rank = '[new_rank]' WHERE ckey = '[admin_ckey]'")
|
||||
if(!query_change_rank.warn_execute())
|
||||
return
|
||||
var/datum/DBQuery/query_change_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'change admin rank', 'Rank of [admin_ckey] changed from [old_rank] to [new_rank]')")
|
||||
if(!query_change_rank_log.warn_execute())
|
||||
return
|
||||
if(D) //they were previously an admin
|
||||
D.disassociate() //existing admin needs to be disassociated
|
||||
D.rank = R //set the admin_rank as our rank
|
||||
D.associate()
|
||||
else
|
||||
D = new(R, admin_ckey, TRUE) //new admin
|
||||
message_admins("[key_name_admin(usr)] edited the admin rank of [admin_ckey] to [new_rank] [use_db ? "permanently" : "temporarily"]")
|
||||
log_admin("[key_name(usr)] edited the admin rank of [admin_ckey] to [new_rank] [use_db ? "permanently" : "temporarily"]")
|
||||
|
||||
/datum/admins/proc/change_admin_flags(admin_ckey, use_db, datum/admins/D)
|
||||
var/new_flags = input_bitfield(usr, "Include permission flags<br>[use_db ? "This will affect ALL admins with this rank." : "This will affect only the current admin [admin_ckey]"]", "admin_flags", D.rank.include_rights, 350, 590, allowed_edit_list = usr.client.holder.rank.can_edit_rights)
|
||||
if(isnull(new_flags))
|
||||
return
|
||||
var/new_exclude_flags = input_bitfield(usr, "Exclude permission flags<br>Flags enabled here will be removed from a rank.<br>Note these take precedence over included flags.<br>[use_db ? "This will affect ALL admins with this rank." : "This will affect only the current admin [admin_ckey]"]", "admin_flags", D.rank.exclude_rights, 350, 660, "red", usr.client.holder.rank.can_edit_rights)
|
||||
if(isnull(new_exclude_flags))
|
||||
return
|
||||
var/new_can_edit_flags = input_bitfield(usr, "Editable permission flags<br>These are the flags this rank is allowed to edit if they have access to the permissions panel.<br>They will be unable to modify admins to a rank that has a flag not included here.<br>[use_db ? "This will affect ALL admins with this rank." : "This will affect only the current admin [admin_ckey]"]", "admin_flags", D.rank.can_edit_rights, 350, 710, allowed_edit_list = usr.client.holder.rank.can_edit_rights)
|
||||
if(isnull(new_can_edit_flags))
|
||||
return
|
||||
if(use_db)
|
||||
var/old_flags
|
||||
var/old_exclude_flags
|
||||
var/old_can_edit_flags
|
||||
var/datum/DBQuery/query_get_rank_flags = SSdbcore.NewQuery("SELECT flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")] WHERE rank = '[D.rank.name]'")
|
||||
if(!query_get_rank_flags.warn_execute())
|
||||
return
|
||||
if(query_get_rank_flags.NextRow())
|
||||
old_flags = text2num(query_get_rank_flags.item[1])
|
||||
old_exclude_flags = text2num(query_get_rank_flags.item[2])
|
||||
old_can_edit_flags = text2num(query_get_rank_flags.item[3])
|
||||
var/datum/DBQuery/query_change_rank_flags = SSdbcore.NewQuery("UPDATE [format_table_name("admin_ranks")] SET flags = '[new_flags]', exclude_flags = '[new_exclude_flags]', can_edit_flags = '[new_can_edit_flags]' WHERE rank = '[D.rank.name]'")
|
||||
if(!query_change_rank_flags.warn_execute())
|
||||
return
|
||||
var/datum/DBQuery/query_change_rank_flags_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, adminckey, adminip, operation, log) VALUES ('[SQLtime()]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'change rank flags', 'Permissions of [admin_ckey] changed from[rights2text(old_flags," ")][rights2text(old_exclude_flags," ", "-")][rights2text(old_can_edit_flags," ", "*")] to[rights2text(new_flags," ")][rights2text(new_exclude_flags," ", "-")][rights2text(new_can_edit_flags," ", "*")]')")
|
||||
if(!query_change_rank_flags_log.warn_execute())
|
||||
return
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
if(R.name != D.rank.name)
|
||||
continue
|
||||
R.rights = new_flags &= ~new_exclude_flags
|
||||
R.exclude_rights = new_exclude_flags
|
||||
R.include_rights = new_flags
|
||||
R.can_edit_rights = new_can_edit_flags
|
||||
for(var/i in GLOB.admin_datums+GLOB.deadmins)
|
||||
var/datum/admins/A = GLOB.admin_datums[i]
|
||||
if(!A)
|
||||
A = GLOB.deadmins[i]
|
||||
if (!A)
|
||||
continue
|
||||
if(A.rank.name != D.rank.name)
|
||||
continue
|
||||
var/client/C = GLOB.directory[A.target]
|
||||
A.disassociate()
|
||||
A.associate(C)
|
||||
else
|
||||
D.disassociate()
|
||||
if(!findtext(D.rank.name, "([admin_ckey])")) //not a modified subrank, need to duplicate the admin_rank datum to prevent modifying others too
|
||||
D.rank = new("[D.rank.name]([admin_ckey])", new_flags, new_exclude_flags, new_can_edit_flags) //duplicate our previous admin_rank but with a new name
|
||||
//we don't add this clone to the admin_ranks list, as it is unique to that ckey
|
||||
else
|
||||
D.rank.rights = new_flags &= ~new_exclude_flags
|
||||
D.rank.include_rights = new_flags
|
||||
D.rank.exclude_rights = new_exclude_flags
|
||||
var/client/C = GLOB.directory[admin_ckey] //find the client with the specified ckey (if they are logged in)
|
||||
D.associate(C) //link up with the client and add verbs
|
||||
message_admins("[key_name_admin(usr)] edited the permissions of [use_db ? " rank [D.rank.name] permanently" : "[admin_ckey] temporarily"]")
|
||||
log_admin("[key_name(usr)] edited the permissions of [use_db ? " rank [D.rank.name] permanently" : "[admin_ckey] temporarily"]")
|
||||
@@ -1,145 +0,0 @@
|
||||
/client/proc/edit_admin_permissions()
|
||||
set category = "Admin"
|
||||
set name = "Permissions Panel"
|
||||
set desc = "Edit admin permissions"
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
return
|
||||
usr.client.holder.edit_admin_permissions()
|
||||
|
||||
/datum/admins/proc/edit_admin_permissions()
|
||||
if(!check_rights(R_PERMISSIONS))
|
||||
return
|
||||
|
||||
var/list/output = list({"<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Permissions Panel</title>
|
||||
<script type='text/javascript' src='search.js'></script>
|
||||
<link rel='stylesheet' type='text/css' href='panels.css'>
|
||||
</head>
|
||||
<body onload='selectTextField();updateSearch();'>
|
||||
<div id='main'><table id='searchable' cellspacing='0'>
|
||||
<tr class='title'>
|
||||
<th style='width:125px;text-align:right;'>CKEY <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=add'>\[+\]</a></th>
|
||||
<th style='width:125px;'>RANK</th>
|
||||
<th style='width:375px;'>PERMISSIONS</th>
|
||||
<th style='width:100%;'>VERB-OVERRIDES</th>
|
||||
</tr>
|
||||
"})
|
||||
|
||||
for(var/adm_ckey in GLOB.admin_datums+GLOB.deadmins)
|
||||
var/datum/admins/D = GLOB.admin_datums[adm_ckey]
|
||||
if(!D)
|
||||
D = GLOB.deadmins[adm_ckey]
|
||||
if (!D)
|
||||
continue
|
||||
|
||||
var/rights = rights2text(D.rank.rights," ")
|
||||
if(!rights)
|
||||
rights = "*none*"
|
||||
var/deadminlink = ""
|
||||
if (D.deadmined)
|
||||
deadminlink = " <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=activate;ckey=[adm_ckey]'>\[RA\]</a>"
|
||||
else
|
||||
deadminlink = " <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=deactivate;ckey=[adm_ckey]'>\[DA\]</a>"
|
||||
|
||||
output += "<tr>"
|
||||
output += "<td style='text-align:right;'>[adm_ckey] [deadminlink]<a class='small' href='?src=[REF(src)];[HrefToken()];editrights=remove;ckey=[adm_ckey]'>\[-\]</a></td>"
|
||||
output += "<td><a href='?src=[REF(src)];[HrefToken()];editrights=rank;ckey=[adm_ckey]'>[D.rank.name]</a></td>"
|
||||
output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;ckey=[adm_ckey]'>[rights]</a></td>"
|
||||
output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;ckey=[adm_ckey]'>[rights2text(0," ",D.rank.adds,D.rank.subs)]</a></td>"
|
||||
output += "</tr>"
|
||||
|
||||
output += {"
|
||||
</table></div>
|
||||
<div id='top'><b>Search:</b> <input type='text' id='filter' value='' style='width:70%;' onkeyup='updateSearch();'></div>
|
||||
</body>
|
||||
</html>"}
|
||||
|
||||
usr << browse(jointext(output, ""),"window=editrights;size=900x650")
|
||||
|
||||
/datum/admins/proc/log_admin_rank_modification(adm_ckey, new_rank)
|
||||
if(CONFIG_GET(flag/admin_legacy_system))
|
||||
return
|
||||
|
||||
if(!usr.client)
|
||||
return
|
||||
|
||||
if (!check_rights(R_PERMISSIONS))
|
||||
return
|
||||
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return
|
||||
|
||||
if(!adm_ckey || !new_rank)
|
||||
return
|
||||
|
||||
adm_ckey = ckey(adm_ckey)
|
||||
|
||||
if(!adm_ckey)
|
||||
return
|
||||
|
||||
if(!istext(adm_ckey) || !istext(new_rank))
|
||||
return
|
||||
|
||||
var/datum/DBQuery/query_get_admin = SSdbcore.NewQuery("SELECT id FROM [format_table_name("admin")] WHERE ckey = '[adm_ckey]'")
|
||||
if(!query_get_admin.warn_execute())
|
||||
return
|
||||
|
||||
var/new_admin = 1
|
||||
var/admin_id
|
||||
while(query_get_admin.NextRow())
|
||||
new_admin = 0
|
||||
admin_id = text2num(query_get_admin.item[1])
|
||||
|
||||
if(new_admin)
|
||||
var/datum/DBQuery/query_add_admin = SSdbcore.NewQuery("INSERT INTO `[format_table_name("admin")]` (`id`, `ckey`, `rank`, `level`, `flags`) VALUES (null, '[adm_ckey]', '[new_rank]', -1, 0)")
|
||||
if(!query_add_admin.warn_execute())
|
||||
return
|
||||
var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO `[format_table_name("admin_log")]` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added new admin [adm_ckey] to rank [new_rank]');")
|
||||
if(!query_add_admin_log.warn_execute())
|
||||
return
|
||||
to_chat(usr, "<span class='adminnotice'>New admin added.</span>")
|
||||
else
|
||||
if(!isnull(admin_id) && isnum(admin_id))
|
||||
var/datum/DBQuery/query_change_admin = SSdbcore.NewQuery("UPDATE `[format_table_name("admin")]` SET rank = '[new_rank]' WHERE id = [admin_id]")
|
||||
if(!query_change_admin.warn_execute())
|
||||
return
|
||||
var/datum/DBQuery/query_change_admin_log = SSdbcore.NewQuery("INSERT INTO `[format_table_name("admin_log")]` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Edited the rank of [adm_ckey] to [new_rank]');")
|
||||
if(!query_change_admin_log.warn_execute())
|
||||
return
|
||||
to_chat(usr, "<span class='adminnnotice'>Admin rank changed.</span>")
|
||||
|
||||
|
||||
/datum/admins/proc/log_admin_permission_modification(adm_ckey, new_permission)
|
||||
if(CONFIG_GET(flag/admin_legacy_system))
|
||||
return
|
||||
if(!usr.client)
|
||||
return
|
||||
if(check_rights(R_PERMISSIONS))
|
||||
return
|
||||
|
||||
if(!SSdbcore.Connect())
|
||||
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
|
||||
return
|
||||
|
||||
if(!adm_ckey || !istext(adm_ckey) || !isnum(new_permission))
|
||||
return
|
||||
|
||||
var/datum/DBQuery/query_get_perms = SSdbcore.NewQuery("SELECT id, flags FROM [format_table_name("admin")] WHERE ckey = '[adm_ckey]'")
|
||||
if(!query_get_perms.warn_execute())
|
||||
return
|
||||
|
||||
var/admin_id
|
||||
while(query_get_perms.NextRow())
|
||||
admin_id = text2num(query_get_perms.item[1])
|
||||
|
||||
if(!admin_id)
|
||||
return
|
||||
|
||||
var/datum/DBQuery/query_change_perms = SSdbcore.NewQuery("UPDATE `[format_table_name("admin")]` SET flags = [new_permission] WHERE id = [admin_id]")
|
||||
if(!query_change_perms.warn_execute())
|
||||
return
|
||||
var/datum/DBQuery/query_change_perms_log = SSdbcore.NewQuery("INSERT INTO `[format_table_name("admin_log")]` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Edit permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]');")
|
||||
query_change_perms_log.warn_execute()
|
||||
@@ -31,6 +31,7 @@
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=tdomereset'>Reset Thunderdome to default state</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=set_name'>Rename Station Name</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=reset_name'>Reset Station Name</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=night_shift_set'>Set Night Shift Mode</A><BR>
|
||||
<BR>
|
||||
<B>Shuttles</B><BR>
|
||||
<BR>
|
||||
@@ -54,7 +55,7 @@
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=quickpower'>Power all SMES</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=tripleAI'>Triple AI mode (needs to be used in the lobby)</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=traitor_all'>Everyone is the traitor</A><BR>
|
||||
<A href='?src=\ref[src];[HrefToken()];secrets=ak47s'>AK-47s For Everyone!</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=ak47s'>AK-47s For Everyone!</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=guns'>Summon Guns</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=magic'>Summon Magic</A><BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];secrets=events'>Summon Events (Toggle)</A><BR>
|
||||
@@ -109,6 +110,7 @@
|
||||
|
||||
if("mentor_log")
|
||||
CitadelMentorLogSecret()
|
||||
|
||||
if("list_job_debug")
|
||||
var/dat = "<B>Job Debug info.</B><HR>"
|
||||
for(var/line in SSjob.job_debug)
|
||||
@@ -167,6 +169,23 @@
|
||||
log_admin("[key_name(usr)] renamed the station to \"[new_name]\".")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] renamed the station to: [new_name].</span>")
|
||||
priority_announce("[command_name()] has renamed the station to \"[new_name]\".")
|
||||
if("night_shift_set")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/val = alert(usr, "What do you want to set night shift to? This will override the automatic system until set to automatic again.", "On", "Off", "Automatic")
|
||||
switch(val)
|
||||
if("Automatic")
|
||||
if(CONFIG_GET(flag/enable_night_shifts))
|
||||
SSnightshift.can_fire = TRUE
|
||||
SSnightshift.fire()
|
||||
else
|
||||
SSnightshift.update_nightshift(FALSE, TRUE)
|
||||
if("On")
|
||||
SSnightshift.can_fire = FALSE
|
||||
SSnightshift.update_nightshift(TRUE, TRUE)
|
||||
if("Off")
|
||||
SSnightshift.can_fire = FALSE
|
||||
SSnightshift.update_nightshift(FALSE, TRUE)
|
||||
|
||||
if("reset_name")
|
||||
if(!check_rights(R_ADMIN))
|
||||
@@ -466,7 +485,7 @@
|
||||
message_admins("[key_name_admin(usr)] activated AK-47s for Everyone!")
|
||||
usr.client.ak47s()
|
||||
sound_to_playing_players('sound/misc/ak47s.ogg')
|
||||
|
||||
|
||||
if("guns")
|
||||
if(!check_rights(R_FUN))
|
||||
return
|
||||
@@ -613,13 +632,13 @@
|
||||
var/list/new_movement = list()
|
||||
for(var/i in 1 to movement_keys.len)
|
||||
var/key = movement_keys[i]
|
||||
|
||||
|
||||
var/msg = "Please input the new movement direction when the user presses [key]. Ex. northeast"
|
||||
var/title = "New direction for [key]"
|
||||
var/new_direction = text2dir(input(usr, msg, title) as text|null)
|
||||
if(!new_direction)
|
||||
new_direction = movement_keys[key]
|
||||
|
||||
|
||||
new_movement[key] = new_direction
|
||||
SSinput.movement_keys = new_movement
|
||||
message_admins("[key_name_admin(usr)] has configured all movement directions.")
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
if(!CheckAdminHref(href, href_list))
|
||||
return
|
||||
|
||||
citaTopic(href, href_list) //CITADEL EDIT, MENTORS
|
||||
|
||||
if(href_list["ahelp"])
|
||||
if(!check_rights(R_ADMIN, TRUE))
|
||||
return
|
||||
@@ -271,50 +273,6 @@
|
||||
return
|
||||
create_message("note", banckey, null, banreason, null, null, 0, 0)
|
||||
|
||||
else if(href_list["mentor"])
|
||||
if(!check_rights(R_ADMIN)) return
|
||||
|
||||
var/mob/M = locate(href_list["mentor"])
|
||||
if(!ismob(M))
|
||||
to_chat(usr, "<span class='danger'>this can be only used on instances of type /mob!</span>")
|
||||
return
|
||||
|
||||
if(!M.client)
|
||||
to_chat(usr, "<span class='danger'>No client.</span>")
|
||||
return
|
||||
|
||||
log_admin("[key_name(usr)] has granted [key_name(M)] mentor access")
|
||||
message_admins("<span class='adminnotice'> [key_name_admin(usr)] has granted [key_name_admin(M)] mentor access.</span>")
|
||||
|
||||
var/datum/DBQuery/query_add_mentors = SSdbcore.NewQuery("INSERT INTO [format_table_name("mentor")] (ckey) VALUES ('[M.client.ckey]')")
|
||||
if(!query_add_mentors.Execute())
|
||||
var/err = query_add_mentors.ErrorMsg()
|
||||
log_game("SQL ERROR during adding new mentor. Error : \[[err]\]\n")
|
||||
load_mentors()
|
||||
M.verbs += /client/proc/cmd_mentor_say
|
||||
M.verbs += /client/proc/show_mentor_memo
|
||||
to_chat(M, "<span class='adminnotice'> You've been granted mentor access! Help people who send mentor-pms.</span>")
|
||||
|
||||
else if(href_list["removementor"])
|
||||
if(!check_rights(R_ADMIN)) return
|
||||
|
||||
var/mob/living/carbon/human/M = locate(href_list["removementor"])
|
||||
if(!ismob(M))
|
||||
usr << "this can be only used on instances of type /mob"
|
||||
return
|
||||
|
||||
log_admin("[key_name(usr)] has removed mentor access from [key_name(M)]")
|
||||
message_admins("<span class='adminnotice'> [key_name_admin(usr)] has removed mentor access from [key_name_admin(M)].</span>")
|
||||
|
||||
var/datum/DBQuery/query_remove_mentors = SSdbcore.NewQuery("DELETE FROM [format_table_name("mentor")] WHERE ckey = '[M.client.ckey]'")
|
||||
if(!query_remove_mentors.Execute())
|
||||
var/err = query_remove_mentors.ErrorMsg()
|
||||
log_game("SQL ERROR during removing mentor. Error : \[[err]\]\n")
|
||||
load_mentors()
|
||||
to_chat(M, "<span class='adminnotice'>Your mentor access has been revoked.</span>")
|
||||
M.verbs -= /client/proc/cmd_mentor_say
|
||||
M.verbs -= /client/proc/show_mentor_memo
|
||||
|
||||
else if(href_list["editrights"])
|
||||
edit_rights_topic(href_list)
|
||||
|
||||
@@ -916,12 +874,6 @@
|
||||
else
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=abductor;jobban4=[REF(M)]'>Abductor</a></td>"
|
||||
|
||||
//Borer
|
||||
if(jobban_isbanned(M, "borer") || isbanned_dept)
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=borer;jobban4=[REF(M)]'><font color=red>Borer</font></a></td>"
|
||||
else
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=borer;jobban4=[REF(M)]'>Borer</a></td>"
|
||||
|
||||
//Alien
|
||||
if(jobban_isbanned(M, ROLE_ALIEN) || isbanned_dept)
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=alien;jobban4=[REF(M)]'><font color=red>Alien</font></a></td>"
|
||||
@@ -1709,7 +1661,7 @@
|
||||
var/mob/living/L = M
|
||||
var/status
|
||||
switch (M.stat)
|
||||
if (CONSCIOUS)
|
||||
if(CONSCIOUS)
|
||||
status = "Alive"
|
||||
if(SOFT_CRIT)
|
||||
status = "<font color='orange'><b>Dying</b></font>"
|
||||
|
||||
@@ -235,42 +235,42 @@
|
||||
|
||||
if(ispath(type, /mob))
|
||||
for(var/mob/d in location)
|
||||
if(typecache[d.type])
|
||||
if(typecache[d.type] && d.can_vv_get())
|
||||
out += d
|
||||
CHECK_TICK
|
||||
|
||||
else if(ispath(type, /turf))
|
||||
for(var/turf/d in location)
|
||||
if(typecache[d.type])
|
||||
if(typecache[d.type] && d.can_vv_get())
|
||||
out += d
|
||||
CHECK_TICK
|
||||
|
||||
else if(ispath(type, /obj))
|
||||
for(var/obj/d in location)
|
||||
if(typecache[d.type])
|
||||
if(typecache[d.type] && d.can_vv_get())
|
||||
out += d
|
||||
CHECK_TICK
|
||||
|
||||
else if(ispath(type, /area))
|
||||
for(var/area/d in location)
|
||||
if(typecache[d.type])
|
||||
if(typecache[d.type] && d.can_vv_get())
|
||||
out += d
|
||||
CHECK_TICK
|
||||
|
||||
else if(ispath(type, /atom))
|
||||
for(var/atom/d in location)
|
||||
if(typecache[d.type])
|
||||
if(typecache[d.type] && d.can_vv_get())
|
||||
out += d
|
||||
CHECK_TICK
|
||||
else if(ispath(type, /datum))
|
||||
if(location == world) //snowflake for byond shortcut
|
||||
for(var/datum/d) //stupid byond trick to have it not return atoms to make this less laggy
|
||||
if(typecache[d.type])
|
||||
if(typecache[d.type] && d.can_vv_get())
|
||||
out += d
|
||||
CHECK_TICK
|
||||
else
|
||||
for(var/datum/d in location)
|
||||
if(typecache[d.type])
|
||||
if(typecache[d.type] && d.can_vv_get())
|
||||
out += d
|
||||
CHECK_TICK
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
admin_sound.status = SOUND_STREAM
|
||||
admin_sound.volume = vol
|
||||
|
||||
var/res = alert(usr, "Show the title of this song to the players?",, "No", "Yes", "Cancel")
|
||||
var/res = alert(usr, "Show the title of this song to the players?",, "Yes","No", "Cancel")
|
||||
switch(res)
|
||||
if("Yes")
|
||||
to_chat(world, "<span class='boldannounce'>An admin played: [S]</span>")
|
||||
|
||||
@@ -242,14 +242,17 @@
|
||||
return TRUE
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/update_icon()
|
||||
var/power_charge = get_clockwork_power()
|
||||
if(GLOB.ratvar_awakens)
|
||||
alpha = 255
|
||||
var/power_charge = get_clockwork_power()
|
||||
alpha = min(initial(alpha) + power_charge * 0.02, 255)
|
||||
if(!power_charge)
|
||||
set_light(0)
|
||||
else
|
||||
set_light(max(alpha * 0.02, 1.4), max(alpha * 0.01, 0.1))
|
||||
alpha = min(CEILING(initial(alpha) + power_charge * 0.02, 35), 255)
|
||||
var/r = alpha * 0.02
|
||||
var/p = max(alpha * 0.01, 0.1)
|
||||
if(!power_charge && light_range != 0)
|
||||
set_light(0)
|
||||
else if(r != light_range || p != light_power)
|
||||
set_light(r, p)
|
||||
|
||||
//Vitality Matrix: Drains health from non-servants to heal or even revive servants.
|
||||
/obj/effect/clockwork/sigil/vitality
|
||||
|
||||
@@ -27,14 +27,13 @@
|
||||
/datum/antagonist/disease/apply_innate_effects(mob/living/mob_override)
|
||||
if(!istype(owner.current, /mob/camera/disease))
|
||||
var/turf/T = get_turf(owner.current)
|
||||
T = T ? T : locate(1, 1, 1)
|
||||
T = T ? T : SSmapping.get_station_center()
|
||||
var/mob/camera/disease/D = new /mob/camera/disease(T)
|
||||
owner.transfer_to(D)
|
||||
|
||||
/datum/antagonist/disease/admin_add(datum/mind/new_owner,mob/admin)
|
||||
..()
|
||||
var/mob/camera/disease/D = new_owner.current
|
||||
D.infect_patient_zero()
|
||||
D.pick_name()
|
||||
|
||||
/datum/antagonist/disease/roundend_report()
|
||||
|
||||
@@ -17,11 +17,7 @@
|
||||
|
||||
var/mob/dead/observer/selected = pick_n_take(candidates)
|
||||
|
||||
var/mob/camera/disease/virus = new /mob/camera/disease(locate(1, 1, 1))
|
||||
if(!virus.infect_patient_zero())
|
||||
message_admins("Event attempted to spawn a sentient disease, but infection of patient zero failed.")
|
||||
qdel(virus)
|
||||
return WAITING_FOR_SOMETHING
|
||||
var/mob/camera/disease/virus = new /mob/camera/disease(SSmapping.get_station_center())
|
||||
virus.key = selected.key
|
||||
INVOKE_ASYNC(virus, /mob/camera/disease/proc/pick_name)
|
||||
message_admins("[key_name_admin(virus)] has been made into a sentient disease by an event.")
|
||||
|
||||
@@ -12,14 +12,19 @@ the new instance inside the host to be updated to the template's stats.
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "marker"
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
move_on_shuttle = 1
|
||||
move_on_shuttle = FALSE
|
||||
see_in_dark = 8
|
||||
invisibility = INVISIBILITY_OBSERVER
|
||||
layer = BELOW_MOB_LAYER
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
sight = SEE_SELF
|
||||
sight = SEE_SELF|SEE_THRU
|
||||
initial_language_holder = /datum/language_holder/empty
|
||||
|
||||
var/freemove = TRUE
|
||||
var/freemove_end = 0
|
||||
var/const/freemove_time = 1200
|
||||
var/freemove_end_timerid
|
||||
|
||||
var/datum/action/innate/disease_adapt/adaptation_menu_action
|
||||
var/datum/disease_ability/examining_ability
|
||||
var/datum/browser/browser
|
||||
@@ -45,19 +50,12 @@ the new instance inside the host to be updated to the template's stats.
|
||||
|
||||
/mob/camera/disease/Initialize(mapload)
|
||||
.= ..()
|
||||
adaptation_menu_action = new /datum/action/innate/disease_adapt()
|
||||
adaptation_menu_action.Grant(src)
|
||||
|
||||
disease_instances = list()
|
||||
hosts = list()
|
||||
|
||||
purchased_abilities = list()
|
||||
unpurchased_abilities = list()
|
||||
for(var/V in GLOB.disease_ability_singletons)
|
||||
unpurchased_abilities[V] = TRUE
|
||||
var/datum/disease_ability/A = V
|
||||
if(A.start_with && A.CanBuy(src))
|
||||
A.Buy(src, TRUE, FALSE)
|
||||
|
||||
disease_template = new /datum/disease/advance/sentient_disease()
|
||||
disease_template.overmind = src
|
||||
@@ -69,29 +67,45 @@ the new instance inside the host to be updated to the template's stats.
|
||||
|
||||
browser = new /datum/browser(src, "disease_menu", "Adaptation Menu", 1000, 770, src)
|
||||
|
||||
freemove_end = world.time + freemove_time
|
||||
freemove_end_timerid = addtimer(CALLBACK(src, .proc/infect_random_patient_zero), freemove_time, TIMER_STOPPABLE)
|
||||
|
||||
/mob/camera/disease/Destroy()
|
||||
. = ..()
|
||||
QDEL_NULL(adaptation_menu_action)
|
||||
for(var/V in GLOB.sentient_disease_instances)
|
||||
var/datum/disease/advance/sentient_disease/S = V
|
||||
if(S.overmind == src)
|
||||
S.overmind = null
|
||||
|
||||
/mob/camera/disease/Login()
|
||||
..()
|
||||
if(freemove)
|
||||
to_chat(src, "<span class='warning'>You have [round((freemove_end - world.time)/10)] seconds to select your first host. Click on a human to select your host.</span>")
|
||||
|
||||
|
||||
/mob/camera/disease/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
stat("Adaptation Points: [points]/[total_points]")
|
||||
stat("Hosts: [disease_instances.len]")
|
||||
var/adapt_ready = next_adaptation_time - world.time
|
||||
if(adapt_ready > 0)
|
||||
stat("Adaptation Ready: [round(adapt_ready/10, 0.1)]s")
|
||||
if(freemove)
|
||||
stat("Host Selection Time: [round((freemove_end - world.time)/10)]s")
|
||||
else
|
||||
stat("Adaptation Points: [points]/[total_points]")
|
||||
stat("Hosts: [disease_instances.len]")
|
||||
var/adapt_ready = next_adaptation_time - world.time
|
||||
if(adapt_ready > 0)
|
||||
stat("Adaptation Ready: [round(adapt_ready/10, 0.1)]s")
|
||||
|
||||
/mob/camera/disease/say(message)
|
||||
return
|
||||
|
||||
/mob/camera/disease/Move(NewLoc, Dir = 0)
|
||||
if(world.time > (last_move_tick + move_delay))
|
||||
follow_next(Dir & NORTHWEST)
|
||||
last_move_tick = world.time
|
||||
if(freemove)
|
||||
forceMove(NewLoc)
|
||||
else
|
||||
if(world.time > (last_move_tick + move_delay))
|
||||
follow_next(Dir & NORTHWEST)
|
||||
last_move_tick = world.time
|
||||
|
||||
/mob/camera/disease/mind_initialize()
|
||||
. = ..()
|
||||
@@ -122,22 +136,56 @@ the new instance inside the host to be updated to the template's stats.
|
||||
if(A)
|
||||
A.disease_name = set_name
|
||||
|
||||
/mob/camera/disease/proc/infect_patient_zero()
|
||||
var/list/possible_hosts = list()
|
||||
var/datum/disease/advance/sentient_disease/V = disease_template.Copy()
|
||||
for(var/mob/living/carbon/human/H in GLOB.carbon_list)
|
||||
if((H.stat != DEAD) && H.CanContractDisease(V))
|
||||
possible_hosts += H
|
||||
if(!possible_hosts.len)
|
||||
/mob/camera/disease/proc/infect_random_patient_zero(del_on_fail = TRUE)
|
||||
if(!freemove)
|
||||
return FALSE
|
||||
var/mob/living/carbon/human/H = pick(possible_hosts)
|
||||
if(H.ForceContractDisease(V, FALSE, TRUE))
|
||||
return TRUE
|
||||
var/list/possible_hosts = list()
|
||||
var/list/afk_possible_hosts = list()
|
||||
for(var/mob/living/carbon/human/H in GLOB.carbon_list)
|
||||
var/turf/T = get_turf(H)
|
||||
if((H.stat != DEAD) && T && is_station_level(T.z) && H.CanContractDisease(disease_template))
|
||||
if(H.client && !H.client.is_afk())
|
||||
possible_hosts += H
|
||||
else
|
||||
afk_possible_hosts += H
|
||||
|
||||
shuffle_inplace(possible_hosts)
|
||||
shuffle_inplace(afk_possible_hosts)
|
||||
possible_hosts += afk_possible_hosts //ideally we want a not-afk person, but we will settle for an afk one if there are no others (mostly for testing)
|
||||
|
||||
while(possible_hosts.len)
|
||||
var/mob/living/carbon/human/target = possible_hosts[1]
|
||||
if(force_infect(target))
|
||||
return TRUE
|
||||
possible_hosts.Cut(1, 2)
|
||||
|
||||
if(del_on_fail)
|
||||
to_chat(src, "<span class=userdanger'>No hosts were available for your disease to infect.</span>")
|
||||
qdel(src)
|
||||
return FALSE
|
||||
|
||||
/mob/camera/disease/proc/force_infect(mob/living/L)
|
||||
var/datum/disease/advance/sentient_disease/V = disease_template.Copy()
|
||||
return L.ForceContractDisease(V, FALSE, TRUE)
|
||||
var/result = L.ForceContractDisease(V, FALSE, TRUE)
|
||||
if(result && freemove)
|
||||
end_freemove()
|
||||
return result
|
||||
|
||||
/mob/camera/disease/proc/end_freemove()
|
||||
if(!freemove)
|
||||
return
|
||||
freemove = FALSE
|
||||
move_on_shuttle = TRUE
|
||||
adaptation_menu_action = new /datum/action/innate/disease_adapt()
|
||||
adaptation_menu_action.Grant(src)
|
||||
for(var/V in GLOB.disease_ability_singletons)
|
||||
unpurchased_abilities[V] = TRUE
|
||||
var/datum/disease_ability/A = V
|
||||
if(A.start_with && A.CanBuy(src))
|
||||
A.Buy(src, TRUE, FALSE)
|
||||
if(freemove_end_timerid)
|
||||
deltimer(freemove_end_timerid)
|
||||
sight = SEE_SELF
|
||||
|
||||
/mob/camera/disease/proc/add_infection(datum/disease/advance/sentient_disease/V)
|
||||
disease_instances += V
|
||||
@@ -214,6 +262,18 @@ the new instance inside the host to be updated to the template's stats.
|
||||
else
|
||||
..()
|
||||
|
||||
/mob/camera/disease/ClickOn(var/atom/A, params)
|
||||
if(freemove && ishuman(A))
|
||||
var/mob/living/carbon/human/H = A
|
||||
if(alert(src, "Select [H.name] as your initial host?", "Select Host", "Yes", "No") != "Yes")
|
||||
return
|
||||
if(!freemove)
|
||||
return
|
||||
if(QDELETED(H) || !force_infect(H))
|
||||
to_chat(src, "<span class='warning'>[H ? H.name : "Host"] cannot be infected.</span>")
|
||||
else
|
||||
..()
|
||||
|
||||
/mob/camera/disease/proc/adapt_cooldown()
|
||||
to_chat(src, "<span class='notice'>You have altered your genetic structure. You will be unable to adapt again for [adaptation_cooldown/10] seconds.</span>")
|
||||
next_adaptation_time = world.time + adaptation_cooldown
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
//Admin-spawn or random event
|
||||
|
||||
#define INVISIBILITY_REVENANT 50
|
||||
#define REVENANT_NAME_FILE "revenant_names.json"
|
||||
|
||||
/mob/living/simple_animal/revenant
|
||||
name = "\a Revenant"
|
||||
@@ -70,6 +71,15 @@
|
||||
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/overload(null))
|
||||
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/blight(null))
|
||||
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction(null))
|
||||
random_revenant_name()
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/random_revenant_name()
|
||||
var/built_name = ""
|
||||
built_name += pick(strings(REVENANT_NAME_FILE, "spirit_type"))
|
||||
built_name += " of "
|
||||
built_name += pick(strings(REVENANT_NAME_FILE, "adverb"))
|
||||
built_name += pick(strings(REVENANT_NAME_FILE, "theme"))
|
||||
name = built_name
|
||||
|
||||
/mob/living/simple_animal/revenant/Login()
|
||||
..()
|
||||
|
||||
@@ -98,11 +98,11 @@
|
||||
var/list/new_overlay_types = tile_graphic()
|
||||
var/list/atmos_overlay_types = src.atmos_overlay_types // Cache for free performance
|
||||
|
||||
/*#if DM_VERSION >= 513
|
||||
#if DM_VERSION >= 513
|
||||
#warning 512 is stable now for sure, remove the old code
|
||||
#endif*/
|
||||
#endif
|
||||
|
||||
/*#if DM_VERSION >= 512
|
||||
#if DM_VERSION >= 512
|
||||
if (atmos_overlay_types)
|
||||
for(var/overlay in atmos_overlay_types-new_overlay_types) //doesn't remove overlays that would only be added
|
||||
vars["vis_contents"] -= overlay
|
||||
@@ -112,7 +112,7 @@
|
||||
vars["vis_contents"] += new_overlay_types - atmos_overlay_types //don't add overlays that already exist
|
||||
else
|
||||
vars["vis_contents"] += new_overlay_types
|
||||
#else*/
|
||||
#else
|
||||
if (atmos_overlay_types)
|
||||
for(var/overlay in atmos_overlay_types-new_overlay_types) //doesn't remove overlays that would only be added
|
||||
cut_overlay(overlay)
|
||||
@@ -122,7 +122,7 @@
|
||||
add_overlay(new_overlay_types - atmos_overlay_types) //don't add overlays that already exist
|
||||
else
|
||||
add_overlay(new_overlay_types)
|
||||
//#endif
|
||||
#endif
|
||||
|
||||
UNSETEMPTY(new_overlay_types)
|
||||
src.atmos_overlay_types = new_overlay_types
|
||||
|
||||
@@ -62,7 +62,6 @@ It's like a regular ol' straight pipe, but you can turn it on and off.
|
||||
investigate_log("Valve, [src.name], was manipiulated by [key_name(usr)] at [x], [y], [z], [A]", "atmos")
|
||||
message_admins("Valve, [src.name], was manipulated by [ADMIN_LOOKUPFLW(user)] at [ADMIN_COORDJMP(T)], [A]")
|
||||
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/valve/digital // can be controlled by AI
|
||||
name = "digital valve"
|
||||
desc = "A digitally controlled valve."
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
continue // i'd be right happy to
|
||||
meme_pack_data[P.group]["packs"] += list(list(
|
||||
"name" = P.name,
|
||||
"cost" = P.cost * 2, //displays twice the normal cost
|
||||
"cost" = P.cost,
|
||||
"id" = pack
|
||||
))
|
||||
|
||||
@@ -120,12 +120,12 @@
|
||||
CHECK_TICK
|
||||
if(empty_turfs && empty_turfs.len)
|
||||
var/LZ = empty_turfs[rand(empty_turfs.len-1)]
|
||||
SSshuttle.points -= SO.pack.cost * 2
|
||||
SSshuttle.points -= SO.pack.cost
|
||||
new /obj/effect/DPtarget(LZ, SO, podID)
|
||||
. = TRUE
|
||||
update_icon()
|
||||
else
|
||||
if(SO.pack.cost * (1.2*MAX_EMAG_ROCKETS) <= SSshuttle.points) // bulk discount :^)
|
||||
if(SO.pack.cost * (0.72*MAX_EMAG_ROCKETS) <= SSshuttle.points) // bulk discount :^)
|
||||
landingzone = locate(pick(GLOB.the_station_areas)) in GLOB.sortedAreas
|
||||
for(var/turf/open/floor/T in landingzone.contents)
|
||||
if(is_blocked_turf(T))
|
||||
|
||||
@@ -988,8 +988,9 @@
|
||||
/obj/item/reagent_containers/pill/insulin,
|
||||
/obj/item/stack/medical/gauze,
|
||||
/obj/item/storage/box/beakers,
|
||||
/obj/item/storage/box/medsprays,
|
||||
/obj/item/storage/box/syringes,
|
||||
/obj/item/storage/box/bodybags)
|
||||
/obj/item/storage/box/bodybags)
|
||||
crate_name = "medical supplies crate"
|
||||
|
||||
/datum/supply_pack/medical/vending
|
||||
@@ -1983,4 +1984,4 @@
|
||||
/obj/item/toy/redbutton,
|
||||
/obj/item/toy/eightball,
|
||||
/obj/item/vending_refill/donksoft)
|
||||
crate_name = "toy crate"
|
||||
crate_name = "toy crate"
|
||||
|
||||
@@ -97,7 +97,7 @@ You can set verify to TRUE if you want send() to sleep until the client has the
|
||||
if(!verify) // Can't access the asset cache browser, rip.
|
||||
client.cache += unreceived
|
||||
return 1
|
||||
|
||||
|
||||
client.sending |= unreceived
|
||||
var/job = ++client.last_asset_job
|
||||
|
||||
@@ -135,7 +135,7 @@ You can set verify to TRUE if you want send() to sleep until the client has the
|
||||
else
|
||||
concurrent_tracker++
|
||||
send_asset(client, file, verify=FALSE)
|
||||
|
||||
|
||||
stoplag(0) //queuing calls like this too quickly can cause issues in some client versions
|
||||
|
||||
//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up.
|
||||
@@ -350,6 +350,11 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
"browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css',
|
||||
)
|
||||
|
||||
/datum/asset/simple/permissions
|
||||
assets = list(
|
||||
"padlock.png" = 'html/padlock.png'
|
||||
)
|
||||
|
||||
//this exists purely to avoid meta by pre-loading all language icons.
|
||||
/datum/asset/language/register()
|
||||
for(var/path in typesof(/datum/language))
|
||||
|
||||
@@ -87,7 +87,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
if(href_list["priv_msg"])
|
||||
cmd_admin_pm(href_list["priv_msg"],null)
|
||||
return
|
||||
|
||||
// Mentor PM
|
||||
if(href_list["mentor_msg"])
|
||||
if(CONFIG_GET(flag.mentors_mobname_only))
|
||||
@@ -158,6 +157,11 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
GLOBAL_LIST_EMPTY(external_rsc_urls)
|
||||
#endif
|
||||
|
||||
/client/can_vv_get(var_name)
|
||||
return var_name != NAMEOF(src, holder) && ..()
|
||||
|
||||
/client/vv_edit_var(var_name, var_value)
|
||||
return var_name != NAMEOF(src, holder) && ..()
|
||||
|
||||
/client/New(TopicData)
|
||||
var/tdata = TopicData //save this for later use
|
||||
@@ -239,16 +243,23 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
|
||||
|
||||
. = ..() //calls mob.Login()
|
||||
#if DM_VERSION >= 512
|
||||
if (num2text(byond_build) in GLOB.blacklisted_builds)
|
||||
log_access("Failed login: blacklisted byond version")
|
||||
to_chat(src, "<span class='userdanger'>Your version of byond is blacklisted.</span>")
|
||||
to_chat(src, "<span class='danger'>Byond build [byond_build] ([byond_version].[byond_build]) has been blacklisted for the following reason: [GLOB.blacklisted_builds[num2text(byond_build)]].</span>")
|
||||
to_chat(src, "<span class='danger'>Please download a new version of byond. if [byond_build] is the latest, you can go to http://www.byond.com/download/build/ to download other versions.</span>")
|
||||
if(connecting_admin)
|
||||
to_chat(src, "As an admin, you are being allowed to continue using this version, but please consider changing byond versions")
|
||||
else
|
||||
if (byond_version >= 512)
|
||||
if (!byond_build || byond_build < 1386)
|
||||
message_admins("<span class='adminnotice'>[key_name(src)] has been detected as spoofing their byond version. Connection rejected.</span>")
|
||||
add_system_note("Spoofed-Byond-Version", "Detected as using a spoofed byond version.")
|
||||
log_access("Failed Login: [key] - Spoofed byond version")
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
if (num2text(byond_build) in GLOB.blacklisted_builds)
|
||||
log_access("Failed login: [key] - blacklisted byond version")
|
||||
to_chat(src, "<span class='userdanger'>Your version of byond is blacklisted.</span>")
|
||||
to_chat(src, "<span class='danger'>Byond build [byond_build] ([byond_version].[byond_build]) has been blacklisted for the following reason: [GLOB.blacklisted_builds[num2text(byond_build)]].</span>")
|
||||
to_chat(src, "<span class='danger'>Please download a new version of byond. if [byond_build] is the latest, you can go to http://www.byond.com/download/build/ to download other versions.</span>")
|
||||
if(connecting_admin)
|
||||
to_chat(src, "As an admin, you are being allowed to continue using this version, but please consider changing byond versions")
|
||||
else
|
||||
qdel(src)
|
||||
return
|
||||
#endif
|
||||
if(SSinput.initialized)
|
||||
set_macros()
|
||||
@@ -409,21 +420,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
|
||||
"Someone come hold me :(",\
|
||||
"I need someone on me :(",\
|
||||
"What happened? Where has everyone gone?",\
|
||||
"Forever alone :(",\
|
||||
"My nipples are so stiff, but Zelda ain't here. :(",\
|
||||
"Leon senpai, play more Spessmans. :(",\
|
||||
"If only Serdy were here...",\
|
||||
"Panic bunker can't keep my love for you out.",\
|
||||
"Cebu needs to Awoo herself back into my heart.",\
|
||||
"I don't even have a Turry to snuggle viciously here.",\
|
||||
"MOM, WHERE ARE YOU??? D:",\
|
||||
"It's a beautiful day outside. Birds are singing, flowers are blooming. On days like this...kids like you...SHOULD BE BURNING IN HELL.",\
|
||||
"Sometimes when I have sex, I think about putting an entire peanut butter and jelly sandwich in the VCR.",\
|
||||
"Oh good, no-one around to watch me lick Goofball's nipples. :D",\
|
||||
"I've replaced Beepsky with a fidget spinner, glory be autism abuse.",\
|
||||
"i shure hop dere are no PRED arund!!!!",\
|
||||
"NO PRED CAN eVER CATCH MI",\
|
||||
"help, the clown is honking his horn in front of dorms and its interrupting everyones erp"\
|
||||
"Forever alone :("\
|
||||
)
|
||||
|
||||
send2irc("Server", "[cheesy_message] (No admins online)")
|
||||
@@ -623,10 +620,13 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
|
||||
to_chat(src, {"<a href="byond://[url]?token=[token]">You will be automatically taken to the game, if not, click here to be taken manually</a>"})
|
||||
|
||||
/client/proc/note_randomizer_user()
|
||||
var/const/adminckey = "CID-Error"
|
||||
add_system_note("CID-Error", "Detected as using a cid randomizer.")
|
||||
|
||||
/client/proc/add_system_note(system_ckey, message)
|
||||
var/sql_system_ckey = sanitizeSQL(system_ckey)
|
||||
var/sql_ckey = sanitizeSQL(ckey)
|
||||
//check to see if we noted them in the last day.
|
||||
var/datum/DBQuery/query_get_notes = SSdbcore.NewQuery("SELECT id FROM [format_table_name("messages")] WHERE type = 'note' AND targetckey = '[sql_ckey]' AND adminckey = '[adminckey]' AND timestamp + INTERVAL 1 DAY < NOW() AND deleted = 0")
|
||||
var/datum/DBQuery/query_get_notes = SSdbcore.NewQuery("SELECT id FROM [format_table_name("messages")] WHERE type = 'note' AND targetckey = '[sql_ckey]' AND adminckey = '[sql_system_ckey]' AND timestamp + INTERVAL 1 DAY < NOW() AND deleted = 0")
|
||||
if(!query_get_notes.Execute())
|
||||
return
|
||||
if(query_get_notes.NextRow())
|
||||
@@ -636,9 +636,9 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
|
||||
if(!query_get_notes.Execute())
|
||||
return
|
||||
if(query_get_notes.NextRow())
|
||||
if (query_get_notes.item[1] == adminckey)
|
||||
if (query_get_notes.item[1] == system_ckey)
|
||||
return
|
||||
create_message("note", sql_ckey, adminckey, "Detected as using a cid randomizer.", null, null, 0, 0)
|
||||
create_message("note", ckey, system_ckey, message, null, null, 0, 0)
|
||||
|
||||
|
||||
/client/proc/check_ip_intel()
|
||||
@@ -735,7 +735,6 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
|
||||
if(!prefs.widescreenpref && new_size == CONFIG_GET(string/default_view))
|
||||
new_size = "15x15"
|
||||
//END OF CIT CHANGES
|
||||
|
||||
view = new_size
|
||||
apply_clickcatcher()
|
||||
if (isliving(mob))
|
||||
@@ -754,4 +753,4 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
|
||||
|
||||
/client/proc/AnnouncePR(announcement)
|
||||
if(prefs && prefs.chat_toggles & CHAT_PULLR)
|
||||
to_chat(src, announcement)
|
||||
to_chat(src, announcement)
|
||||
|
||||
@@ -250,20 +250,6 @@ TOGGLE_CHECKBOX(/datum/verbs/menu/Settings, listen_ooc)()
|
||||
/datum/verbs/menu/Settings/listen_ooc/Get_checked(client/C)
|
||||
return C.prefs.chat_toggles & CHAT_OOC
|
||||
|
||||
TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Sound, togglehoundsleeper)()
|
||||
set name = "Allow/Deny Hound Sleeper"
|
||||
set category = "Preferences"
|
||||
set desc = "Allow MediHound Sleepers"
|
||||
usr.client.prefs.toggles ^= MEDIHOUND_SLEEPER
|
||||
usr.client.prefs.save_preferences()
|
||||
if(usr.client.prefs.toggles & MEDIHOUND_SLEEPER)
|
||||
to_chat(usr, "You will now allow MediHounds to place you in their sleeper.")
|
||||
else
|
||||
to_chat(usr, "You will no longer allow MediHounds to place you in their sleeper.")
|
||||
SSblackbox.record_feedback("nested tally", "preferences_verb", 1, list("Toggle MediHound Sleeper", "[usr.client.prefs.toggles & MEDIHOUND_SLEEPER ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
/datum/verbs/menu/Settings/Sound/togglehoundsleeper/Get_checked(client/C)
|
||||
return C.prefs.toggles & MEDIHOUND_SLEEPER
|
||||
|
||||
|
||||
GLOBAL_LIST_INIT(ghost_forms, list("ghost","ghostking","ghostian2","skeleghost","ghost_red","ghost_black", \
|
||||
"ghost_blue","ghost_yellow","ghost_green","ghost_pink", \
|
||||
@@ -429,4 +415,3 @@ GLOBAL_LIST_INIT(ghost_orbits, list(GHOST_ORBIT_CIRCLE,GHOST_ORBIT_TRIANGLE,GHOS
|
||||
prefs.save_preferences()
|
||||
to_chat(src, "You will [(prefs.chat_toggles & CHAT_PRAYER) ? "now" : "no longer"] see prayerchat.")
|
||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Prayer Visibility", "[prefs.chat_toggles & CHAT_PRAYER ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
@@ -9,6 +9,12 @@
|
||||
earliest_start = 30 MINUTES
|
||||
gamemode_blacklist = list("nuclear")
|
||||
|
||||
/datum/round_event_control/pirates/preRunEvent()
|
||||
if (!SSmapping.empty_space)
|
||||
return EVENT_CANT_RUN
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/round_event/pirates
|
||||
startWhen = 60 //2 minutes to answer
|
||||
var/datum/comm_message/threat
|
||||
|
||||
@@ -23,9 +23,6 @@
|
||||
growing_icon = 'icons/obj/hydroponics/growing_mushrooms.dmi'
|
||||
reagents_add = list("morphine" = 0.35, "charcoal" = 0.35, "nutriment" = 0)
|
||||
|
||||
|
||||
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/grown/mushroom/reishi
|
||||
seed = /obj/item/seeds/reishi
|
||||
name = "reishi"
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
var/blood_type = null
|
||||
var/list/features = null
|
||||
var/factions = null
|
||||
var/list/traits = null
|
||||
var/contains_sample = 0
|
||||
|
||||
/obj/item/seeds/replicapod/attackby(obj/item/W, mob/user, params)
|
||||
@@ -34,6 +35,7 @@
|
||||
blood_type = bloodSample.data["blood_type"]
|
||||
features = bloodSample.data["features"]
|
||||
factions = bloodSample.data["factions"]
|
||||
traits = bloodSample.data["traits"]
|
||||
W.reagents.clear_reagents()
|
||||
to_chat(user, "<span class='notice'>You inject the contents of the syringe into the seeds.</span>")
|
||||
contains_sample = 1
|
||||
@@ -99,6 +101,8 @@
|
||||
podman.faction |= factions
|
||||
if(!features["mcolor"])
|
||||
features["mcolor"] = "#59CE00"
|
||||
for(var/V in traits)
|
||||
new V(podman)
|
||||
podman.hardset_dna(null,null,podman.real_name,blood_type, new /datum/species/pod,features)//Discard SE's and UI's, podman cloning is inaccurate, and always make them a podman
|
||||
podman.set_cloned_appearance()
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/datum/language/mushroom
|
||||
name = "Mushroom"
|
||||
desc = "A language that consists of the sound of periodic gusts of spore-filled air being released."
|
||||
speech_verb = "puffs"
|
||||
ask_verb = "puffs inquisitively"
|
||||
exclaim_verb = "poofs loudly"
|
||||
whisper_verb = "puffs quietly"
|
||||
key = "y"
|
||||
sentence_chance = 0
|
||||
default_priority = 80
|
||||
syllables = list("poof", "pff", "pFfF", "piff", "puff", "pooof", "pfffff", "piffpiff", "puffpuff", "poofpoof", "pifpafpofpuf")
|
||||
@@ -160,3 +160,4 @@ GLOBAL_LIST_EMPTY(z_is_planet)
|
||||
. = ..()
|
||||
var/turf/T = get_turf(src)
|
||||
GLOB.z_is_planet["[T.z]"] = TRUE
|
||||
|
||||
|
||||
@@ -125,4 +125,4 @@
|
||||
righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
|
||||
force = 5
|
||||
throwforce = 7
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
/obj/item/device/wormhole_jaunter/proc/get_destinations(mob/user)
|
||||
var/list/destinations = list()
|
||||
|
||||
for(var/obj/item/device/radio/beacon/B in GLOB.teleportbeacons)
|
||||
for(var/obj/item/device/beacon/B in GLOB.teleportbeacons)
|
||||
var/turf/T = get_turf(B)
|
||||
if(is_station_level(T.z))
|
||||
destinations += B
|
||||
|
||||
@@ -379,9 +379,8 @@
|
||||
if(SSshuttle.emergency.timeLeft(1) > initial(SSshuttle.emergencyCallTime)*0.5)
|
||||
SSticker.mode.make_antag_chance(humanc)
|
||||
|
||||
for(var/V in character.roundstart_traits)
|
||||
var/datum/trait/T = V
|
||||
T.on_spawn() //so latejoins still get their correct traits
|
||||
if(CONFIG_GET(flag/roundstart_traits))
|
||||
SStraits.AssignTraits(humanc, humanc.client, TRUE)
|
||||
|
||||
log_manifest(character.mind.key,character.mind,character,latejoin = TRUE)
|
||||
|
||||
|
||||
@@ -1402,6 +1402,14 @@
|
||||
/datum/sprite_accessory/legs/digitigrade_lizard
|
||||
name = "Digitigrade Legs"
|
||||
|
||||
/datum/sprite_accessory/caps
|
||||
icon = 'icons/mob/mutant_bodyparts.dmi'
|
||||
color_src = HAIR
|
||||
|
||||
/datum/sprite_accessory/caps/round
|
||||
name = "Round"
|
||||
icon_state = "round"
|
||||
|
||||
/datum/sprite_accessory/moth_wings
|
||||
icon = 'icons/mob/wings.dmi'
|
||||
color_src = null
|
||||
|
||||
@@ -288,8 +288,16 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
if(response != "Ghost")
|
||||
return //didn't want to ghost after-all
|
||||
ghostize(0) //0 parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3
|
||||
return
|
||||
|
||||
/mob/camera/verb/ghost()
|
||||
set category = "OOC"
|
||||
set name = "Ghost"
|
||||
set desc = "Relinquish your life and enter the land of the dead."
|
||||
|
||||
var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you may not play again this round! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
|
||||
if(response != "Ghost")
|
||||
return
|
||||
ghostize(0)
|
||||
|
||||
/mob/dead/observer/Move(NewLoc, direct)
|
||||
if(updatedir)
|
||||
@@ -634,7 +642,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
/mob/dead/observer/MouseDrop(atom/over)
|
||||
if(!usr || !over)
|
||||
return
|
||||
if (isobserver(usr) && usr.client.holder && isliving(over))
|
||||
if (isobserver(usr) && usr.client.holder && (isliving(over) || iscameramob(over)) )
|
||||
if (usr.client.holder.cmd_ghost_drag(src,over))
|
||||
return
|
||||
|
||||
|
||||
@@ -191,6 +191,10 @@
|
||||
blood_data["real_name"] = real_name
|
||||
blood_data["features"] = dna.features
|
||||
blood_data["factions"] = faction
|
||||
blood_data["traits"] = list()
|
||||
for(var/V in roundstart_traits)
|
||||
var/datum/trait/T = V
|
||||
blood_data["traits"] += T.type
|
||||
return blood_data
|
||||
|
||||
//get the id of the substance this mob use as blood.
|
||||
|
||||
@@ -683,6 +683,8 @@ GLOBAL_LIST_EMPTY(roundstart_races)
|
||||
S = GLOB.legs_list[H.dna.features["legs"]]
|
||||
if("moth_wings")
|
||||
S = GLOB.moth_wings_list[H.dna.features["moth_wings"]]
|
||||
if("caps")
|
||||
S = GLOB.caps_list[H.dna.features["caps"]]
|
||||
|
||||
//Mammal Bodyparts
|
||||
if("mam_tail")
|
||||
|
||||
@@ -17,4 +17,4 @@
|
||||
use_skintones = 0
|
||||
species_traits = list(SPECIES_ORGANIC,NOBLOOD,EYECOLOR)
|
||||
inherent_traits = list(TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER)
|
||||
sexes = 0
|
||||
sexes = 0
|
||||
@@ -53,7 +53,8 @@
|
||||
miss_sound = 'sound/weapons/slashmiss.ogg'
|
||||
liked_food = MEAT
|
||||
disliked_food = TOXIC
|
||||
|
||||
meat = /obj/item/reagent_containers/food/snacks/carpmeat/aquatic
|
||||
|
||||
/datum/species/aquatic/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
if(H)
|
||||
H.endTailWag()
|
||||
|
||||
@@ -384,6 +384,7 @@
|
||||
around.</span>",
|
||||
"<span class='notice'>...and move this one instead.</span>")
|
||||
|
||||
|
||||
///////////////////////////////////LUMINESCENTS//////////////////////////////////////////
|
||||
|
||||
//Luminescents are able to consume and use slime extracts, without them decaying.
|
||||
@@ -542,7 +543,6 @@
|
||||
|
||||
if(species.current_extract)
|
||||
species.extract_cooldown = world.time + 100
|
||||
|
||||
var/cooldown = species.current_extract.activate(H, species, activation_type)
|
||||
species.extract_cooldown = world.time + cooldown
|
||||
|
||||
@@ -555,8 +555,6 @@
|
||||
///////////////////////////////////STARGAZERS//////////////////////////////////////////
|
||||
|
||||
//Stargazers are the telepathic branch of jellypeople, able to project psychic messages and to link minds with willing participants.
|
||||
//Admin spawn only
|
||||
|
||||
|
||||
/datum/species/jelly/stargazer
|
||||
name = "Stargazer"
|
||||
@@ -725,5 +723,4 @@
|
||||
to_chat(H, "<span class='notice'>You connect [target]'s mind to your slime link!</span>")
|
||||
else
|
||||
to_chat(H, "<span class='warning'>You can't seem to link [target]'s mind...</span>")
|
||||
to_chat(target, "<span class='warning'>The foreign presence leaves your mind.</span>")
|
||||
|
||||
to_chat(target, "<span class='warning'>The foreign presence leaves your mind.</span>")
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
/datum/species/moth/space_move(mob/living/carbon/human/H)
|
||||
. = ..()
|
||||
if(H.loc && !isspaceturf(H.loc) && H.dna.features["moth_wings"] != "Burnt Off" || "None")
|
||||
if(H.loc && !isspaceturf(H.loc) && H.dna.features["moth_wings"] != "Burnt Off")
|
||||
var/datum/gas_mixture/current = H.loc.return_air()
|
||||
if(current && (current.return_pressure() >= ONE_ATMOSPHERE*0.85)) //as long as there's reasonable pressure and no gravity, flight is possible
|
||||
return TRUE
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/datum/species/mush //mush mush codecuck
|
||||
name = "Mushroomperson"
|
||||
id = "mush"
|
||||
mutant_bodyparts = list("caps")
|
||||
default_features = list("caps" = "Round")
|
||||
|
||||
fixed_mut_color = "DBBF92"
|
||||
hair_color = "FF4B19" //cap color, spot color uses eye color
|
||||
nojumpsuit = TRUE
|
||||
|
||||
say_mod = "poofs" //what does a mushroom sound like
|
||||
species_traits = list(MUTCOLORS, NOEYES, NO_UNDERWEAR)
|
||||
inherent_traits = list(TRAIT_NOBREATH)
|
||||
speedmod = 1.5 //faster than golems but not by much
|
||||
|
||||
punchdamagelow = 6
|
||||
punchdamagehigh = 14
|
||||
punchstunthreshold = 14 //about 44% chance to stun
|
||||
|
||||
no_equip = list(slot_wear_mask, slot_wear_suit, slot_gloves, slot_shoes, slot_w_uniform)
|
||||
|
||||
burnmod = 1.25
|
||||
heatmod = 1.5
|
||||
|
||||
mutanteyes = /obj/item/organ/eyes/night_vision/mushroom
|
||||
use_skintones = FALSE
|
||||
var/datum/martial_art/mushpunch/mush
|
||||
|
||||
/datum/species/mush/check_roundstart_eligible()
|
||||
return FALSE //hard locked out of roundstart on the order of design lead kor, this can be removed in the future when planetstation is here OR SOMETHING but right now we have a problem with races.
|
||||
|
||||
/datum/species/mush/after_equip_job(datum/job/J, mob/living/carbon/human/H)
|
||||
H.grant_language(/datum/language/mushroom) //pomf pomf
|
||||
|
||||
/datum/species/mush/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
. = ..()
|
||||
if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
if(!H.dna.features["caps"])
|
||||
H.dna.features["caps"] = "Round"
|
||||
handle_mutant_bodyparts(H)
|
||||
H.faction |= "mushroom"
|
||||
mush = new(null)
|
||||
mush.teach(H)
|
||||
|
||||
/datum/species/mush/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
C.faction -= "mushroom"
|
||||
mush.remove(C)
|
||||
QDEL_NULL(mush)
|
||||
|
||||
/datum/species/mush/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
|
||||
if(chem.id == "weedkiller")
|
||||
H.adjustToxLoss(3)
|
||||
H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
|
||||
return TRUE
|
||||
|
||||
/datum/species/mush/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour)
|
||||
forced_colour = FALSE
|
||||
..()
|
||||
@@ -59,6 +59,29 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
"÷" = "cords"
|
||||
))
|
||||
|
||||
/mob/living/proc/Ellipsis(original_msg, chance = 50, keep_words)
|
||||
if(chance <= 0)
|
||||
return "..."
|
||||
if(chance >= 100)
|
||||
return original_msg
|
||||
|
||||
var/list
|
||||
words = splittext(original_msg," ")
|
||||
new_words = list()
|
||||
|
||||
var/new_msg = ""
|
||||
|
||||
for(var/w in words)
|
||||
if(prob(chance))
|
||||
new_words += "..."
|
||||
if(!keep_words)
|
||||
continue
|
||||
new_words += w
|
||||
|
||||
new_msg = jointext(new_words," ")
|
||||
|
||||
return new_msg
|
||||
|
||||
/mob/living/say(message, bubble_type,var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE)
|
||||
var/static/list/crit_allowed_modes = list(MODE_WHISPER = TRUE, MODE_CHANGELING = TRUE, MODE_ALIEN = TRUE)
|
||||
var/static/list/unconscious_allowed_modes = list(MODE_CHANGELING = TRUE, MODE_ALIEN = TRUE)
|
||||
@@ -381,4 +404,4 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
if(.)
|
||||
return .
|
||||
|
||||
. = ..()
|
||||
. = ..()
|
||||
|
||||
@@ -106,10 +106,10 @@
|
||||
var/turf/t = turf
|
||||
if(obscuredTurfs[t])
|
||||
if(!t.obscured)
|
||||
t.obscured = image('icons/effects/cameravis.dmi', t, null, LIGHTING_LAYER+1)
|
||||
t.obscured = image('icons/effects/cameravis.dmi', t, null, BYOND_LIGHTING_LAYER+0.1)
|
||||
t.obscured.pixel_x = -t.pixel_x
|
||||
t.obscured.pixel_y = -t.pixel_y
|
||||
t.obscured.plane = LIGHTING_PLANE+1
|
||||
t.obscured.plane = BYOND_LIGHTING_PLANE+0.1
|
||||
obscured += t.obscured
|
||||
for(var/eye in seenby)
|
||||
var/mob/camera/aiEye/m = eye
|
||||
@@ -170,4 +170,4 @@
|
||||
obscured += t.obscured
|
||||
|
||||
#undef UPDATE_BUFFER
|
||||
#undef CHUNK_SIZE
|
||||
#undef CHUNK_SIZE
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user