Merge branch 'master' into crewobjectivesandmiscreants

This commit is contained in:
deathride58
2017-10-01 23:45:49 +00:00
committed by GitHub
485 changed files with 81708 additions and 13183 deletions
+11
View File
@@ -0,0 +1,11 @@
#define CINEMATIC_DEFAULT 1
#define CINEMATIC_SELFDESTRUCT 2
#define CINEMATIC_SELFDESTRUCT_MISS 3
#define CINEMATIC_NUKE_WIN 4
#define CINEMATIC_NUKE_MISS 5
#define CINEMATIC_ANNIHILATION 6
#define CINEMATIC_MALF 7
#define CINEMATIC_CULT 8
#define CINEMATIC_NUKE_FAKE 9
#define CINEMATIC_NUKE_NO_CORE 10
#define CINEMATIC_NUKE_FAR 11
+17 -29
View File
@@ -8,43 +8,31 @@
GLOBAL_VAR_INIT(clockwork_construction_value, 0) //The total value of all structures built by the clockwork cult
GLOBAL_VAR_INIT(clockwork_caches, 0) //How many clockwork caches exist in the world (not each individual)
GLOBAL_VAR_INIT(clockwork_vitality, 0) //How much Vitality is stored, total
GLOBAL_LIST_EMPTY(active_daemons) //A list of all active tinkerer's daemons
GLOBAL_VAR_INIT(clockwork_power, 0) //How many watts of power are globally available to the clockwork cult
GLOBAL_LIST_EMPTY(all_clockwork_objects) //All clockwork items, structures, and effects in existence
GLOBAL_LIST_EMPTY(all_clockwork_mobs) //All clockwork SERVANTS (not creatures) in existence
GLOBAL_LIST_INIT(clockwork_component_cache, list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 0, HIEROPHANT_ANSIBLE = 0)) //The pool of components that caches draw from
GLOBAL_VAR_INIT(ratvar_approaches, 0) //The servants can choose to "herald" Ratvar, permanently buffing them but announcing their presence to the crew.
GLOBAL_VAR_INIT(ratvar_awakens, 0) //If Ratvar has been summoned; not a boolean, for proper handling of multiple Ratvars
GLOBAL_VAR_INIT(ark_of_the_clockwork_justiciar, FALSE) //The Ark on the Reebe z-level
GLOBAL_VAR_INIT(clockwork_gateway_activated, FALSE) //if a gateway to the celestial derelict has ever been successfully activated
GLOBAL_VAR_INIT(script_scripture_unlocked, FALSE) //If script scripture is available, through converting at least one crewmember
GLOBAL_VAR_INIT(application_scripture_unlocked, FALSE) //If script scripture is available
GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not used to track existing scripture
//Scripture tiers and requirements; peripherals should never be used
#define SCRIPTURE_PERIPHERAL "Peripheral"
#define SCRIPTURE_DRIVER "Driver"
#define SCRIPTURE_SCRIPT "Script"
#define SCRIPT_SERVANT_REQ 6
#define SCRIPT_CACHE_REQ 1
#define SCRIPTURE_APPLICATION "Application"
#define APPLICATION_SERVANT_REQ 9
#define APPLICATION_CACHE_REQ 3
#define APPLICATION_CV_REQ 100
#define SCRIPTURE_JUDGEMENT "Judgement"
#define JUDGEMENT_SERVANT_REQ 12
#define JUDGEMENT_CACHE_REQ 5
#define JUDGEMENT_CV_REQ 300
//general component/cooldown things
#define SLAB_PRODUCTION_TIME 450 //how long(deciseconds) slabs require to produce a single component; defaults to 45 seconds
//Various costs related to power.
#define SCRIPT_UNLOCK_THRESHOLD 50000 //Scripts will unlock if the total power reaches this amount
#define APPLICATION_UNLOCK_THRESHOLD 100000 //Applications will unlock if the total powre reaches this amount
#define SLAB_SERVANT_SLOWDOWN 150 //how much each servant above 5 slows down slab-based generation; defaults to 15 seconds per sevant
#define SLAB_SLOWDOWN_MAXIMUM 1350 //maximum slowdown from additional servants; defaults to 2 minutes 15 seconds
#define CACHE_PRODUCTION_TIME 300 //how long(deciseconds) caches require to produce a component; defaults to 30 seconds
#define ACTIVE_CACHE_SLOWDOWN 50 //how many additional deciseconds caches take to produce a component for each linked cache; defaults to 5 seconds
#define LOWER_PROB_PER_COMPONENT 10 //how much each component in the cache reduces the weight of getting another of that component type
#define MAX_COMPONENTS_BEFORE_RAND (10*LOWER_PROB_PER_COMPONENT) //the number of each component, times LOWER_PROB_PER_COMPONENT, you need to have before component generation will become random
#define ABSCOND_ABDUCTION_COST 95
//clockcult power defines
#define MIN_CLOCKCULT_POWER 25 //the minimum amount of power clockcult machines will handle gracefully
@@ -72,11 +60,11 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
//Ark defines
#define GATEWAY_SUMMON_RATE 1 //the time amount the Gateway to the Celestial Derelict gets each process tick; defaults to 1 per tick
#define GATEWAY_REEBE_FOUND 119 //when progress is at or above this, the gateway finds reebe and begins drawing power
#define GATEWAY_REEBE_FOUND 240 //when progress is at or above this, the gateway finds reebe and begins drawing power
#define GATEWAY_RATVAR_COMING 239 //when progress is at or above this, ratvar has entered and is coming through the gateway
#define GATEWAY_RATVAR_COMING 480 //when progress is at or above this, ratvar has entered and is coming through the gateway
#define GATEWAY_RATVAR_ARRIVAL 300 //when progress is at or above this, game over ratvar's here everybody go home
#define GATEWAY_RATVAR_ARRIVAL 600 //when progress is at or above this, game over ratvar's here everybody go home
#define ARK_SUMMON_COST 5 //how many of each component an Ark costs to summon
@@ -94,6 +82,6 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
#define OCULAR_WARDEN_EXCLUSION_RANGE 3 //the range at which ocular wardens cannot be placed near other ocular wardens
#define RATVARIAN_SPEAR_DURATION 1800 //how long ratvarian spears last; defaults to 3 minutes
#define CLOCKWORK_ARMOR_COOLDOWN 1800 //The cooldown period between summoning suits of clockwork armor
#define PRISM_DELAY_DURATION 1200 //how long prolonging prisms delay the shuttle for; defaults to 2 minutes
#define RATVARIAN_SPEAR_COOLDOWN 300 //The cooldown period between summoning another Ratvarian spear
+10
View File
@@ -0,0 +1,10 @@
//config files
#define CONFIG_DEF(X) /datum/config_entry/##X { resident_file = CURRENT_RESIDENT_FILE }; /datum/config_entry/##X
#define CONFIG_GET(X) global.config.Get(/datum/config_entry/##X)
#define CONFIG_SET(X, Y) global.config.Set(/datum/config_entry/##X, ##Y)
#define CONFIG_MAPS_FILE "maps.txt"
//flags
#define CONFIG_ENTRY_LOCKED 1 //can't edit
#define CONFIG_ENTRY_HIDDEN 2 //can't see value
+3
View File
@@ -53,6 +53,9 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
// TESLA_IGNORE grants immunity from being targeted by tesla-style electricity
#define TESLA_IGNORE_2 512
// Stops you from putting things like an RCD or other items into an ORM or protolathe for materials.
#define NO_MAT_REDEMPTION_2 1024
//turf-only flags
#define NOJAUNT_1 1
#define UNUSED_TRANSIT_TURF_1 2
+7 -3
View File
@@ -9,6 +9,8 @@
#define ismovableatom(A) (istype(A, /atom/movable))
//Turfs
//#define isturf(A) (istype(A, /turf)) This is actually a byond built-in. Added here for completeness sake.
#define isopenturf(A) (istype(A, /turf/open))
#define isindestructiblefloor(A) (istype(A, /turf/open/indestructible))
@@ -136,6 +138,8 @@
#define isitem(A) (istype(A, /obj/item))
#define isstructure(A) (istype(A, /obj/structure))
#define is_cleanable(A) (istype(A, /obj/effect/decal/cleanable) || istype(A, /obj/effect/rune)) //if something is cleanable
#define isorgan(A) (istype(A, /obj/item/organ))
@@ -164,9 +168,9 @@ GLOBAL_LIST_INIT(pointed_types, typecacheof(list(
#define istimer(O) (istype(O, /obj/item/device/assembly/timer))
GLOBAL_LIST_INIT(glass_sheet_types, typecacheof(list(
/obj/item/stack/sheet/glass,
/obj/item/stack/sheet/rglass,
/obj/item/stack/sheet/plasmaglass,
/obj/item/stack/sheet/glass,
/obj/item/stack/sheet/rglass,
/obj/item/stack/sheet/plasmaglass,
/obj/item/stack/sheet/plasmarglass)))
#define is_glass_sheet(O) (is_type_in_typecache(O, GLOB.glass_sheet_types))
+3
View File
@@ -7,11 +7,14 @@
#define PLANE_SPACE_PARALLAX -90
#define GAME_PLANE 0
#define SPACE_LAYER 1.8
#define ABOVE_SPACE_LAYER 1.9
//#define TURF_LAYER 2 //For easy recordkeeping; this is a byond define
#define MID_TURF_LAYER 2.02
#define HIGH_TURF_LAYER 2.03
#define ABOVE_OPEN_TURF_LAYER 2.04
#define CLOSED_TURF_LAYER 2.05
#define BULLET_HOLE_LAYER 2.06
#define ABOVE_NORMAL_TURF_LAYER 2.08
#define LATTICE_LAYER 2.2
#define DISPOSAL_PIPE_LAYER 2.3
+4 -1
View File
@@ -3,10 +3,11 @@ The /tg/ codebase currently requires you to have 11 z-levels of the same size di
z-level order is important, the order you put them in inside the map config.dm will determine what z level number they are assigned ingame.
Names of z-level do not matter, but order does greatly, for instances such as checking alive status of revheads on z1
current as of 2016/6/2
current as of september 17, 2017
z1 = station
z2 = centcom
z5 = mining
z6 = city of cogs
Everything else = randomized space
Last space-z level = empty
*/
@@ -17,6 +18,7 @@ Last space-z level = empty
#define MAIN_STATION "Main Station"
#define CENTCOM "CentCom"
#define CITY_OF_COGS "City of Cogs"
#define EMPTY_AREA_1 "Empty Area 1"
#define EMPTY_AREA_2 "Empty Area 2"
#define MINING "Mining Asteroid"
@@ -38,6 +40,7 @@ Last space-z level = empty
#define ZLEVEL_STATION_PRIMARY 2
#define ZLEVEL_MINING 5
#define ZLEVEL_LAVALAND 5
#define ZLEVEL_CITYOFCOGS 6
#define ZLEVEL_EMPTY_SPACE 12
#define ZLEVEL_TRANSIT 11
+103 -14
View File
@@ -1,34 +1,123 @@
// /tg/station 13 server tools API v3.1
//CONFIGURATION
//use this define if you want to do configuration outside of this file
#ifndef SERVER_TOOLS_EXTERNAL_CONFIGURATION
//Comment this out once you've filled in the below
//#error /tg/station server tools interface unconfigured
//Required interfaces (fill in with your codebase equivalent):
//create a global variable named `Name` and set it to `Value`
//These globals must not be modifiable from anywhere outside of the server tools
#define SERVER_TOOLS_DEFINE_AND_SET_GLOBAL(Name, Value) GLOBAL_VAR_INIT(##Name, ##Value); GLOBAL_PROTECT(##Name)
//Read the value in the global variable `Name`
#define SERVER_TOOLS_READ_GLOBAL(Name) GLOB.##Name
//Set the value in the global variable `Name` to `Value`
#define SERVER_TOOLS_WRITE_GLOBAL(Name, Value) GLOB.##Name = ##Value
//display an announcement `message` from the server to all players
#define SERVER_TOOLS_WORLD_ANNOUNCE(message) to_chat(world, "<span class='boldannounce'>[html_encode(##message)]</span>")
//Write a string `message` to a server log
#define SERVER_TOOLS_LOG(message) log_world("SERVICE: [##message]")
//Notify current in-game administrators of a string `event`
#define SERVER_TOOLS_NOTIFY_ADMINS(event) message_admins(##event)
#endif
//Required hooks:
//Put this somewhere in /world/New() that is always run
#define SERVER_TOOLS_ON_NEW ServiceInit()
//Put this somewhere in /world/Topic(T, Addr, Master, Keys) that is always run before T is modified
#define SERVER_TOOLS_ON_TOPIC var/service_topic_return = ServiceCommand(params2list(T)); if(service_topic_return) return service_topic_return
//Put at the beginning of world/Reboot(reason)
#define SERVER_TOOLS_ON_REBOOT ServiceReboot()
//Optional callable functions:
//Returns the string version of the API
#define SERVER_TOOLS_API_VERSION ServiceAPIVersion()
//Returns TRUE if the world was launched under the server tools and the API matches, FALSE otherwise
//No function below this succeed if this is FALSE
#define SERVER_TOOLS_PRESENT RunningService()
//Gets the current version of the service running the server
#define SERVER_TOOLS_VERSION ServiceVersion()
//Forces a hard reboot of BYOND by ending the process
//unlike del(world) clients will try to reconnect
//If the service has not requested a shutdown, the world will reboot shortly after
#define SERVER_TOOLS_REBOOT_BYOND world.ServiceEndProcess()
/*
Gets the list of any testmerged github pull requests
"[PR Number]" => list(
"title" -> PR title
"commit" -> Full hash of commit merged
"author" -> Github username of the author of the PR
)
*/
#define SERVER_TOOLS_PR_LIST GetTestMerges()
//Sends a message to connected game chats
#define SERVER_TOOLS_CHAT_BROADCAST(message) world.ChatBroadcast(message)
//Sends a message to connected admin chats
#define SERVER_TOOLS_RELAY_BROADCAST(message) world.AdminBroadcast(message)
//IMPLEMENTATION
#define SERVICE_API_VERSION_STRING "3.1.0.0"
#define REBOOT_MODE_NORMAL 0
#define REBOOT_MODE_HARD 1
#define REBOOT_MODE_SHUTDOWN 2
#define IRC_STATUS_THROTTLE 5
#define PR_ANNOUNCEMENTS_PER_ROUND 5 //The number of unique PR announcements allowed per round
//This makes sure that a single person can only spam 3 reopens and 3 closes before being ignored
//keep these in sync with TGS3
#define SERVICE_WORLD_PARAM "server_service"
#define SERVICE_VERSION_PARAM "server_service_version"
#define SERVICE_PR_TEST_JSON "prtestjob.json"
#define SERVICE_PR_TEST_JSON_OLD "..\\..\\[SERVICE_PR_TEST_JSON]"
#define SERVICE_INTERFACE_DLL "TGServiceInterface.dll"
#define SERVICE_INTERFACE_FUNCTION "DDEntryPoint"
#define SERVICE_CMD_HARD_REBOOT "hard_reboot"
#define SERVICE_CMD_GRACEFUL_SHUTDOWN "graceful_shutdown"
#define SERVICE_CMD_WORLD_ANNOUNCE "world_announce"
#define SERVICE_CMD_IRC_CHECK "irc_check"
#define SERVICE_CMD_IRC_STATUS "irc_status"
#define SERVICE_CMD_ADMIN_MSG "adminmsg"
#define SERVICE_CMD_NAME_CHECK "namecheck"
#define SERVICE_CMD_ADMIN_WHO "adminwho"
#define SERVICE_CMD_LIST_CUSTOM "list_custom_commands"
#define SERVICE_CMD_PARAM_KEY "serviceCommsKey"
#define SERVICE_CMD_PARAM_COMMAND "command"
#define SERVICE_CMD_PARAM_MESSAGE "message"
#define SERVICE_CMD_PARAM_TARGET "target"
#define SERVICE_CMD_PARAM_SENDER "sender"
#define SERVICE_CMD_PARAM_CUSTOM "custom"
#define SERVICE_CMD_API_COMPATIBLE "api_compat"
#define SERVICE_JSON_PARAM_HELPTEXT "help_text"
#define SERVICE_JSON_PARAM_ADMINONLY "admin_only"
#define SERVICE_JSON_PARAM_REQUIREDPARAMETERS "required_parameters"
#define SERVICE_REQUEST_KILL_PROCESS "killme"
#define SERVICE_REQUEST_IRC_BROADCAST "irc"
#define SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE "send2irc"
#define SERVICE_REQUEST_WORLD_REBOOT "worldreboot"
#define SERVICE_REQUEST_API_VERSION "api_ver"
/*
The MIT License
Copyright (c) 2011 Dominic Tarr
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and
associated documentation files (the "Software"), to
deal in the Software without restriction, including
without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom
the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+2
View File
@@ -62,6 +62,8 @@
#define CURSE_WASTING 4 //causes gradual damage
#define CURSE_GRASPING 8 //hands reach out from the sides of the screen, doing damage and stunning if they hit the target
#define STATUS_EFFECT_KINDLE /datum/status_effect/kindle //A knockdown reduced by 1 second for every 3 points of damage the target takes.
/////////////
// NEUTRAL //
/////////////
+1 -1
View File
@@ -474,7 +474,7 @@
#error Remie said that lummox was adding a way to get a lists
#error contents via list.values, if that is true remove this
#error otherwise, update the version and bug lummox
#elseif
#endif
//Flattens a keyed list into a list of it's contents
/proc/flatten_list(list/key_list)
if(!islist(key_list))
+21 -17
View File
@@ -26,74 +26,74 @@
/proc/log_admin(text)
GLOB.admin_log.Add(text)
if (config.log_admin)
if (CONFIG_GET(flag/log_admin))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]ADMIN: [text]")
//Items using this proc are stripped from public logs - use with caution
/proc/log_admin_private(text)
GLOB.admin_log.Add(text)
if (config.log_admin)
if (CONFIG_GET(flag/log_admin))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]ADMINPRIVATE: [text]")
/proc/log_adminsay(text)
if (config.log_adminchat)
if (CONFIG_GET(flag/log_adminchat))
log_admin_private("ASAY: [text]")
/proc/log_dsay(text)
if (config.log_adminchat)
if (CONFIG_GET(flag/log_adminchat))
log_admin("DSAY: [text]")
/proc/log_game(text)
if (config.log_game)
if (CONFIG_GET(flag/log_game))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]GAME: [text]")
/proc/log_vote(text)
if (config.log_vote)
if (CONFIG_GET(flag/log_vote))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]VOTE: [text]")
/proc/log_access(text)
if (config.log_access)
if (CONFIG_GET(flag/log_access))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]ACCESS: [text]")
/proc/log_say(text)
if (config.log_say)
if (CONFIG_GET(flag/log_say))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]SAY: [text]")
/proc/log_prayer(text)
if (config.log_prayer)
if (CONFIG_GET(flag/log_prayer))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]PRAY: [text]")
/proc/log_law(text)
if (config.log_law)
if (CONFIG_GET(flag/log_law))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]LAW: [text]")
/proc/log_ooc(text)
if (config.log_ooc)
if (CONFIG_GET(flag/log_ooc))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]OOC: [text]")
/proc/log_whisper(text)
if (config.log_whisper)
if (CONFIG_GET(flag/log_whisper))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]WHISPER: [text]")
/proc/log_emote(text)
if (config.log_emote)
if (CONFIG_GET(flag/log_emote))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]EMOTE: [text]")
/proc/log_attack(text)
if (config.log_attack)
if (CONFIG_GET(flag/log_attack))
WRITE_FILE(GLOB.world_attack_log, "\[[time_stamp()]]ATTACK: [text]")
/proc/log_pda(text)
if (config.log_pda)
if (CONFIG_GET(flag/log_pda))
WRITE_FILE(GLOB.world_pda_log, "\[[time_stamp()]]PDA: [text]")
/proc/log_comment(text)
if (config.log_pda)
if (CONFIG_GET(flag/log_pda))
//reusing the PDA option because I really don't think news comments are worth a config option
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]COMMENT: [text]")
/proc/log_chat(text)
if (config.log_pda)
if (CONFIG_GET(flag/log_pda))
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]CHAT: [text]")
/proc/log_qdel(text)
@@ -102,6 +102,10 @@
/proc/log_sql(text)
WRITE_FILE(GLOB.sql_error_log, "\[[time_stamp()]]SQL: [text]")
/proc/log_config(text)
WRITE_FILE(GLOB.config_error_log, text)
SEND_TEXT(world.log, text)
//This replaces world.log so it displays both in DD and the file
/proc/log_world(text)
WRITE_FILE(GLOB.world_runtime_log, text)
+3 -2
View File
@@ -314,10 +314,11 @@
// Will return a list of active candidates. It increases the buffer 5 times until it finds a candidate which is active within the buffer.
/proc/get_candidates(be_special_type, afk_bracket = config.inactivity_period, jobbanType)
/proc/get_candidates(be_special_type, afk_bracket = CONFIG_GET(number/inactivity_period), jobbanType)
var/list/candidates = list()
// Keep looping until we find a non-afk candidate within the time bracket (we limit the bracket to 10 minutes (6000))
while(!candidates.len && afk_bracket < config.afk_period)
var/afk_period = CONFIG_GET(number/afk_period)
while(!candidates.len && afk_bracket < afk_period)
for(var/mob/dead/observer/G in GLOB.player_list)
if(G.client != null)
if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD))
+115 -116
View File
@@ -1,116 +1,115 @@
//////////////////////////
/////Initial Building/////
//////////////////////////
/proc/make_datum_references_lists()
//hair
init_sprite_accessory_subtypes(/datum/sprite_accessory/hair, GLOB.hair_styles_list, GLOB.hair_styles_male_list, GLOB.hair_styles_female_list)
//facial hair
init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_hair, GLOB.facial_hair_styles_list, GLOB.facial_hair_styles_male_list, GLOB.facial_hair_styles_female_list)
//underwear
init_sprite_accessory_subtypes(/datum/sprite_accessory/underwear, GLOB.underwear_list, GLOB.underwear_m, GLOB.underwear_f)
//undershirt
init_sprite_accessory_subtypes(/datum/sprite_accessory/undershirt, GLOB.undershirt_list, GLOB.undershirt_m, GLOB.undershirt_f)
//socks
init_sprite_accessory_subtypes(/datum/sprite_accessory/socks, GLOB.socks_list)
//lizard bodyparts (blizzard intensifies)
init_sprite_accessory_subtypes(/datum/sprite_accessory/body_markings, GLOB.body_markings_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/lizard, GLOB.tails_list_lizard)
init_sprite_accessory_subtypes(/datum/sprite_accessory/tails_animated/lizard, GLOB.animated_tails_list_lizard)
init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/human, GLOB.tails_list_human)
init_sprite_accessory_subtypes(/datum/sprite_accessory/tails_animated/human, GLOB.animated_tails_list_human)
init_sprite_accessory_subtypes(/datum/sprite_accessory/snouts, GLOB.snouts_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/horns,GLOB.horns_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/ears, GLOB.ears_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, GLOB.wings_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings_open, GLOB.wings_open_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/frills, GLOB.frills_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/spines, GLOB.spines_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/spines_animated, GLOB.animated_spines_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/legs, GLOB.legs_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, GLOB.r_wings_list,roundstart = TRUE)
//citadel code
//mammal bodyparts (fucking furries)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_body_markings, GLOB.mam_body_markings_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails, GLOB.mam_tails_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_ears, GLOB.mam_ears_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails_animated, GLOB.mam_tails_animated_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/taur, GLOB.taur_list)
//avian bodyparts (i swear this isn't starbound)
// init_sprite_accessory_subtypes(/datum/sprite_accessory/beaks/avian, GLOB.avian_beaks_list)
// init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/avian, GLOB.avian_tails_list)
// init_sprite_accessory_subtypes(/datum/sprite_accessory/avian_wings, GLOB.avian_wings_list)
// init_sprite_accessory_subtypes(/datum/sprite_accessory/avian_open_wings, GLOB.avian_open_wings_list)
//xeno parts (hiss?)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_head, GLOB.xeno_head_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_tail, GLOB.xeno_tail_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_dorsal, GLOB.xeno_dorsal_list)
//genitals
init_sprite_accessory_subtypes(/datum/sprite_accessory/penis, GLOB.cock_shapes_list)
for(var/K in GLOB.cock_shapes_list)
var/datum/sprite_accessory/penis/value = GLOB.cock_shapes_list[K]
GLOB.cock_shapes_icons[K] = value.icon_state
init_sprite_accessory_subtypes(/datum/sprite_accessory/vagina, GLOB.vagina_shapes_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/breasts, GLOB.breasts_shapes_list)
GLOB.breasts_size_list = list("a","b","c","d","e") //We need the list to choose from initialized, but it's no longer a sprite_accessory thing.
//Species
for(var/spath in subtypesof(/datum/species))
var/datum/species/S = new spath()
if(S.roundstart)
GLOB.roundstart_species[S.id] = S.type
GLOB.species_list[S.id] = S.type
//Surgeries
for(var/path in subtypesof(/datum/surgery))
GLOB.surgeries_list += new path()
//Materials
for(var/path in subtypesof(/datum/material))
var/datum/material/D = new path()
GLOB.materials_list[D.id] = D
//Techs
for(var/path in subtypesof(/datum/tech))
var/datum/tech/D = new path()
GLOB.tech_list[D.id] = D
//Emotes
for(var/path in subtypesof(/datum/emote))
var/datum/emote/E = new path()
E.emote_list[E.key] = E
init_subtypes(/datum/crafting_recipe, GLOB.crafting_recipes)
/* // Uncomment to debug chemical reaction list.
/client/verb/debug_chemical_list()
for (var/reaction in chemical_reactions_list)
. += "chemical_reactions_list\[\"[reaction]\"\] = \"[chemical_reactions_list[reaction]]\"\n"
if(islist(chemical_reactions_list[reaction]))
var/list/L = chemical_reactions_list[reaction]
for(var/t in L)
. += " has: [t]\n"
to_chat(world, .)
*/
//creates every subtype of prototype (excluding prototype) and adds it to list L.
//if no list/L is provided, one is created.
/proc/init_subtypes(prototype, list/L)
if(!istype(L))
L = list()
for(var/path in subtypesof(prototype))
L += new path()
return L
//returns a list of paths to every subtype of prototype (excluding prototype)
//if no list/L is provided, one is created.
/proc/init_paths(prototype, list/L)
if(!istype(L))
L = list()
for(var/path in subtypesof(prototype))
L+= path
return L
//////////////////////////
/////Initial Building/////
//////////////////////////
/proc/make_datum_references_lists()
//hair
init_sprite_accessory_subtypes(/datum/sprite_accessory/hair, GLOB.hair_styles_list, GLOB.hair_styles_male_list, GLOB.hair_styles_female_list)
//facial hair
init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_hair, GLOB.facial_hair_styles_list, GLOB.facial_hair_styles_male_list, GLOB.facial_hair_styles_female_list)
//underwear
init_sprite_accessory_subtypes(/datum/sprite_accessory/underwear, GLOB.underwear_list, GLOB.underwear_m, GLOB.underwear_f)
//undershirt
init_sprite_accessory_subtypes(/datum/sprite_accessory/undershirt, GLOB.undershirt_list, GLOB.undershirt_m, GLOB.undershirt_f)
//socks
init_sprite_accessory_subtypes(/datum/sprite_accessory/socks, GLOB.socks_list)
//lizard bodyparts (blizzard intensifies)
init_sprite_accessory_subtypes(/datum/sprite_accessory/body_markings, GLOB.body_markings_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/lizard, GLOB.tails_list_lizard)
init_sprite_accessory_subtypes(/datum/sprite_accessory/tails_animated/lizard, GLOB.animated_tails_list_lizard)
init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/human, GLOB.tails_list_human)
init_sprite_accessory_subtypes(/datum/sprite_accessory/tails_animated/human, GLOB.animated_tails_list_human)
init_sprite_accessory_subtypes(/datum/sprite_accessory/snouts, GLOB.snouts_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/horns,GLOB.horns_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/ears, GLOB.ears_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, GLOB.wings_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings_open, GLOB.wings_open_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/frills, GLOB.frills_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/spines, GLOB.spines_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/spines_animated, GLOB.animated_spines_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/legs, GLOB.legs_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, GLOB.r_wings_list,roundstart = TRUE)
//citadel code
//mammal bodyparts (fucking furries)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_body_markings, GLOB.mam_body_markings_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails, GLOB.mam_tails_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_ears, GLOB.mam_ears_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails_animated, GLOB.mam_tails_animated_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/taur, GLOB.taur_list)
//avian bodyparts (i swear this isn't starbound)
// init_sprite_accessory_subtypes(/datum/sprite_accessory/beaks/avian, GLOB.avian_beaks_list)
// init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/avian, GLOB.avian_tails_list)
// init_sprite_accessory_subtypes(/datum/sprite_accessory/avian_wings, GLOB.avian_wings_list)
// init_sprite_accessory_subtypes(/datum/sprite_accessory/avian_open_wings, GLOB.avian_open_wings_list)
//xeno parts (hiss?)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_head, GLOB.xeno_head_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_tail, GLOB.xeno_tail_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_dorsal, GLOB.xeno_dorsal_list)
//genitals
init_sprite_accessory_subtypes(/datum/sprite_accessory/penis, GLOB.cock_shapes_list)
for(var/K in GLOB.cock_shapes_list)
var/datum/sprite_accessory/penis/value = GLOB.cock_shapes_list[K]
GLOB.cock_shapes_icons[K] = value.icon_state
init_sprite_accessory_subtypes(/datum/sprite_accessory/vagina, GLOB.vagina_shapes_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/breasts, GLOB.breasts_shapes_list)
GLOB.breasts_size_list = list("a","b","c","d","e") //We need the list to choose from initialized, but it's no longer a sprite_accessory thing.
//Species
for(var/spath in subtypesof(/datum/species))
var/datum/species/S = new spath()
GLOB.species_list[S.id] = spath
//Surgeries
for(var/path in subtypesof(/datum/surgery))
GLOB.surgeries_list += new path()
//Materials
for(var/path in subtypesof(/datum/material))
var/datum/material/D = new path()
GLOB.materials_list[D.id] = D
//Techs
for(var/path in subtypesof(/datum/tech))
var/datum/tech/D = new path()
GLOB.tech_list[D.id] = D
//Emotes
for(var/path in subtypesof(/datum/emote))
var/datum/emote/E = new path()
E.emote_list[E.key] = E
init_subtypes(/datum/crafting_recipe, GLOB.crafting_recipes)
/* // Uncomment to debug chemical reaction list.
/client/verb/debug_chemical_list()
for (var/reaction in chemical_reactions_list)
. += "chemical_reactions_list\[\"[reaction]\"\] = \"[chemical_reactions_list[reaction]]\"\n"
if(islist(chemical_reactions_list[reaction]))
var/list/L = chemical_reactions_list[reaction]
for(var/t in L)
. += " has: [t]\n"
to_chat(world, .)
*/
//creates every subtype of prototype (excluding prototype) and adds it to list L.
//if no list/L is provided, one is created.
/proc/init_subtypes(prototype, list/L)
if(!istype(L))
L = list()
for(var/path in subtypesof(prototype))
L += new path()
return L
//returns a list of paths to every subtype of prototype (excluding prototype)
//if no list/L is provided, one is created.
/proc/init_paths(prototype, list/L)
if(!istype(L))
L = list()
for(var/path in subtypesof(prototype))
L+= path
return L
-1
View File
@@ -220,7 +220,6 @@ GLOBAL_LIST_INIT(skin_tones, list(
))
GLOBAL_LIST_EMPTY(species_list)
GLOBAL_LIST_EMPTY(roundstart_species)
/proc/age2agedescription(age)
switch(age)
+248 -246
View File
@@ -1,246 +1,248 @@
#define ION_FILE "ion_laws.json"
/proc/lizard_name(gender)
if(gender == MALE)
return "[pick(GLOB.lizard_names_male)]-[pick(GLOB.lizard_names_male)]"
else
return "[pick(GLOB.lizard_names_female)]-[pick(GLOB.lizard_names_female)]"
/proc/plasmaman_name()
return "[pick(GLOB.plasmaman_names)] \Roman[rand(1,99)]"
/proc/church_name()
var/static/church_name
if (church_name)
return church_name
var/name = ""
name += pick("Holy", "United", "First", "Second", "Last")
if (prob(20))
name += " Space"
name += " " + pick("Church", "Cathedral", "Body", "Worshippers", "Movement", "Witnesses")
name += " of [religion_name()]"
return name
GLOBAL_VAR(command_name)
/proc/command_name()
if (GLOB.command_name)
return GLOB.command_name
var/name = "Central Command"
GLOB.command_name = name
return name
/proc/change_command_name(name)
GLOB.command_name = name
return name
/proc/religion_name()
var/static/religion_name
if (religion_name)
return religion_name
var/name = ""
name += pick("bee", "science", "edu", "captain", "assistant", "monkey", "alien", "space", "unit", "sprocket", "gadget", "bomb", "revolution", "beyond", "station", "goon", "robot", "ivor", "hobnob")
name += pick("ism", "ia", "ology", "istism", "ites", "ick", "ian", "ity")
return capitalize(name)
/proc/station_name()
if(!GLOB.station_name)
var/newname
if(config && config.station_name)
newname = config.station_name
else
newname = new_station_name()
set_station_name(newname)
return GLOB.station_name
/proc/set_station_name(newname)
GLOB.station_name = newname
if(config && config.server_name)
world.name = "[config.server_name][config.server_name==GLOB.station_name ? "" : ": [GLOB.station_name]"]"
else
world.name = GLOB.station_name
/proc/new_station_name()
var/random = rand(1,5)
var/name = ""
var/new_station_name = ""
//Rare: Pre-Prefix
if (prob(10))
name = pick(GLOB.station_prefixes)
new_station_name = name + " "
name = ""
// Prefix
for(var/holiday_name in SSevents.holidays)
if(holiday_name == "Friday the 13th")
random = 13
var/datum/holiday/holiday = SSevents.holidays[holiday_name]
name = holiday.getStationPrefix()
//get normal name
if(!name)
name = pick(GLOB.station_names)
if(name)
new_station_name += name + " "
// Suffix
name = pick(GLOB.station_suffixes)
new_station_name += name + " "
// ID Number
switch(random)
if(1)
new_station_name += "[rand(1, 99)]"
if(2)
new_station_name += pick(GLOB.greek_letters)
if(3)
new_station_name += "\Roman[rand(1,99)]"
if(4)
new_station_name += pick(GLOB.phonetic_alphabet)
if(5)
new_station_name += pick(GLOB.numbers_as_words)
if(13)
new_station_name += pick("13","XIII","Thirteen")
return new_station_name
/proc/syndicate_name()
var/static/syndicate_name
if (syndicate_name)
return syndicate_name
var/name = ""
// Prefix
name += pick("Clandestine", "Prima", "Blue", "Zero-G", "Max", "Blasto", "Waffle", "North", "Omni", "Newton", "Cyber", "Bonk", "Gene", "Gib")
// Suffix
if (prob(80))
name += " "
// Full
if (prob(60))
name += pick("Syndicate", "Consortium", "Collective", "Corporation", "Group", "Holdings", "Biotech", "Industries", "Systems", "Products", "Chemicals", "Enterprises", "Family", "Creations", "International", "Intergalactic", "Interplanetary", "Foundation", "Positronics", "Hive")
// Broken
else
name += pick("Syndi", "Corp", "Bio", "System", "Prod", "Chem", "Inter", "Hive")
name += pick("", "-")
name += pick("Tech", "Sun", "Co", "Tek", "X", "Inc", "Code")
// Small
else
name += pick("-", "*", "")
name += pick("Tech", "Sun", "Co", "Tek", "X", "Inc", "Gen", "Star", "Dyne", "Code", "Hive")
syndicate_name = name
return name
//Traitors and traitor silicons will get these. Revs will not.
GLOBAL_VAR(syndicate_code_phrase) //Code phrase for traitors.
GLOBAL_VAR(syndicate_code_response) //Code response for traitors.
/*
Should be expanded.
How this works:
Instead of "I'm looking for James Smith," the traitor would say "James Smith" as part of a conversation.
Another traitor may then respond with: "They enjoy running through the void-filled vacuum of the derelict."
The phrase should then have the words: James Smith.
The response should then have the words: run, void, and derelict.
This way assures that the code is suited to the conversation and is unpredicatable.
Obviously, some people will be better at this than others but in theory, everyone should be able to do it and it only enhances roleplay.
Can probably be done through "{ }" but I don't really see the practical benefit.
One example of an earlier system is commented below.
/N
*/
/proc/generate_code_phrase(return_list=FALSE)//Proc is used for phrase and response in master_controller.dm
if(!return_list)
. = ""
else
. = list()
var/words = pick(//How many words there will be. Minimum of two. 2, 4 and 5 have a lesser chance of being selected. 3 is the most likely.
50; 2,
200; 3,
50; 4,
25; 5
)
var/list/safety = list(1,2,3)//Tells the proc which options to remove later on.
var/nouns = strings(ION_FILE, "ionabstract")
var/objects = strings(ION_FILE, "ionobjects")
var/adjectives = strings(ION_FILE, "ionadjectives")
var/threats = strings(ION_FILE, "ionthreats")
var/foods = strings(ION_FILE, "ionfood")
var/drinks = strings(ION_FILE, "iondrinks")
var/list/locations = GLOB.teleportlocs.len ? GLOB.teleportlocs : drinks //if null, defaults to drinks instead.
var/list/names = list()
for(var/datum/data/record/t in GLOB.data_core.general)//Picks from crew manifest.
names += t.fields["name"]
var/maxwords = words//Extra var to check for duplicates.
for(words,words>0,words--)//Randomly picks from one of the choices below.
if(words==1&&(1 in safety)&&(2 in safety))//If there is only one word remaining and choice 1 or 2 have not been selected.
safety = list(pick(1,2))//Select choice 1 or 2.
else if(words==1&&maxwords==2)//Else if there is only one word remaining (and there were two originally), and 1 or 2 were chosen,
safety = list(3)//Default to list 3
switch(pick(safety))//Chance based on the safety list.
if(1)//1 and 2 can only be selected once each to prevent more than two specific names/places/etc.
switch(rand(1,2))//Mainly to add more options later.
if(1)
if(names.len&&prob(70))
. += pick(names)
else
if(prob(10))
. += pick(lizard_name(MALE),lizard_name(FEMALE))
else
var/new_name = pick(pick(GLOB.first_names_male,GLOB.first_names_female))
new_name += " "
new_name += pick(GLOB.last_names)
. += new_name
if(2)
. += pick(get_all_jobs())//Returns a job.
safety -= 1
if(2)
switch(rand(1,3))//Food, drinks, or things. Only selectable once.
if(1)
. += lowertext(pick(drinks))
if(2)
. += lowertext(pick(foods))
if(3)
. += lowertext(pick(locations))
safety -= 2
if(3)
switch(rand(1,4))//Abstract nouns, objects, adjectives, threats. Can be selected more than once.
if(1)
. += lowertext(pick(nouns))
if(2)
. += lowertext(pick(objects))
if(3)
. += lowertext(pick(adjectives))
if(4)
. += lowertext(pick(threats))
if(!return_list)
if(words==1)
. += "."
else
. += ", "
#define ION_FILE "ion_laws.json"
/proc/lizard_name(gender)
if(gender == MALE)
return "[pick(GLOB.lizard_names_male)]-[pick(GLOB.lizard_names_male)]"
else
return "[pick(GLOB.lizard_names_female)]-[pick(GLOB.lizard_names_female)]"
/proc/plasmaman_name()
return "[pick(GLOB.plasmaman_names)] \Roman[rand(1,99)]"
/proc/church_name()
var/static/church_name
if (church_name)
return church_name
var/name = ""
name += pick("Holy", "United", "First", "Second", "Last")
if (prob(20))
name += " Space"
name += " " + pick("Church", "Cathedral", "Body", "Worshippers", "Movement", "Witnesses")
name += " of [religion_name()]"
return name
GLOBAL_VAR(command_name)
/proc/command_name()
if (GLOB.command_name)
return GLOB.command_name
var/name = "Central Command"
GLOB.command_name = name
return name
/proc/change_command_name(name)
GLOB.command_name = name
return name
/proc/religion_name()
var/static/religion_name
if (religion_name)
return religion_name
var/name = ""
name += pick("bee", "science", "edu", "captain", "assistant", "monkey", "alien", "space", "unit", "sprocket", "gadget", "bomb", "revolution", "beyond", "station", "goon", "robot", "ivor", "hobnob")
name += pick("ism", "ia", "ology", "istism", "ites", "ick", "ian", "ity")
return capitalize(name)
/proc/station_name()
if(!GLOB.station_name)
var/newname
var/config_station_name = CONFIG_GET(string/stationname)
if(config_station_name)
newname = config_station_name
else
newname = new_station_name()
set_station_name(newname)
return GLOB.station_name
/proc/set_station_name(newname)
GLOB.station_name = newname
var/config_server_name = CONFIG_GET(string/servername)
if(config_server_name)
world.name = "[config_server_name][config_server_name == GLOB.station_name ? "" : ": [GLOB.station_name]"]"
else
world.name = GLOB.station_name
/proc/new_station_name()
var/random = rand(1,5)
var/name = ""
var/new_station_name = ""
//Rare: Pre-Prefix
if (prob(10))
name = pick(GLOB.station_prefixes)
new_station_name = name + " "
name = ""
// Prefix
for(var/holiday_name in SSevents.holidays)
if(holiday_name == "Friday the 13th")
random = 13
var/datum/holiday/holiday = SSevents.holidays[holiday_name]
name = holiday.getStationPrefix()
//get normal name
if(!name)
name = pick(GLOB.station_names)
if(name)
new_station_name += name + " "
// Suffix
name = pick(GLOB.station_suffixes)
new_station_name += name + " "
// ID Number
switch(random)
if(1)
new_station_name += "[rand(1, 99)]"
if(2)
new_station_name += pick(GLOB.greek_letters)
if(3)
new_station_name += "\Roman[rand(1,99)]"
if(4)
new_station_name += pick(GLOB.phonetic_alphabet)
if(5)
new_station_name += pick(GLOB.numbers_as_words)
if(13)
new_station_name += pick("13","XIII","Thirteen")
return new_station_name
/proc/syndicate_name()
var/static/syndicate_name
if (syndicate_name)
return syndicate_name
var/name = ""
// Prefix
name += pick("Clandestine", "Prima", "Blue", "Zero-G", "Max", "Blasto", "Waffle", "North", "Omni", "Newton", "Cyber", "Bonk", "Gene", "Gib")
// Suffix
if (prob(80))
name += " "
// Full
if (prob(60))
name += pick("Syndicate", "Consortium", "Collective", "Corporation", "Group", "Holdings", "Biotech", "Industries", "Systems", "Products", "Chemicals", "Enterprises", "Family", "Creations", "International", "Intergalactic", "Interplanetary", "Foundation", "Positronics", "Hive")
// Broken
else
name += pick("Syndi", "Corp", "Bio", "System", "Prod", "Chem", "Inter", "Hive")
name += pick("", "-")
name += pick("Tech", "Sun", "Co", "Tek", "X", "Inc", "Code")
// Small
else
name += pick("-", "*", "")
name += pick("Tech", "Sun", "Co", "Tek", "X", "Inc", "Gen", "Star", "Dyne", "Code", "Hive")
syndicate_name = name
return name
//Traitors and traitor silicons will get these. Revs will not.
GLOBAL_VAR(syndicate_code_phrase) //Code phrase for traitors.
GLOBAL_VAR(syndicate_code_response) //Code response for traitors.
/*
Should be expanded.
How this works:
Instead of "I'm looking for James Smith," the traitor would say "James Smith" as part of a conversation.
Another traitor may then respond with: "They enjoy running through the void-filled vacuum of the derelict."
The phrase should then have the words: James Smith.
The response should then have the words: run, void, and derelict.
This way assures that the code is suited to the conversation and is unpredicatable.
Obviously, some people will be better at this than others but in theory, everyone should be able to do it and it only enhances roleplay.
Can probably be done through "{ }" but I don't really see the practical benefit.
One example of an earlier system is commented below.
/N
*/
/proc/generate_code_phrase(return_list=FALSE)//Proc is used for phrase and response in master_controller.dm
if(!return_list)
. = ""
else
. = list()
var/words = pick(//How many words there will be. Minimum of two. 2, 4 and 5 have a lesser chance of being selected. 3 is the most likely.
50; 2,
200; 3,
50; 4,
25; 5
)
var/list/safety = list(1,2,3)//Tells the proc which options to remove later on.
var/nouns = strings(ION_FILE, "ionabstract")
var/objects = strings(ION_FILE, "ionobjects")
var/adjectives = strings(ION_FILE, "ionadjectives")
var/threats = strings(ION_FILE, "ionthreats")
var/foods = strings(ION_FILE, "ionfood")
var/drinks = strings(ION_FILE, "iondrinks")
var/list/locations = GLOB.teleportlocs.len ? GLOB.teleportlocs : drinks //if null, defaults to drinks instead.
var/list/names = list()
for(var/datum/data/record/t in GLOB.data_core.general)//Picks from crew manifest.
names += t.fields["name"]
var/maxwords = words//Extra var to check for duplicates.
for(words,words>0,words--)//Randomly picks from one of the choices below.
if(words==1&&(1 in safety)&&(2 in safety))//If there is only one word remaining and choice 1 or 2 have not been selected.
safety = list(pick(1,2))//Select choice 1 or 2.
else if(words==1&&maxwords==2)//Else if there is only one word remaining (and there were two originally), and 1 or 2 were chosen,
safety = list(3)//Default to list 3
switch(pick(safety))//Chance based on the safety list.
if(1)//1 and 2 can only be selected once each to prevent more than two specific names/places/etc.
switch(rand(1,2))//Mainly to add more options later.
if(1)
if(names.len&&prob(70))
. += pick(names)
else
if(prob(10))
. += pick(lizard_name(MALE),lizard_name(FEMALE))
else
var/new_name = pick(pick(GLOB.first_names_male,GLOB.first_names_female))
new_name += " "
new_name += pick(GLOB.last_names)
. += new_name
if(2)
. += pick(get_all_jobs())//Returns a job.
safety -= 1
if(2)
switch(rand(1,3))//Food, drinks, or things. Only selectable once.
if(1)
. += lowertext(pick(drinks))
if(2)
. += lowertext(pick(foods))
if(3)
. += lowertext(pick(locations))
safety -= 2
if(3)
switch(rand(1,4))//Abstract nouns, objects, adjectives, threats. Can be selected more than once.
if(1)
. += lowertext(pick(nouns))
if(2)
. += lowertext(pick(objects))
if(3)
. += lowertext(pick(adjectives))
if(4)
. += lowertext(pick(threats))
if(!return_list)
if(words==1)
. += "."
else
. += ", "
+152 -27
View File
@@ -19,7 +19,7 @@
return copytext(sqltext, 2, lentext(sqltext));//Quote() adds quotes around input, we already do that
/proc/format_table_name(table as text)
return global.sqlfdbktableprefix + table
return CONFIG_GET(string/feedback_tableprefix) + table
/*
* Text sanitization
@@ -414,34 +414,159 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
end = temp
return end
/proc/parsepencode(t, mob/user=null, signfont=SIGNFONT)
if(length(t) < 1) //No input means nothing needs to be parsed
/proc/parsemarkdown_basic_step1(t, limited=FALSE)
if(length(t) <= 0)
return
t = replacetext(t, "\[center\]", "<center>")
t = replacetext(t, "\[/center\]", "</center>")
t = replacetext(t, "\[br\]", "<BR>")
t = replacetext(t, "\[b\]", "<B>")
t = replacetext(t, "\[/b\]", "</B>")
t = replacetext(t, "\[i\]", "<I>")
t = replacetext(t, "\[/i\]", "</I>")
t = replacetext(t, "\[u\]", "<U>")
t = replacetext(t, "\[/u\]", "</U>")
t = replacetext(t, "\[large\]", "<font size=\"4\">")
t = replacetext(t, "\[/large\]", "</font>")
if(user)
t = replacetext(t, "\[sign\]", "<font face=\"[signfont]\"><i>[user.real_name]</i></font>")
else
t = replacetext(t, "\[sign\]", "")
t = replacetext(t, "\[field\]", "<span class=\"paper_field\"></span>")
// This parses markdown with no custom rules
t = replacetext(t, "\[*\]", "<li>")
t = replacetext(t, "\[hr\]", "<HR>")
t = replacetext(t, "\[small\]", "<font size = \"1\">")
t = replacetext(t, "\[/small\]", "</font>")
t = replacetext(t, "\[list\]", "<ul>")
t = replacetext(t, "\[/list\]", "</ul>")
// Escape backslashed
t = replacetext(t, "$", "$-")
t = replacetext(t, "\\\\", "$1")
t = replacetext(t, "\\**", "$2")
t = replacetext(t, "\\*", "$3")
t = replacetext(t, "\\__", "$4")
t = replacetext(t, "\\_", "$5")
t = replacetext(t, "\\^", "$6")
t = replacetext(t, "\\((", "$7")
t = replacetext(t, "\\))", "$8")
t = replacetext(t, "\\|", "$9")
t = replacetext(t, "\\%", "$0")
// Escape single characters that will be used
t = replacetext(t, "!", "$a")
// Parse hr and small
if(!limited)
t = replacetext(t, "((", "<font size=\"1\">")
t = replacetext(t, "))", "</font>")
t = replacetext(t, regex("(-){3,}", "gm"), "<hr>")
t = replacetext(t, regex("^\\((-){3,}\\)$", "gm"), "$1")
// Parse lists
var/list/tlist = splittext(t, "\n")
var/tlistlen = tlist.len
var/listlevel = -1
var/singlespace = -1 // if 0, double spaces are used before asterisks, if 1, single are
for(var/i = 1, i <= tlistlen, i++)
var/line = tlist[i]
var/count_asterisk = length(replacetext(line, regex("\[^\\*\]+", "g"), ""))
if(count_asterisk % 2 == 1 && findtext(line, regex("^\\s*\\*", "g"))) // there is an extra asterisk in the beggining
var/count_w = length(replacetext(line, regex("^( *)\\*.*$", "g"), "$1")) // whitespace before asterisk
line = replacetext(line, regex("^ *(\\*.*)$", "g"), "$1")
if(singlespace == -1 && count_w == 2)
if(listlevel == 0)
singlespace = 0
else
singlespace = 1
if(singlespace == 0)
count_w = count_w % 2 ? round(count_w / 2 + 0.25) : count_w / 2
line = replacetext(line, regex("\\*", ""), "<li>")
while(listlevel < count_w)
line = "<ul>" + line
listlevel++
while(listlevel > count_w)
line = "</ul>" + line
listlevel--
else while(listlevel >= 0)
line = "</ul>" + line
listlevel--
tlist[i] = line
// end for
t = tlist[1]
for(var/i = 2, i <= tlistlen, i++)
t += "\n" + tlist[i]
while(listlevel >= 0)
t += "</ul>"
listlevel--
else
t = replacetext(t, "((", "")
t = replacetext(t, "))", "")
// Parse headers
t = replacetext(t, regex("^#(?!#) ?(.+)$", "gm"), "<h2>$1</h2>")
t = replacetext(t, regex("^##(?!#) ?(.+)$", "gm"), "<h3>$1</h3>")
t = replacetext(t, regex("^###(?!#) ?(.+)$", "gm"), "<h4>$1</h4>")
t = replacetext(t, regex("^#### ?(.+)$", "gm"), "<h5>$1</h5>")
// Parse most rules
t = replacetext(t, regex("\\*(\[^\\*\]*)\\*", "g"), "<i>$1</i>")
t = replacetext(t, regex("_(\[^_\]*)_", "g"), "<i>$1</i>")
t = replacetext(t, "<i></i>", "!")
t = replacetext(t, "</i><i>", "!")
t = replacetext(t, regex("\\!(\[^\\!\]+)\\!", "g"), "<b>$1</b>")
t = replacetext(t, regex("\\^(\[^\\^\]+)\\^", "g"), "<font size=\"4\">$1</font>")
t = replacetext(t, regex("\\|(\[^\\|\]+)\\|", "g"), "<center>$1</center>")
t = replacetext(t, "!", "</i><i>")
return t
/proc/parsemarkdown_basic_step2(t)
if(length(t) <= 0)
return
// Restore the single characters used
t = replacetext(t, "$a", "!")
// Redo the escaping
t = replacetext(t, "$1", "\\")
t = replacetext(t, "$2", "**")
t = replacetext(t, "$3", "*")
t = replacetext(t, "$4", "__")
t = replacetext(t, "$5", "_")
t = replacetext(t, "$6", "^")
t = replacetext(t, "$7", "((")
t = replacetext(t, "$8", "))")
t = replacetext(t, "$9", "|")
t = replacetext(t, "$0", "%")
t = replacetext(t, "$-", "$")
return t
/proc/parsemarkdown_basic(t, limited=FALSE)
t = parsemarkdown_basic_step1(t, limited)
t = parsemarkdown_basic_step2(t)
return t
/proc/parsemarkdown(t, mob/user=null, limited=FALSE)
if(length(t) <= 0)
return
// Premanage whitespace
t = replacetext(t, regex("\[^\\S\\r\\n \]", "g"), " ")
t = parsemarkdown_basic_step1(t)
t = replacetext(t, regex("%s(?:ign)?(?=\\s|$)", "igm"), user ? "<font face=\"[SIGNFONT]\"><i>[user.real_name]</i></font>" : "<span class=\"paper_field\"></span>")
t = replacetext(t, regex("%f(?:ield)?(?=\\s|$)", "igm"), "<span class=\"paper_field\"></span>")
t = parsemarkdown_basic_step2(t)
// Manage whitespace
t = replacetext(t, regex("(?:\\r\\n?|\\n)", "g"), "<br>")
t = replacetext(t, " ", "&nbsp;&nbsp;")
// Done
return t
@@ -469,7 +594,7 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
//in the json file and have it be reflected in the in game item/mob it came from.
//(That's what things like savefiles are for) Note that this list is not shuffled.
/proc/twitterize(list/proposed, filename, cullshort = 1, storemax = 1000)
if(!islist(proposed) || !filename || !config.log_twitter)
if(!islist(proposed) || !filename || !CONFIG_GET(flag/log_twitter))
return
//Regular expressions are, as usual, absolute magic
+21
View File
@@ -554,3 +554,24 @@
else
return /datum
return text2path(copytext(string_type, 1, last_slash))
//returns a string the last bit of a type, without the preceeding '/'
/proc/type2top(the_type)
//handle the builtins manually
if(!ispath(the_type))
return
switch(the_type)
if(/datum)
return "datum"
if(/atom)
return "atom"
if(/obj)
return "obj"
if(/mob)
return "mob"
if(/area)
return "area"
if(/turf)
return "turf"
else //regex everything else (works for /proc too)
return lowertext(replacetext("[the_type]", "[type2parent(the_type)]/", ""))
+7 -80
View File
@@ -502,28 +502,12 @@ Turf and target are separate in case you want to teleport some distance from a t
var/y=arcsin(x/sqrt(1+x*x))
return y
/atom/proc/GetAllContents(list/ignore_typecache)
var/list/processing_list = list(src)
var/list/assembled = list()
if(ignore_typecache) //If there's a typecache, use it.
while(processing_list.len)
var/atom/A = processing_list[1]
processing_list -= A
if(ignore_typecache[A.type])
continue
processing_list |= (A.contents - assembled)
assembled |= A
else //If there's none, only make this check once for performance.
while(processing_list.len)
var/atom/A = processing_list[1]
processing_list -= A
processing_list |= (A.contents - assembled)
assembled |= A
return assembled
/atom/proc/GetAllContents(list/output=list())
. = output
output += src
for(var/i in 1 to contents.len)
var/atom/thing = contents[i]
thing.GetAllContents(output)
//Step-towards method of determining whether one atom can see another. Similar to viewers()
/proc/can_see(atom/source, atom/target, length=5) // I couldnt be arsed to do actual raycasting :I This is horribly inaccurate.
@@ -1282,7 +1266,7 @@ proc/pick_closest_path(value, list/matches = get_fancy_list_of_atom_types())
#define QDEL_LIST(L) if(L) { for(var/I in L) qdel(I); L.Cut(); }
#define QDEL_LIST_IN(L, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/______qdel_list_wrapper, L), time, TIMER_STOPPABLE)
#define QDEL_LIST_ASSOC(L) if(L) { for(var/I in L) { qdel(L[I]); qdel(I); } L.Cut(); }
#define QDEL_LIST_ASSOC_VAL(L) if(L) { for(var/I in L) qel(L[I]); L.Cut(); }
#define QDEL_LIST_ASSOC_VAL(L) if(L) { for(var/I in L) qdel(L[I]); L.Cut(); }
/proc/______qdel_list_wrapper(list/L) //the underscores are to encourage people not to use this directly.
QDEL_LIST(L)
@@ -1380,63 +1364,6 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
return FALSE
return TRUE
//WHATEVER YOU USE THIS FOR MUST BE SANITIZED TO SHIT, IT USES SHELL
//It also sleeps
//Set this to TRUE before calling
//This prevents RCEs from badmins
//kevinz000 if you touch this I will hunt you down
GLOBAL_VAR_INIT(valid_HTTPSGet, FALSE)
GLOBAL_PROTECT(valid_HTTPSGet)
/proc/HTTPSGet(url) //tgs2 support
if(findtext(url, "\""))
GLOB.valid_HTTPSGet = FALSE
if(!GLOB.valid_HTTPSGet)
if(usr)
CRASH("[usr.ckey]([usr]) just attempted an invalid HTTPSGet on: [url]!")
else
CRASH("Invalid HTTPSGet call on: [url]")
GLOB.valid_HTTPSGet = FALSE
//"This has got to be the ugliest hack I have ever done"
//warning, here be dragons
/*
| @___oo
/\ /\ / (__,,,,|
) /^\) ^\/ _)
) /^\/ _)
) _ / / _)
/\ )/\/ || | )_)
< > |(,,) )__)
|| / \)___)\
| \____( )___) )___
\______(_______;;; __;;;
*/
var/temp_file = "data/HTTPSGetOutput.txt"
var/command
if(world.system_type == MS_WINDOWS)
command = "powershell -Command \"wget [url] -OutFile [temp_file]\""
else if(world.system_type == UNIX)
command = "wget -O [temp_file] [url]"
else
CRASH("Invalid world.system_type ([world.system_type])? Yell at Lummox.")
log_world("HTTPSGet: [url]")
var/result = shell(command)
if(result != 0)
log_world("Download failed: shell exited with code: [result]")
return
var/f = file(temp_file)
if(!f)
log_world("Download failed: Temp file not found")
return
. = file2text(f)
f = null
fdel(temp_file)
#define UNTIL(X) while(!(X)) stoplag()
/proc/pass()
+1 -1
View File
@@ -33,7 +33,7 @@
#define MAX_CHARTER_LEN 80
//MINOR TWEAKS/MISC
#define AGE_MIN 17 //youngest a character can be
#define AGE_MIN 18 //youngest a character can be
#define AGE_MAX 85 //oldest a character can be
#define WIZARD_AGE_MIN 30 //youngest a wizard can be
#define SHOES_SLOWDOWN 0 //How much shoes slow you down by default. Negative values speed you up
+7 -3
View File
@@ -1,4 +1,4 @@
GLOBAL_REAL(config, /datum/configuration)
GLOBAL_REAL(config, /datum/controller/configuration)
GLOBAL_DATUM_INIT(revdata, /datum/getrev, new)
@@ -11,9 +11,7 @@ GLOBAL_VAR_INIT(hub_visibility, FALSE)
GLOBAL_VAR_INIT(ooc_allowed, TRUE) // used with admin verbs to disable ooc - not a config option apparently
GLOBAL_VAR_INIT(dooc_allowed, TRUE)
GLOBAL_VAR_INIT(abandon_allowed, TRUE)
GLOBAL_VAR_INIT(enter_allowed, TRUE)
GLOBAL_VAR_INIT(guests_allowed, TRUE)
GLOBAL_VAR_INIT(shuttle_frozen, FALSE)
GLOBAL_VAR_INIT(shuttle_left, FALSE)
GLOBAL_VAR_INIT(tinted_weldhelh, TRUE)
@@ -25,10 +23,16 @@ GLOBAL_VAR_INIT(Debug, FALSE) // global debug switch
GLOBAL_VAR_INIT(Debug2, FALSE)
//This was a define, but I changed it to a variable so it can be changed in-game.(kept the all-caps definition because... code...) -Errorage
//Protecting these because the proper way to edit them is with the config/secrets
GLOBAL_VAR_INIT(MAX_EX_DEVESTATION_RANGE, 3)
GLOBAL_PROTECT(MAX_EX_DEVESTATION_RANGE)
GLOBAL_VAR_INIT(MAX_EX_HEAVY_RANGE, 7)
GLOBAL_PROTECT(MAX_EX_HEAVY_RANGE)
GLOBAL_VAR_INIT(MAX_EX_LIGHT_RANGE, 14)
GLOBAL_PROTECT(MAX_EX_LIGHT_RANGE)
GLOBAL_VAR_INIT(MAX_EX_FLASH_RANGE, 14)
GLOBAL_PROTECT(MAX_EX_FLASH_RANGE)
GLOBAL_VAR_INIT(MAX_EX_FLAME_RANGE, 14)
GLOBAL_PROTECT(MAX_EX_FLAME_RANGE)
GLOBAL_VAR_INIT(DYN_EX_SCALE, 0.5)
+4
View File
@@ -33,6 +33,8 @@ GLOBAL_LIST_EMPTY(department_security_spawns) //list of all department security
GLOBAL_LIST_EMPTY(generic_event_spawns) //list of all spawns for events
GLOBAL_LIST_EMPTY(wizardstart)
GLOBAL_LIST_EMPTY(nukeop_start)
GLOBAL_LIST_EMPTY(nukeop_leader_start)
GLOBAL_LIST_EMPTY(newplayer_start)
GLOBAL_LIST_EMPTY(prisonwarp) //prisoners go to these
GLOBAL_LIST_EMPTY(holdingfacility) //captured people go here
@@ -46,6 +48,8 @@ GLOBAL_LIST_EMPTY(blobstart)
GLOBAL_LIST_EMPTY(secequipment)
GLOBAL_LIST_EMPTY(deathsquadspawn)
GLOBAL_LIST_EMPTY(emergencyresponseteamspawn)
GLOBAL_LIST_EMPTY(servant_spawns) //Servants of Ratvar spawn here
GLOBAL_LIST_EMPTY(city_of_cogs_spawns) //Anyone entering the City of Cogs spawns here
GLOBAL_LIST_EMPTY(ruin_landmarks)
//away missions
-16
View File
@@ -1,16 +0,0 @@
//Server API key
GLOBAL_REAL_VAR(comms_key) = "default_pwd"
GLOBAL_REAL_VAR(comms_allowed) = FALSE //By default, the server does not allow messages to be sent to it, unless the key is strong enough (this is to prevent misconfigured servers from becoming vulnerable)
GLOBAL_REAL_VAR(medal_hub)
GLOBAL_REAL_VAR(medal_pass) = " "
GLOBAL_REAL_VAR(medals_enabled) = TRUE //will be auto set to false if the game fails contacting the medal hub to prevent unneeded calls.
// MySQL configuration
GLOBAL_REAL_VAR(sqladdress) = "localhost"
GLOBAL_REAL_VAR(sqlport) = "3306"
GLOBAL_REAL_VAR(sqlfdbkdb) = "test"
GLOBAL_REAL_VAR(sqlfdbklogin) = "root"
GLOBAL_REAL_VAR(sqlfdbkpass) = ""
GLOBAL_REAL_VAR(sqlfdbktableprefix) = ""
+20 -109
View File
@@ -378,90 +378,6 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
/obj/screen/alert/clockwork
alerttooltipstyle = "clockcult"
/obj/screen/alert/clockwork/scripture_reqs
name = "Next Tier Requirements"
desc = "You shouldn't be seeing this description unless you're very fast. If you're very fast, good job!"
icon_state = "no-servants-caches"
/obj/screen/alert/clockwork/scripture_reqs/Initialize()
. = ..()
START_PROCESSING(SSprocessing, src)
process()
/obj/screen/alert/clockwork/scripture_reqs/Destroy()
STOP_PROCESSING(SSprocessing, src)
return ..()
/obj/screen/alert/clockwork/scripture_reqs/process()
if(GLOB.clockwork_gateway_activated)
mob_viewer.clear_alert("scripturereq")
return
var/current_state
for(var/i in SSticker.scripture_states)
if(!SSticker.scripture_states[i])
current_state = i
break
icon_state = "no"
if(!current_state)
name = "Current Objective"
for(var/obj/structure/destructible/clockwork/massive/celestial_gateway/G in GLOB.all_clockwork_objects)
var/area/gate_area = get_area(G)
desc = "<b>Protect the Ark at [gate_area.map_name]!</b>"
return
desc = "<b>All tiers of Scripture are unlocked.<br>\
Acquire components and summon the Ark.</b>"
else
name = "Next Tier Requirements"
var/validservants = 0
var/unconverted_ais_exist = get_unconverted_ais()
for(var/mob/living/L in GLOB.living_mob_list)
if(is_servant_of_ratvar(L) && (ishuman(L) || issilicon(L)))
validservants++
var/req_servants = 0
var/req_caches = 0
var/req_cv = 0
var/req_ai = FALSE
var/list/textlist = list("Requirements for <b>[current_state] Scripture:</b>")
switch(current_state) //get our requirements based on the tier
if(SCRIPTURE_SCRIPT)
req_servants = SCRIPT_SERVANT_REQ
req_caches = SCRIPT_CACHE_REQ
if(SCRIPTURE_APPLICATION)
req_servants = APPLICATION_SERVANT_REQ
req_caches = APPLICATION_CACHE_REQ
req_cv = APPLICATION_CV_REQ
if(SCRIPTURE_JUDGEMENT)
req_servants = JUDGEMENT_SERVANT_REQ
req_caches = JUDGEMENT_CACHE_REQ
req_cv = JUDGEMENT_CV_REQ
req_ai = TRUE
textlist += "<br><b>[validservants]/[req_servants]</b> Servants"
if(validservants < req_servants)
icon_state += "-servants" //in this manner, generate an icon key based on what we're missing
else
textlist += ": <b><font color=#5A6068>\[CHECK\]</font></b>"
textlist += "<br><b>[GLOB.clockwork_caches]/[req_caches]</b> Tinkerer's Caches"
if(GLOB.clockwork_caches < req_caches)
icon_state += "-caches"
else
textlist += ": <b><font color=#5A6068>\[CHECK\]</font></b>"
if(req_cv) //cv only shows up if the tier requires it
textlist += "<br><b>[GLOB.clockwork_construction_value]/[req_cv]</b> Construction Value"
if(GLOB.clockwork_construction_value < req_cv)
icon_state += "-cv"
else
textlist += ": <b><font color=#5A6068>\[CHECK\]</font></b>"
if(req_ai) //same for ai
if(unconverted_ais_exist)
if(unconverted_ais_exist > 1)
textlist += "<br><b>[unconverted_ais_exist] unconverted AIs exist!</b><br>"
else
textlist += "<br><b>An unconverted AI exists!</b>"
icon_state += "-ai"
else
textlist += "<br>No unconverted AIs exist: <b><font color=#5A6068>\[CHECK\]</font></b>"
desc = textlist.Join()
/obj/screen/alert/clockwork/infodump
name = "Global Records"
desc = "You shouldn't be seeing this description, because it should be dynamically generated."
@@ -473,7 +389,6 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
else
var/servants = 0
var/validservants = 0
var/unconverted_ais_exist = get_unconverted_ais()
var/list/textlist
for(var/mob/living/L in GLOB.living_mob_list)
if(is_servant_of_ratvar(L))
@@ -487,29 +402,25 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
textlist = list("<b>[servants]</b> Servants, [validservants ? "<b>[validservants]</b> of which counts":"none of which count"] towards scripture.<br>")
else
textlist = list("<b>[servants]</b> Servant, who [validservants ? "counts":"does not count"] towards scripture.<br>")
textlist += "<b>[GLOB.clockwork_caches ? "[GLOB.clockwork_caches]</b> Tinkerer's Caches.":"No Tinkerer's Caches, construct one!</b>"]<br>\
<b>[GLOB.clockwork_construction_value]</b> Construction Value.<br>"
textlist += "<b>[Floor(servants * 0.2)]</b> Tinkerer's Daemons can be active at once. <b>[LAZYLEN(GLOB.active_daemons)]</b> are active.<br>"
for(var/obj/structure/destructible/clockwork/massive/celestial_gateway/G in GLOB.all_clockwork_objects)
var/area/gate_area = get_area(G)
textlist += "Ark Location: <b>[uppertext(gate_area.map_name)]</b><br>"
if(G.still_needs_components())
textlist += "Ark Components required:<br>"
for(var/i in G.required_components)
if(G.required_components[i])
textlist += "[get_component_icon(i)] <b><font color=[get_component_color_bright(i)]>[G.required_components[i]]</font></b> "
textlist += "<br>"
else
textlist += "Seconds until Ratvar's arrival: <b>[G.get_arrival_text(TRUE)]</b><br>"
break
if(unconverted_ais_exist)
if(unconverted_ais_exist > 1)
textlist += "<b>[unconverted_ais_exist] unconverted AIs exist!</b><br>"
else
textlist += "<b>An unconverted AI exists!</b><br>"
for(var/i in SSticker.scripture_states)
if(i != SCRIPTURE_DRIVER) //ignore the always-unlocked stuff
textlist += "[i] Scripture: <b>[SSticker.scripture_states[i] ? "UNLOCKED":"LOCKED"]</b><br>"
for(var/i in SSticker.scripture_states)
if(i != SCRIPTURE_DRIVER) //ignore the always-unlocked stuff
textlist += "[i] Scripture: <b>[SSticker.scripture_states[i] ? "UNLOCKED":"LOCKED"]</b><br>"
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
if(G)
var/time_info
var/time_name
if(G.seconds_until_activation)
time_info = G.seconds_until_activation
time_name = "until the Ark activates"
else if(G.grace_period)
time_info = G.grace_period
time_name = "of grace period remaining"
else if(G.progress_in_seconds)
time_info = GATEWAY_RATVAR_ARRIVAL - G.progress_in_seconds
time_name = "until the Ark finishes summoning"
if(time_info)
textlist += "<b>[time_info / 60] minutes</b> [time_name].<br>"
textlist += "<b>[DisplayPower(get_clockwork_power())]</b> power available for use."
desc = textlist.Join()
..()
@@ -627,7 +538,7 @@ so as to remain in compliance with the most up-to-date laws."
if(NOTIFY_JUMP)
var/turf/T = get_turf(target)
if(T && isturf(T))
G.loc = T
G.forceMove(T)
if(NOTIFY_ORBIT)
G.ManualFollow(target)
-45
View File
@@ -1,45 +0,0 @@
/datum/hud/marauder
var/obj/screen/hosthealth
var/obj/screen/blockchance
var/obj/screen/counterchance
/datum/hud/marauder/New(mob/living/simple_animal/hostile/guardian/owner)
..()
var/obj/screen/using
healths = new /obj/screen/healths/clock()
infodisplay += healths
hosthealth = new /obj/screen/healths/clock()
hosthealth.screen_loc = ui_internal
infodisplay += hosthealth
using = new /obj/screen/marauder/emerge()
using.screen_loc = ui_zonesel
static_inventory += using
/datum/hud/marauder/Destroy()
blockchance = null
counterchance = null
hosthealth = null
return ..()
/mob/living/simple_animal/hostile/clockwork/marauder/create_mob_hud()
if(client && !hud_used)
hud_used = new /datum/hud/marauder(src, ui_style2icon(client.prefs.UI_style))
/obj/screen/marauder
icon = 'icons/mob/clockwork_mobs.dmi'
/obj/screen/marauder/emerge
icon_state = "marauder_emerge"
name = "Emerge/Return"
desc = "Emerge or Return."
/obj/screen/marauder/emerge/Click()
if(istype(usr, /mob/living/simple_animal/hostile/clockwork/marauder))
var/mob/living/simple_animal/hostile/clockwork/marauder/M = usr
if(M.is_in_host())
M.try_emerge()
else
M.return_to_host()
+91 -104
View File
@@ -1,104 +1,91 @@
/mob/dead/observer/DblClickOn(var/atom/A, var/params)
if(client.click_intercept)
if(call(client.click_intercept,"InterceptClickOn")(src,params,A))
return
if(can_reenter_corpse && mind && mind.current)
if(A == mind.current || (mind.current in A)) // double click your corpse or whatever holds it
reenter_corpse() // (cloning scanner, body bag, closet, mech, etc)
return // seems legit.
// Things you might plausibly want to follow
if(ismovableatom(A))
ManualFollow(A)
// Otherwise jump
else if(A.loc)
loc = get_turf(A)
update_parallax_contents()
/mob/dead/observer/ClickOn(var/atom/A, var/params)
if(client.click_intercept)
if(call(client.click_intercept,"InterceptClickOn")(src,params,A))
return
var/list/modifiers = params2list(params)
if(modifiers["shift"] && modifiers["middle"])
ShiftMiddleClickOn(A)
return
if(modifiers["shift"] && modifiers["ctrl"])
CtrlShiftClickOn(A)
return
if(modifiers["middle"])
MiddleClickOn(A)
return
if(modifiers["shift"])
ShiftClickOn(A)
return
if(modifiers["alt"])
AltClickOn(A)
return
if(modifiers["ctrl"])
CtrlClickOn(A)
return
if(world.time <= next_move)
return
// You are responsible for checking config.ghost_interaction when you override this function
// Not all of them require checking, see below
A.attack_ghost(src)
// Oh by the way this didn't work with old click code which is why clicking shit didn't spam you
/atom/proc/attack_ghost(mob/dead/observer/user)
if(user.client)
if(IsAdminGhost(user))
attack_ai(user)
if(user.client.prefs.inquisitive_ghost)
user.examinate(src)
// ---------------------------------------
// And here are some good things for free:
// Now you can click through portals, wormholes, gateways, and teleporters while observing. -Sayu
/obj/machinery/teleport/hub/attack_ghost(mob/user)
var/atom/l = loc
var/obj/machinery/computer/teleporter/com = locate(/obj/machinery/computer/teleporter, locate(l.x - 2, l.y, l.z))
if(com && com.locked)
user.forceMove(get_turf(com.locked))
/obj/effect/portal/attack_ghost(mob/user)
if(linked)
user.forceMove(get_turf(linked))
/obj/machinery/gateway/centerstation/attack_ghost(mob/user)
if(awaygate)
user.forceMove(awaygate.loc)
else
to_chat(user, "[src] has no destination.")
/obj/machinery/gateway/centeraway/attack_ghost(mob/user)
if(stationgate)
user.forceMove(stationgate.loc)
else
to_chat(user, "[src] has no destination.")
/obj/item/storage/attack_ghost(mob/user)
orient2hud(user)
show_to(user)
/obj/machinery/teleport/hub/attack_ghost(mob/user)
if(power_station && power_station.engaged && power_station.teleporter_console && power_station.teleporter_console.target)
user.forceMove(get_turf(power_station.teleporter_console.target))
// -------------------------------------------
// This was supposed to be used by adminghosts
// I think it is a *terrible* idea
// but I'm leaving it here anyway
// commented out, of course.
/*
/atom/proc/attack_admin(mob/user as mob)
if(!user || !user.client || !user.client.holder)
return
attack_hand(user)
*/
/mob/dead/observer/DblClickOn(var/atom/A, var/params)
if(client.click_intercept)
if(call(client.click_intercept,"InterceptClickOn")(src,params,A))
return
if(can_reenter_corpse && mind && mind.current)
if(A == mind.current || (mind.current in A)) // double click your corpse or whatever holds it
reenter_corpse() // (cloning scanner, body bag, closet, mech, etc)
return // seems legit.
// Things you might plausibly want to follow
if(ismovableatom(A))
ManualFollow(A)
// Otherwise jump
else if(A.loc)
loc = get_turf(A)
update_parallax_contents()
/mob/dead/observer/ClickOn(var/atom/A, var/params)
if(client.click_intercept)
if(call(client.click_intercept,"InterceptClickOn")(src,params,A))
return
var/list/modifiers = params2list(params)
if(modifiers["shift"] && modifiers["middle"])
ShiftMiddleClickOn(A)
return
if(modifiers["shift"] && modifiers["ctrl"])
CtrlShiftClickOn(A)
return
if(modifiers["middle"])
MiddleClickOn(A)
return
if(modifiers["shift"])
ShiftClickOn(A)
return
if(modifiers["alt"])
AltClickOn(A)
return
if(modifiers["ctrl"])
CtrlClickOn(A)
return
if(world.time <= next_move)
return
// You are responsible for checking config.ghost_interaction when you override this function
// Not all of them require checking, see below
A.attack_ghost(src)
// Oh by the way this didn't work with old click code which is why clicking shit didn't spam you
/atom/proc/attack_ghost(mob/dead/observer/user)
if(user.client)
if(IsAdminGhost(user))
attack_ai(user)
if(user.client.prefs.inquisitive_ghost)
user.examinate(src)
// ---------------------------------------
// And here are some good things for free:
// Now you can click through portals, wormholes, gateways, and teleporters while observing. -Sayu
/obj/machinery/teleport/hub/attack_ghost(mob/user)
var/atom/l = loc
var/obj/machinery/computer/teleporter/com = locate(/obj/machinery/computer/teleporter, locate(l.x - 2, l.y, l.z))
if(com && com.locked)
user.forceMove(get_turf(com.locked))
/obj/effect/portal/attack_ghost(mob/user)
if(linked)
user.forceMove(get_turf(linked))
/obj/machinery/gateway/centerstation/attack_ghost(mob/user)
if(awaygate)
user.forceMove(awaygate.loc)
else
to_chat(user, "[src] has no destination.")
/obj/machinery/gateway/centeraway/attack_ghost(mob/user)
if(stationgate)
user.forceMove(stationgate.loc)
else
to_chat(user, "[src] has no destination.")
/obj/item/storage/attack_ghost(mob/user)
orient2hud(user)
show_to(user)
/obj/machinery/teleport/hub/attack_ghost(mob/user)
if(power_station && power_station.engaged && power_station.teleporter_console && power_station.teleporter_console.target)
user.forceMove(get_turf(power_station.teleporter_console.target))
+1 -1
View File
@@ -92,7 +92,7 @@
/obj/item/tk_grab/dropped(mob/user)
if(focus && user && loc != user && loc != user.loc) // drop_item() gets called when you tk-attack a table/closet with an item
if(focus.Adjacent(loc))
focus.loc = loc
focus.forceMove(loc)
. = ..()
//stops TK grabs being equipped anywhere but into hands
+435 -5
View File
@@ -172,6 +172,27 @@
spread = 30 //should be 40 for XCOM memes, but since its adminspawn only, might as well make it useable
recoil = 1
///toy memes///
/obj/item/ammo_box/magazine/toy/x9
name = "foam force X9 magazine"
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "toy9magazine"
max_ammo = 30
multiple_sprites = 2
/obj/item/gun/ballistic/automatic/x9/toy
name = "donksoft X9"
desc = "An old but reliable assault rifle made for combat against unknown enemies. Appears to be hastily converted. Ages 8 and up."
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "toy9"
can_suppress = 0
needs_permit = 0
mag_type = /obj/item/ammo_box/magazine/toy/x9
casing_ejector = 0
spread = 45 //MAXIMUM XCOM MEMES (actually that'd be 90 spread)
////////XCOM2 Magpistol/////////
//////projectiles//////
@@ -213,7 +234,7 @@
//////magazines/////
/obj/item/ammo_box/magazine/mmags
/obj/item/ammo_box/magazine/mmag/small
name = "magpistol magazine (non-lethal disabler)"
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "nlmagmag"
@@ -223,7 +244,7 @@
max_ammo = 7
multiple_sprites = 2
/obj/item/ammo_box/magazine/mmags/lethal
/obj/item/ammo_box/magazine/mmag/small/lethal
name = "magpistol magazine (lethal)"
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "smallmagmag"
@@ -239,7 +260,7 @@
icon_state = "magpistol"
force = 10
fire_sound = 'sound/weapons/magpistol.ogg'
mag_type = /obj/item/ammo_box/magazine/mmags
mag_type = /obj/item/ammo_box/magazine/mmag/small
can_suppress = 0
casing_ejector = 0
fire_delay = 5
@@ -276,7 +297,7 @@
req_tech = list("combat" = 5, "magnets" = 6, "materials" = 5, "syndicate" = 3)
build_type = PROTOLATHE
materials = list(MAT_METAL = 4000, MAT_SILVER = 500)
build_path = /obj/item/ammo_box/magazine/mmags/lethal
build_path = /obj/item/ammo_box/magazine/mmag/small/lethal
category = list("Ammo")
/datum/design/mag_magpistol/nl
@@ -285,7 +306,7 @@
id = "mag_magpistol_nl"
req_tech = list("combat" = 5, "magnets" = 6, "materials" = 5)
materials = list(MAT_METAL = 3000, MAT_SILVER = 250, MAT_TITANIUM = 250)
build_path = /obj/item/ammo_box/magazine/mmags
build_path = /obj/item/ammo_box/magazine/mmag/small
//////toy memes/////
@@ -339,3 +360,412 @@
materials = list(MAT_METAL = 7500, MAT_GLASS = 1000)
build_path = /obj/item/gun/ballistic/shotgun/toy/mag
category = list("hacked", "Misc")
//////Magrifle//////
///projectiles///
/obj/item/projectile/bullet/magrifle
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "magjectile-large"
damage = 30
armour_penetration = 25
light_range = 3
light_color = LIGHT_COLOR_RED
/obj/item/projectile/bullet/nlmagrifle //non-lethal boolets
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "magjectile-large-nl"
damage = 5
knockdown = 30
stamina = 75
armour_penetration = 0
light_range = 3
light_color = LIGHT_COLOR_BLUE
///ammo casings///
/obj/item/ammo_casing/caseless/amagm
desc = "A large ferromagnetic slug intended to be launched out of a compatible weapon."
caliber = "magm"
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "mag-casing-live"
projectile_type = /obj/item/projectile/bullet/magrifle
/obj/item/ammo_casing/caseless/anlmagm
desc = "A large, specialized ferromagnetic slug designed with a less-than-lethal payload."
caliber = "magm"
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "mag-casing-live"
projectile_type = /obj/item/projectile/bullet/nlmagrifle
///magazines///
/obj/item/ammo_box/magazine/mmag/
name = "magrifle magazine (non-lethal disabler)"
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "mediummagmag"
origin_tech = "magnets=6"
ammo_type = /obj/item/ammo_casing/caseless/anlmagm
caliber = "magm"
max_ammo = 15
multiple_sprites = 2
/obj/item/ammo_box/magazine/mmag/lethal
name = "magrifle magazine (lethal)"
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "mediummagmag"
origin_tech = "combat=6"
ammo_type = /obj/item/ammo_casing/caseless/amagm
///the gun itself///
/obj/item/gun/ballistic/automatic/magrifle
name = "\improper Magnetic Rifle"
desc = "A simple upscalling of the technologies used in the magpistol, the magrifle is capable of firing slightly larger slugs in bursts. Compatible with the magpistol's slugs."
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "magrifle"
item_state = "arg"
slot_flags = 0
origin_tech = "combat=6;engineering=6;magnets=6"
mag_type = /obj/item/ammo_box/magazine/mmag
fire_sound = 'sound/weapons/magrifle.ogg'
can_suppress = 0
burst_size = 3
fire_delay = 2
spread = 15
recoil = 1
casing_ejector = 0
///research///
/obj/item/gun/ballistic/automatic/magrifle/nopin
pin = null
/datum/design/magrifle
name = "Magrifle"
desc = "An upscaled Magpistol in rifle form."
id = "magrifle"
req_tech = list("combat" = 7, "magnets" = 7, "powerstorage" = 7)
build_type = PROTOLATHE
materials = list(MAT_METAL = 10000, MAT_GLASS = 2000, MAT_URANIUM = 2000, MAT_TITANIUM = 10000, MAT_SILVER = 4000, MAT_GOLD = 2000)
build_path = /obj/item/gun/ballistic/automatic/magrifle/nopin
category = list("Weapons")
/datum/design/mag_magrifle
name = "Magrifle Magazine (Lethal)"
desc = "A 15 round magazine for the Magrifle."
id = "mag_magrifle"
req_tech = list("combat" = 7, "magnets" = 7, "materials" = 5, "syndicate" = 4)
build_type = PROTOLATHE
materials = list(MAT_METAL = 8000, MAT_SILVER = 1000)
build_path = /obj/item/ammo_box/magazine/mmag/lethal
category = list("Ammo")
/datum/design/mag_magrifle/nl
name = "Magrifle Magazine (Non-Lethal)"
desc = "A 15 round non-lethal magazine for the Magrifle."
id = "mag_magrifle_nl"
req_tech = list("combat" = 7, "magnets" = 7, "materials" = 5)
materials = list(MAT_METAL = 6000, MAT_SILVER = 500, MAT_TITANIUM = 500)
build_path = /obj/item/ammo_box/magazine/mmag
//////Hyper-Burst Rifle//////
///projectiles///
/obj/item/projectile/bullet/mags/hyper
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "magjectile"
damage = 10
armour_penetration = 10
stamina = 10
forcedodge = TRUE
range = 6
light_range = 1
light_color = LIGHT_COLOR_RED
/obj/item/projectile/bullet/mags/hyper/inferno
icon_state = "magjectile-large"
stamina = 0
forcedodge = FALSE
range = 25
light_range = 4
/obj/item/projectile/bullet/mags/hyper/inferno/on_hit(atom/target, blocked = FALSE)
..()
explosion(target, -1, 1, 2, 4, 5)
return 1
///ammo casings///
/obj/item/ammo_casing/caseless/ahyper
desc = "A large block of speciallized ferromagnetic material designed to be fired out of the experimental Hyper-Burst Rifle."
caliber = "hypermag"
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "hyper-casing-live"
projectile_type = /obj/item/projectile/bullet/mags/hyper
pellets = 12
variance = 40
/obj/item/ammo_casing/caseless/ahyper/inferno
projectile_type = /obj/item/projectile/bullet/mags/hyper/inferno
pellets = 1
variance = 0
///magazines///
/obj/item/ammo_box/magazine/mhyper
name = "hyper-burst rifle magazine"
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "hypermag-4"
ammo_type = /obj/item/ammo_casing/caseless/ahyper
caliber = "hypermag"
desc = "A magazine for the Hyper-Burst Rifle. Loaded with a special slug that fragments into 12 smaller shards which can absolutely puncture anything, but has rather short effective range."
max_ammo = 4
/obj/item/ammo_box/magazine/mhyper/update_icon()
..()
icon_state = "hypermag-[ammo_count() ? "4" : "0"]"
/obj/item/ammo_box/magazine/mhyper/inferno
name = "hyper-burst rifle magazine (inferno)"
ammo_type = /obj/item/ammo_casing/caseless/ahyper/inferno
desc = "A magazine for the Hyper-Burst Rifle. Loaded with a special slug that violently reacts with whatever surface it strikes, generating a massive amount of heat and light."
///gun itself///
/obj/item/gun/ballistic/automatic/hyperburst
name = "\improper Hyper-Burst Rifle"
desc = "An extremely beefed up version of a stolen Nanotrasen weapon prototype, this 'rifle' is more like a cannon, with an extremely large bore barrel capable of generating several smaller magnetic 'barrels' to simultaneously launch multiple projectiles at once."
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "hyperburst"
item_state = "arg"
slot_flags = 0
origin_tech = "combat=6;engineering=6;magnets=6;syndicate=6"
mag_type = /obj/item/ammo_box/magazine/mhyper
fire_sound = 'sound/weapons/magburst.ogg'
can_suppress = 0
burst_size = 1
fire_delay = 40
recoil = 2
casing_ejector = 0
weapon_weight = WEAPON_HEAVY
/obj/item/gun/ballistic/automatic/hyperburst/update_icon()
..()
icon_state = "hyperburst[magazine ? "-[get_ammo()]" : ""][chambered ? "" : "-e"]"
/* made redundant by reskinnable stetchkins
//////Stealth Pistol//////
/obj/item/gun/ballistic/automatic/pistol/stealth
name = "stealth pistol"
desc = "A unique bullpup pistol with a compact frame. Has an integrated surpressor."
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "stealthpistol"
w_class = WEIGHT_CLASS_SMALL
origin_tech = "combat=3;materials=3;syndicate=4"
mag_type = /obj/item/ammo_box/magazine/m10mm
can_suppress = 0
fire_sound = 'sound/weapons/gunshot_silenced.ogg'
suppressed = 1
burst_size = 1
/obj/item/gun/ballistic/automatic/pistol/stealth/update_icon()
..()
if(magazine)
cut_overlays()
add_overlay("stealthpistol-magazine")
else
cut_overlays()
icon_state = "[initial(icon_state)][chambered ? "" : "-e"]"
*/
//////10mm soporific bullets//////
obj/item/projectile/bullet/c10mm/soporific
name ="10mm soporific bullet"
armour_penetration = 0
nodamage = TRUE
dismemberment = 0
knockdown = 0
/obj/item/projectile/bullet/c10mm/soporific/on_hit(atom/target, blocked = FALSE)
if((blocked != 100) && isliving(target))
var/mob/living/L = target
L.blur_eyes(6)
if(L.staminaloss >= 40)
L.Sleeping(250)
else
L.adjustStaminaLoss(58)
return 1
/obj/item/ammo_casing/c10mm/soporific
name = ".10mm soporific bullet casing"
desc = "A 10mm soporific bullet casing."
projectile_type = /obj/item/projectile/bullet/c10mm/soporific
/obj/item/ammo_box/magazine/m10mm/soporific
name = "pistol magazine (10mm soporific)"
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "9x19pS"
desc = "A gun magazine. Loaded with rounds which inject the target with a variety of illegal substances to induce sleep in the target."
ammo_type = /obj/item/ammo_casing/c10mm/soporific
/obj/item/ammo_box/c10mm/soporific
name = "ammo box (10mm soporific)"
ammo_type = /obj/item/ammo_casing/c10mm/soporific
max_ammo = 24
//////Flechette Launcher//////
///projectiles///
/obj/item/projectile/bullet/cflechetteap //shreds armor
name = "flechette (armor piercing)"
damage = 8
armour_penetration = 80
/obj/item/projectile/bullet/cflechettes //shreds flesh and forces bleeding
name = "flechette (serrated)"
damage = 8
dismemberment = 10
armour_penetration = -80
/obj/item/projectile/bullet/cflechettes/on_hit(atom/target, blocked = FALSE)
if((blocked != 100) && iscarbon(target))
var/mob/living/carbon/C = target
C.bleed(10)
return ..()
///ammo casings (CASELESS AMMO CASINGS WOOOOOOOO)///
/obj/item/ammo_casing/caseless/flechetteap
name = "flechette (armor piercing)"
desc = "A flechette made with a tungsten alloy."
projectile_type = /obj/item/projectile/bullet/cflechetteap
caliber = "flechette"
throwforce = 1
throw_speed = 3
/obj/item/ammo_casing/caseless/flechettes
name = "flechette (serrated)"
desc = "A serrated flechette made of a special alloy intended to deform drastically upon penetration of human flesh."
projectile_type = /obj/item/projectile/bullet/cflechettes
caliber = "flechette"
throwforce = 2
throw_speed = 3
embed_chance = 75
///magazine///
/obj/item/ammo_box/magazine/flechette
name = "flechette magazine (armor piercing)"
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "flechettemag"
origin_tech = "combat=5;syndicate=1"
ammo_type = /obj/item/ammo_casing/caseless/flechetteap
caliber = "flechette"
max_ammo = 40
multiple_sprites = 2
/obj/item/ammo_box/magazine/flechette/s
name = "flechette magazine (serrated)"
ammo_type = /obj/item/ammo_casing/caseless/flechettes
///the gun itself///
/obj/item/gun/ballistic/automatic/flechette
name = "\improper CX Flechette Launcher"
desc = "A flechette launching machine pistol with an unconventional bullpup frame."
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "flechettegun"
item_state = "gun"
w_class = WEIGHT_CLASS_NORMAL
slot_flags = 0
/obj/item/device/firing_pin/implant/pindicate
origin_tech = "combat=6;materials=2;syndicate=5"
mag_type = /obj/item/ammo_box/magazine/flechette/
fire_sound = 'sound/weapons/gunshot_smg.ogg'
can_suppress = 0
burst_size = 5
fire_delay = 1
casing_ejector = 0
spread = 20
/obj/item/gun/ballistic/automatic/flechette/update_icon()
..()
if(magazine)
cut_overlays()
add_overlay("flechettegun-magazine")
else
cut_overlays()
icon_state = "[initial(icon_state)][chambered ? "" : "-e"]"
///unique variant///
/obj/item/projectile/bullet/cflechetteshredder
name = "flechette (shredder)"
damage = 5
dismemberment = 40
/obj/item/ammo_casing/caseless/flechetteshredder
name = "flechette (shredder)"
desc = "A serrated flechette made of a special alloy that forms a monofilament edge."
projectile_type = /obj/item/projectile/bullet/cflechettes
/obj/item/ammo_box/magazine/flechette/shredder
name = "flechette magazine (shredder)"
icon_state = "shreddermag"
ammo_type = /obj/item/ammo_casing/caseless/flechetteshredder
/obj/item/gun/ballistic/automatic/flechette/shredder
name = "\improper CX Shredder"
desc = "A flechette launching machine pistol made of ultra-light CFRP optimized for firing serrated monofillament flechettes."
w_class = WEIGHT_CLASS_SMALL
mag_type = /obj/item/ammo_box/magazine/flechette/shredder
spread = 30
/obj/item/gun/ballistic/automatic/flechette/shredder/update_icon()
..()
if(magazine)
cut_overlays()
add_overlay("shreddergun-magazine")
else
cut_overlays()
icon_state = "[initial(icon_state)][chambered ? "" : "-e"]"
//////modular pistol////// (reskinnable stetchkins)
/obj/item/gun/ballistic/automatic/pistol/modular
name = "modular pistol"
desc = "A small, easily concealable 10mm handgun. Has a threaded barrel for suppressors."
icon = 'icons/obj/guns/cit_guns.dmi'
icon_state = "cde"
can_unsuppress = TRUE
unique_rename = TRUE
unique_reskin = list("Default" = "cde",
"NT-99" = "n99",
"Stealth" = "stealthpistol",
"HKVP-78" = "vp78",
"Luger" = "p08b",
"Mk.58" = "secguncomp",
"PX4 Storm" = "px4"
)
/obj/item/gun/ballistic/automatic/pistol/modular/update_icon()
..()
if(current_skin)
icon_state = "[unique_reskin[current_skin]][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]"
else
icon_state = "[initial(icon_state)][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]"
if(magazine && suppressed)
cut_overlays()
add_overlay("[unique_reskin[current_skin]]-magazine-sup") //Yes, this means the default iconstate can't have a magazine overlay
else if (magazine)
cut_overlays()
add_overlay("[unique_reskin[current_skin]]-magazine")
else
cut_overlays()
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,178 @@
#undef CURRENT_RESIDENT_FILE
#define LIST_MODE_NUM 0
#define LIST_MODE_TEXT 1
#define LIST_MODE_FLAG 2
/datum/config_entry
var/name //read-only, this is determined by the last portion of the derived entry type
var/value
var/default //read-only, just set value directly
var/resident_file //the file which this belongs to, must be set
var/modified = FALSE //set to TRUE if the default has been overridden by a config entry
var/protection = NONE
var/abstract_type = /datum/config_entry //do not instantiate if type matches this
var/dupes_allowed = FALSE
/datum/config_entry/New()
if(!resident_file)
CRASH("Config entry [type] has no resident_file set")
if(type == abstract_type)
CRASH("Abstract config entry [type] instatiated!")
name = lowertext(type2top(type))
if(islist(value))
var/list/L = value
default = L.Copy()
else
default = value
/datum/config_entry/Destroy()
config.RemoveEntry(src)
return ..()
/datum/config_entry/can_vv_get(var_name)
. = ..()
if(var_name == "value" || var_name == "default")
. &= !(protection & CONFIG_ENTRY_HIDDEN)
/datum/config_entry/vv_edit_var(var_name, var_value)
var/static/list/banned_edits = list("name", "default", "resident_file", "protection", "abstract_type", "modified", "dupes_allowed")
if(var_name == "value")
if(protection & CONFIG_ENTRY_LOCKED)
return FALSE
. = ValidateAndSet("[var_value]")
if(.)
var_edited = TRUE
return
if(var_name in banned_edits)
return FALSE
return ..()
/datum/config_entry/proc/ValidateAndSet(str_val)
CRASH("Invalid config entry type!")
/datum/config_entry/proc/ValidateKeyedList(str_val, list_mode, splitter)
str_val = trim(str_val)
var/key_pos = findtext(str_val, splitter)
var/key_name = null
var/key_value = null
if(key_pos || list_mode == LIST_MODE_FLAG)
key_name = lowertext(copytext(str_val, 1, key_pos))
key_value = copytext(str_val, key_pos + 1)
var/temp
var/continue_check
switch(list_mode)
if(LIST_MODE_FLAG)
temp = TRUE
continue_check = TRUE
if(LIST_MODE_NUM)
temp = text2num(key_value)
continue_check = !isnull(temp)
if(LIST_MODE_TEXT)
temp = key_value
continue_check = temp
if(continue_check && ValidateKeyName(key_name))
value[key_name] = temp
return TRUE
return FALSE
/datum/config_entry/proc/ValidateKeyName(key_name)
return TRUE
/datum/config_entry/string
value = ""
abstract_type = /datum/config_entry/string
var/auto_trim = TRUE
/datum/config_entry/string/vv_edit_var(var_name, var_value)
return var_name != "auto_trim" && ..()
/datum/config_entry/string/ValidateAndSet(str_val)
value = auto_trim ? trim(str_val) : str_val
return TRUE
/datum/config_entry/number
value = 0
abstract_type = /datum/config_entry/number
var/integer = TRUE
var/max_val = INFINITY
var/min_val = -INFINITY
/datum/config_entry/number/ValidateAndSet(str_val)
var/temp = text2num(trim(str_val))
if(!isnull(temp))
value = Clamp(integer ? round(temp) : temp, min_val, max_val)
if(value != temp && !var_edited)
log_config("Changing [name] from [temp] to [value]!")
return TRUE
return FALSE
/datum/config_entry/number/vv_edit_var(var_name, var_value)
var/static/list/banned_edits = list("max_val", "min_val", "integer")
return !(var_name in banned_edits) && ..()
/datum/config_entry/flag
value = FALSE
abstract_type = /datum/config_entry/flag
/datum/config_entry/flag/ValidateAndSet(str_val)
value = text2num(trim(str_val)) != 0
return TRUE
/datum/config_entry/number_list
abstract_type = /datum/config_entry/number_list
value = list()
/datum/config_entry/number_list/ValidateAndSet(str_val)
str_val = trim(str_val)
var/list/new_list = list()
var/list/values = splittext(str_val," ")
for(var/I in values)
var/temp = text2num(I)
if(isnull(temp))
return FALSE
new_list += temp
if(!new_list.len)
return FALSE
value = new_list
return TRUE
/datum/config_entry/keyed_flag_list
abstract_type = /datum/config_entry/keyed_flag_list
value = list()
dupes_allowed = TRUE
/datum/config_entry/keyed_flag_list/ValidateAndSet(str_val)
return ValidateKeyedList(str_val, LIST_MODE_FLAG, " ")
/datum/config_entry/keyed_number_list
abstract_type = /datum/config_entry/keyed_number_list
value = list()
dupes_allowed = TRUE
var/splitter = " "
/datum/config_entry/keyed_number_list/vv_edit_var(var_name, var_value)
return var_name != "splitter" && ..()
/datum/config_entry/keyed_number_list/ValidateAndSet(str_val)
return ValidateKeyedList(str_val, LIST_MODE_NUM, splitter)
/datum/config_entry/keyed_string_list
abstract_type = /datum/config_entry/keyed_string_list
value = list()
dupes_allowed = TRUE
var/splitter = " "
/datum/config_entry/keyed_string_list/vv_edit_var(var_name, var_value)
return var_name != "splitter" && ..()
/datum/config_entry/keyed_string_list/ValidateAndSet(str_val)
return ValidateKeyedList(str_val, LIST_MODE_TEXT, splitter)
#undef LIST_MODE_NUM
#undef LIST_MODE_TEXT
#undef LIST_MODE_FLAG
@@ -0,0 +1,287 @@
GLOBAL_VAR_INIT(config_dir, "config/")
GLOBAL_PROTECT(config_dir)
/datum/controller/configuration
name = "Configuration"
var/hiding_entries_by_type = TRUE //Set for readability, admins can set this to FALSE if they want to debug it
var/list/entries
var/list/entries_by_type
var/list/maplist
var/datum/map_config/defaultmap
var/list/modes // allowed modes
var/list/gamemode_cache
var/list/votable_modes // votable modes
var/list/mode_names
var/list/mode_reports
var/list/mode_false_report_weight
/datum/controller/configuration/New()
config = src
var/list/config_files = InitEntries()
LoadModes()
for(var/I in config_files)
LoadEntries(I)
if(Get(/datum/config_entry/flag/maprotation))
loadmaplist(CONFIG_MAPS_FILE)
/datum/controller/configuration/Destroy()
entries_by_type.Cut()
QDEL_LIST_ASSOC_VAL(entries)
QDEL_LIST_ASSOC_VAL(maplist)
QDEL_NULL(defaultmap)
config = null
return ..()
/datum/controller/configuration/proc/InitEntries()
var/list/_entries = list()
entries = _entries
var/list/_entries_by_type = list()
entries_by_type = _entries_by_type
. = list()
for(var/I in typesof(/datum/config_entry)) //typesof is faster in this case
var/datum/config_entry/E = I
if(initial(E.abstract_type) == I)
continue
E = new I
_entries_by_type[I] = E
var/esname = E.name
var/datum/config_entry/test = _entries[esname]
if(test)
log_config("Error: [test.type] has the same name as [E.type]: [esname]! Not initializing [E.type]!")
qdel(E)
continue
_entries[esname] = E
.[E.resident_file] = TRUE
/datum/controller/configuration/proc/RemoveEntry(datum/config_entry/CE)
entries -= CE.name
entries_by_type -= CE.type
/datum/controller/configuration/proc/LoadEntries(filename)
log_config("Loading config file [filename]...")
var/list/lines = world.file2list("[GLOB.config_dir][filename]")
var/list/_entries = entries
for(var/L in lines)
if(!L)
continue
if(copytext(L, 1, 2) == "#")
continue
var/pos = findtext(L, " ")
var/entry = null
var/value = null
if(pos)
entry = lowertext(copytext(L, 1, pos))
value = copytext(L, pos + 1)
else
entry = lowertext(L)
if(!entry)
continue
var/datum/config_entry/E = _entries[entry]
if(!E)
log_config("Unknown setting in configuration: '[entry]'")
continue
if(filename != E.resident_file)
log_config("Found [entry] in [filename] when it should have been in [E.resident_file]! Ignoring.")
continue
var/validated = E.ValidateAndSet(value)
if(!validated)
log_config("Failed to validate setting \"[value]\" for [entry]")
else if(E.modified && !E.dupes_allowed)
log_config("Duplicate setting for [entry] ([value]) detected! Using latest.")
if(validated)
E.modified = TRUE
/datum/controller/configuration/can_vv_get(var_name)
return (var_name != "entries_by_type" || !hiding_entries_by_type) && ..()
/datum/controller/configuration/vv_edit_var(var_name, var_value)
return !(var_name in list("entries_by_type", "entries")) && ..()
/datum/controller/configuration/stat_entry()
if(!statclick)
statclick = new/obj/effect/statclick/debug(null, "Edit", src)
stat("[name]:", statclick)
/datum/controller/configuration/proc/Get(entry_type)
if(IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Get" && GLOB.LastAdminCalledTargetRef == "\ref[src]")
log_admin_private("Config access of [entry_type] attempted by [key_name(usr)]")
return
var/datum/config_entry/E = entry_type
var/entry_is_abstract = initial(E.abstract_type) == entry_type
if(entry_is_abstract)
CRASH("Tried to retrieve an abstract config_entry: [entry_type]")
E = entries_by_type[entry_type]
if(!E)
CRASH("Missing config entry for [entry_type]!")
return E.value
/datum/controller/configuration/proc/Set(entry_type, new_val)
if(IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Set" && GLOB.LastAdminCalledTargetRef == "\ref[src]")
log_admin_private("Config rewrite of [entry_type] to [new_val] attempted by [key_name(usr)]")
return
var/datum/config_entry/E = entry_type
var/entry_is_abstract = initial(E.abstract_type) == entry_type
if(entry_is_abstract)
CRASH("Tried to retrieve an abstract config_entry: [entry_type]")
E = entries_by_type[entry_type]
if(!E)
CRASH("Missing config entry for [entry_type]!")
return E.ValidateAndSet(new_val)
/datum/controller/configuration/proc/LoadModes()
gamemode_cache = typecacheof(/datum/game_mode, TRUE)
modes = list()
mode_names = list()
mode_reports = list()
mode_false_report_weight = list()
votable_modes = list()
var/list/probabilities = Get(/datum/config_entry/keyed_number_list/probability)
for(var/T in gamemode_cache)
// I wish I didn't have to instance the game modes in order to look up
// their information, but it is the only way (at least that I know of).
var/datum/game_mode/M = new T()
if(M.config_tag)
if(!(M.config_tag in modes)) // ensure each mode is added only once
modes += M.config_tag
mode_names[M.config_tag] = M.name
probabilities[M.config_tag] = M.probability
mode_reports[M.config_tag] = M.generate_report()
mode_false_report_weight[M.config_tag] = M.false_report_weight
if(M.votable)
votable_modes += M.config_tag
qdel(M)
votable_modes += "secret"
/datum/controller/configuration/proc/loadmaplist(filename)
filename = "[GLOB.config_dir][filename]"
var/list/Lines = world.file2list(filename)
var/datum/map_config/currentmap = null
for(var/t in Lines)
if(!t)
continue
t = trim(t)
if(length(t) == 0)
continue
else if(copytext(t, 1, 2) == "#")
continue
var/pos = findtext(t, " ")
var/command = null
var/data = null
if(pos)
command = lowertext(copytext(t, 1, pos))
data = copytext(t, pos + 1)
else
command = lowertext(t)
if(!command)
continue
if (!currentmap && command != "map")
continue
switch (command)
if ("map")
currentmap = new ("_maps/[data].json")
if(currentmap.defaulted)
log_config("Failed to load map config for [data]!")
if ("minplayers","minplayer")
currentmap.config_min_users = text2num(data)
if ("maxplayers","maxplayer")
currentmap.config_max_users = text2num(data)
if ("weight","voteweight")
currentmap.voteweight = text2num(data)
if ("default","defaultmap")
defaultmap = currentmap
if ("endmap")
LAZYINITLIST(maplist)
maplist[currentmap.map_name] = currentmap
currentmap = null
if ("disabled")
currentmap = null
else
WRITE_FILE(GLOB.config_error_log, "Unknown command in map vote config: '[command]'")
/datum/controller/configuration/proc/pick_mode(mode_name)
// I wish I didn't have to instance the game modes in order to look up
// their information, but it is the only way (at least that I know of).
// ^ This guy didn't try hard enough
for(var/T in gamemode_cache)
var/datum/game_mode/M = T
var/ct = initial(M.config_tag)
if(ct && ct == mode_name)
return new T
return new /datum/game_mode/extended()
/datum/controller/configuration/proc/get_runnable_modes()
var/list/datum/game_mode/runnable_modes = new
var/list/probabilities = Get(/datum/config_entry/keyed_number_list/probability)
var/list/min_pop = Get(/datum/config_entry/keyed_number_list/min_pop)
var/list/max_pop = Get(/datum/config_entry/keyed_number_list/max_pop)
var/list/repeated_mode_adjust = Get(/datum/config_entry/number_list/repeated_mode_adjust)
for(var/T in gamemode_cache)
var/datum/game_mode/M = new T()
if(!(M.config_tag in modes))
qdel(M)
continue
if(probabilities[M.config_tag]<=0)
qdel(M)
continue
if(min_pop[M.config_tag])
M.required_players = min_pop[M.config_tag]
if(max_pop[M.config_tag])
M.maximum_players = max_pop[M.config_tag]
if(M.can_start())
var/final_weight = probabilities[M.config_tag]
if(SSpersistence.saved_modes.len == 3 && repeated_mode_adjust.len == 3)
var/recent_round = min(SSpersistence.saved_modes.Find(M.config_tag),3)
var/adjustment = 0
while(recent_round)
adjustment += repeated_mode_adjust[recent_round]
recent_round = SSpersistence.saved_modes.Find(M.config_tag,recent_round+1,0)
final_weight *= ((100-adjustment)/100)
runnable_modes[M] = final_weight
return runnable_modes
/datum/controller/configuration/proc/get_runnable_midround_modes(crew)
var/list/datum/game_mode/runnable_modes = new
var/list/probabilities = Get(/datum/config_entry/keyed_number_list/probability)
var/list/min_pop = Get(/datum/config_entry/keyed_number_list/min_pop)
var/list/max_pop = Get(/datum/config_entry/keyed_number_list/max_pop)
for(var/T in (gamemode_cache - SSticker.mode.type))
var/datum/game_mode/M = new T()
if(!(M.config_tag in modes))
qdel(M)
continue
if(probabilities[M.config_tag]<=0)
qdel(M)
continue
if(min_pop[M.config_tag])
M.required_players = min_pop[M.config_tag]
if(max_pop[M.config_tag])
M.maximum_players = max_pop[M.config_tag]
if(M.required_players <= crew)
if(M.maximum_players >= 0 && M.maximum_players < crew)
continue
runnable_modes[M] = probabilities[M.config_tag]
return runnable_modes
@@ -0,0 +1,22 @@
#define CURRENT_RESIDENT_FILE "comms.txt"
CONFIG_DEF(string/comms_key)
protection = CONFIG_ENTRY_HIDDEN
/datum/config_entry/string/comms_key/ValidateAndSet(str_val)
return str_val != "default_pwd" && length(str_val) > 6 && ..()
CONFIG_DEF(string/cross_server_address)
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/string/cross_server_address/ValidateAndSet(str_val)
return str_val != "byond:\\address:port" && ..()
CONFIG_DEF(string/cross_comms_name)
GLOBAL_VAR_INIT(medals_enabled, TRUE) //will be auto set to false if the game fails contacting the medal hub to prevent unneeded calls.
CONFIG_DEF(string/medal_hub_address)
CONFIG_DEF(string/medal_hub_password)
protection = CONFIG_ENTRY_HIDDEN
@@ -0,0 +1,387 @@
#define CURRENT_RESIDENT_FILE "config.txt"
CONFIG_DEF(flag/autoadmin) // if autoadmin is enabled
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/autoadmin_rank) // the rank for autoadmins
value = "Game Master"
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/servername) // server name (the name of the game window)
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/serversqlname) // short form server name used for the DB
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/stationname) // station name (the name of the station in-game)
CONFIG_DEF(number/lobby_countdown) // In between round countdown.
value = 120
min_val = 0
CONFIG_DEF(number/round_end_countdown) // Post round murder death kill countdown
value = 25
min_val = 0
CONFIG_DEF(flag/hub) // if the game appears on the hub or not
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_ooc) // log OOC channel
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_access) // log login/logout
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_say) // log client say
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_admin) // log admin actions
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_prayer) // log prayers
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_law) // log lawchanges
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_game) // log game events
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_vote) // log voting
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_whisper) // log client whisper
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_attack) // log attack messages
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_emote) // log emotes
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_adminchat) // log admin chat messages
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_pda) // log pda messages
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_twitter) // log certain expliotable parrots and other such fun things in a JSON file of twitter valid phrases.
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/log_world_topic) // log all world.Topic() calls
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/allow_admin_ooccolor) // Allows admins with relevant permissions to have their own ooc colour
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/allow_vote_restart) // allow votes to restart
CONFIG_DEF(flag/allow_vote_mode) // allow votes to change mode
CONFIG_DEF(number/vote_delay) // minimum time between voting sessions (deciseconds, 10 minute default)
value = 6000
min_val = 0
CONFIG_DEF(number/vote_period) // length of voting period (deciseconds, default 1 minute)
value = 600
min_val = 0
CONFIG_DEF(flag/default_no_vote) // vote does not default to nochange/norestart
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/no_dead_vote) // dead people can't vote
CONFIG_DEF(flag/allow_metadata) // Metadata is supported.
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/popup_admin_pm) // adminPMs to non-admins show in a pop-up 'reply' window when set
CONFIG_DEF(number/fps)
value = 20
min_val = 1
max_val = 100 //byond will start crapping out at 50, so this is just ridic
var/sync_validate = FALSE
/datum/config_entry/number/fps/ValidateAndSet(str_val)
. = ..()
if(.)
sync_validate = TRUE
var/datum/config_entry/number/ticklag/TL = config.entries_by_type[/datum/config_entry/number/ticklag]
if(!TL.sync_validate)
TL.ValidateAndSet(10 / value)
sync_validate = FALSE
CONFIG_DEF(number/ticklag)
integer = FALSE
var/sync_validate = FALSE
/datum/config_entry/number/ticklag/New() //ticklag weirdly just mirrors fps
var/datum/config_entry/CE = /datum/config_entry/number/fps
value = 10 / initial(CE.value)
..()
/datum/config_entry/number/ticklag/ValidateAndSet(str_val)
. = text2num(str_val) > 0 && ..()
if(.)
sync_validate = TRUE
var/datum/config_entry/number/fps/FPS = config.entries_by_type[/datum/config_entry/number/fps]
if(!FPS.sync_validate)
FPS.ValidateAndSet(10 / value)
sync_validate = FALSE
CONFIG_DEF(flag/allow_holidays)
CONFIG_DEF(number/tick_limit_mc_init) //SSinitialization throttling
value = TICK_LIMIT_MC_INIT_DEFAULT
min_val = 0 //oranges warned us
integer = FALSE
CONFIG_DEF(flag/admin_legacy_system) //Defines whether the server uses the legacy admin system with admins.txt or the SQL system
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/hostedby)
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/norespawn)
CONFIG_DEF(flag/guest_jobban)
CONFIG_DEF(flag/usewhitelist)
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/ban_legacy_system) //Defines whether the server uses the legacy banning system with the files in /data or the SQL system.
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/use_age_restriction_for_jobs) //Do jobs use account age restrictions? --requires database
CONFIG_DEF(flag/use_account_age_for_jobs) //Uses the time they made the account for the job restriction stuff. New player joining alerts should be unaffected.
CONFIG_DEF(flag/use_exp_tracking)
CONFIG_DEF(flag/use_exp_restrictions_heads)
CONFIG_DEF(number/use_exp_restrictions_heads_hours)
value = 0
min_val = 0
CONFIG_DEF(flag/use_exp_restrictions_heads_department)
CONFIG_DEF(flag/use_exp_restrictions_other)
CONFIG_DEF(flag/use_exp_restrictions_admin_bypass)
CONFIG_DEF(string/server)
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/banappeals)
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/wikiurl)
protection = CONFIG_ENTRY_LOCKED
value = "http://www.tgstation13.org/wiki"
CONFIG_DEF(string/forumurl)
protection = CONFIG_ENTRY_LOCKED
value = "http://tgstation13.org/phpBB/index.php"
CONFIG_DEF(string/rulesurl)
protection = CONFIG_ENTRY_LOCKED
value = "http://www.tgstation13.org/wiki/Rules"
CONFIG_DEF(string/githuburl)
protection = CONFIG_ENTRY_LOCKED
value = "https://www.github.com/tgstation/-tg-station"
CONFIG_DEF(number/githubrepoid)
protection = CONFIG_ENTRY_LOCKED
value = null
min_val = 0
CONFIG_DEF(flag/guest_ban)
CONFIG_DEF(number/id_console_jobslot_delay)
value = 30
min_val = 0
CONFIG_DEF(number/inactivity_period) //time in ds until a player is considered inactive)
value = 3000
min_val = 0
/datum/config_entry/number/inactivity_period/ValidateAndSet(str_val)
. = ..()
if(.)
value *= 10 //documented as seconds in config.txt
CONFIG_DEF(number/afk_period) //time in ds until a player is considered inactive)
value = 3000
min_val = 0
/datum/config_entry/number/afk_period/ValidateAndSet(str_val)
. = ..()
if(.)
value *= 10 //documented as seconds in config.txt
CONFIG_DEF(flag/kick_inactive) //force disconnect for inactive players
CONFIG_DEF(flag/load_jobs_from_txt)
CONFIG_DEF(flag/forbid_singulo_possession)
CONFIG_DEF(flag/useircbot) //tgs2 support
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/automute_on) //enables automuting/spam prevention
CONFIG_DEF(string/panic_server_name)
protection = CONFIG_ENTRY_LOCKED
/datum/config_entry/string/panic_server_name/ValidateAndSet(str_val)
return str_val != "\[Put the name here\]" && ..()
CONFIG_DEF(string/panic_address) //Reconnect a player this linked server if this server isn't accepting new players
/datum/config_entry/string/panic_address/ValidateAndSet(str_val)
return str_val != "byond://address:port" && ..()
CONFIG_DEF(string/invoke_youtubedl)
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
CONFIG_DEF(flag/show_irc_name)
CONFIG_DEF(flag/see_own_notes) //Can players see their own admin notes (read-only)?
CONFIG_DEF(number/note_fresh_days)
value = null
min_val = 0
integer = FALSE
CONFIG_DEF(number/note_stale_days)
value = null
min_val = 0
integer = FALSE
CONFIG_DEF(flag/maprotation)
CONFIG_DEF(number/maprotatechancedelta)
value = 0.75
min_val = 0
max_val = 1
integer = FALSE
CONFIG_DEF(number/soft_popcap)
value = null
min_val = 0
CONFIG_DEF(number/hard_popcap)
value = null
min_val = 0
CONFIG_DEF(number/extreme_popcap)
value = null
min_val = 0
CONFIG_DEF(string/soft_popcap_message)
value = "Be warned that the server is currently serving a high number of users, consider using alternative game servers."
CONFIG_DEF(string/hard_popcap_message)
value = "The server is currently serving a high number of users, You cannot currently join. You may wait for the number of living crew to decline, observe, or find alternative servers."
CONFIG_DEF(string/extreme_popcap_message)
value = "The server is currently serving a high number of users, find alternative servers."
CONFIG_DEF(flag/panic_bunker) // prevents people the server hasn't seen before from connecting
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(number/notify_new_player_age) // how long do we notify admins of a new player
min_val = -1
CONFIG_DEF(number/notify_new_player_account_age) // how long do we notify admins of a new byond account
min_val = 0
CONFIG_DEF(flag/irc_first_connection_alert) // do we notify the irc channel when somebody is connecting for the first time?
CONFIG_DEF(flag/check_randomizer)
CONFIG_DEF(string/ipintel_email)
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
/datum/config_entry/string/ipintel_email/ValidateAndSet(str_val)
return str_val != "ch@nge.me" && ..()
CONFIG_DEF(number/ipintel_rating_bad)
value = 1
integer = FALSE
min_val = 0
max_val = 1
CONFIG_DEF(number/ipintel_save_good)
protection = CONFIG_ENTRY_LOCKED
value = 12
min_val = 0
CONFIG_DEF(number/ipintel_save_bad)
protection = CONFIG_ENTRY_LOCKED
value = 1
min_val = 0
CONFIG_DEF(string/ipintel_domain)
protection = CONFIG_ENTRY_LOCKED
value = "check.getipintel.net"
CONFIG_DEF(flag/aggressive_changelog)
CONFIG_DEF(flag/autoconvert_notes) //if all connecting player's notes should attempt to be converted to the database
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(flag/allow_webclient)
CONFIG_DEF(flag/webclient_only_byond_members)
CONFIG_DEF(flag/announce_admin_logout)
CONFIG_DEF(flag/announce_admin_login)
CONFIG_DEF(flag/allow_map_voting)
CONFIG_DEF(flag/generate_minimaps)
CONFIG_DEF(number/client_warn_version)
value = null
min_val = 500
max_val = DM_VERSION - 1
CONFIG_DEF(string/client_warn_message)
value = "Your version of byond may have issues or be blocked from accessing this server in the future."
CONFIG_DEF(number/client_error_version)
value = null
min_val = 500
max_val = DM_VERSION - 1
CONFIG_DEF(string/client_error_message)
value = "Your version of byond is too old, may have issues, and is blocked from accessing this server."
CONFIG_DEF(number/minute_topic_limit)
value = null
min_val = 0
CONFIG_DEF(number/second_topic_limit)
value = null
min_val = 0
CONFIG_DEF(number/error_cooldown) // The "cooldown" time for each occurrence of a unique error)
value = 600
min_val = 0
CONFIG_DEF(number/error_limit) // How many occurrences before the next will silence them
value = 50
CONFIG_DEF(number/error_silence_time) // How long a unique error will be silenced for
value = 6000
CONFIG_DEF(number/error_msg_delay) // How long to wait between messaging admins about occurrences of a unique error
value = 50
CONFIG_DEF(flag/irc_announce_new_game)
CONFIG_DEF(flag/debug_admin_hrefs)
@@ -0,0 +1,28 @@
#define CURRENT_RESIDENT_FILE "dbconfig.txt"
CONFIG_DEF(flag/sql_enabled) // for sql switching
protection = CONFIG_ENTRY_LOCKED
CONFIG_DEF(string/address)
value = "localhost"
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
CONFIG_DEF(number/port)
value = 3306
min_val = 0
max_val = 65535
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
CONFIG_DEF(string/feedback_database)
value = "test"
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
CONFIG_DEF(string/feedback_login)
value = "root"
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
CONFIG_DEF(string/feedback_password)
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
CONFIG_DEF(string/feedback_tableprefix)
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
@@ -0,0 +1,266 @@
#define CURRENT_RESIDENT_FILE "game_options.txt"
CONFIG_DEF(number_list/repeated_mode_adjust)
CONFIG_DEF(keyed_number_list/probability)
/datum/config_entry/keyed_number_list/probability/ValidateKeyName(key_name)
return key_name in config.modes
CONFIG_DEF(keyed_number_list/max_pop)
/datum/config_entry/keyed_number_list/max_pop/ValidateKeyName(key_name)
return key_name in config.modes
CONFIG_DEF(keyed_number_list/min_pop)
/datum/config_entry/keyed_number_list/min_pop/ValidateKeyName(key_name)
return key_name in config.modes
CONFIG_DEF(keyed_flag_list/continuous) // which roundtypes continue if all antagonists die
/datum/config_entry/keyed_flag_list/continuous/ValidateKeyName(key_name)
return key_name in config.modes
CONFIG_DEF(keyed_flag_list/midround_antag) // which roundtypes use the midround antagonist system
/datum/config_entry/keyed_flag_list/midround_antag/ValidateKeyName(key_name)
return key_name in config.modes
CONFIG_DEF(keyed_string_list/policy)
CONFIG_DEF(number/damage_multiplier)
value = 1
integer = FALSE
CONFIG_DEF(number/minimal_access_threshold) //If the number of players is larger than this threshold, minimal access will be turned on.
min_val = 0
CONFIG_DEF(flag/jobs_have_minimal_access) //determines whether jobs use minimal access or expanded access.
CONFIG_DEF(flag/assistants_have_maint_access)
CONFIG_DEF(flag/security_has_maint_access)
CONFIG_DEF(flag/everyone_has_maint_access)
CONFIG_DEF(flag/sec_start_brig) //makes sec start in brig instead of dept sec posts
CONFIG_DEF(flag/force_random_names)
CONFIG_DEF(flag/humans_need_surnames)
CONFIG_DEF(flag/allow_ai) // allow ai job
CONFIG_DEF(flag/disable_secborg) // disallow secborg module to be chosen.
CONFIG_DEF(flag/disable_peaceborg)
CONFIG_DEF(number/traitor_scaling_coeff) //how much does the amount of players get divided by to determine traitors
value = 6
min_val = 1
CONFIG_DEF(number/brother_scaling_coeff) //how many players per brother team
value = 25
min_val = 1
CONFIG_DEF(number/changeling_scaling_coeff) //how much does the amount of players get divided by to determine changelings
value = 6
min_val = 1
CONFIG_DEF(number/security_scaling_coeff) //how much does the amount of players get divided by to determine open security officer positions
value = 8
min_val = 1
CONFIG_DEF(number/abductor_scaling_coeff) //how many players per abductor team
value = 15
min_val = 1
CONFIG_DEF(number/traitor_objectives_amount)
value = 2
min_val = 0
CONFIG_DEF(number/brother_objectives_amount)
value = 2
min_val = 0
CONFIG_DEF(flag/reactionary_explosions) //If we use reactionary explosions, explosions that react to walls and doors
CONFIG_DEF(flag/protect_roles_from_antagonist) //If security and such can be traitor/cult/other
CONFIG_DEF(flag/protect_assistant_from_antagonist) //If assistants can be traitor/cult/other
CONFIG_DEF(flag/enforce_human_authority) //If non-human species are barred from joining as a head of staff
CONFIG_DEF(flag/allow_latejoin_antagonists) // If late-joining players can be traitor/changeling
CONFIG_DEF(number/midround_antag_time_check) // How late (in minutes) you want the midround antag system to stay on, setting this to 0 will disable the system
value = 60
min_val = 0
CONFIG_DEF(number/midround_antag_life_check) // A ratio of how many people need to be alive in order for the round not to immediately end in midround antagonist
value = 0.7
integer = FALSE
min_val = 0
max_val = 1
CONFIG_DEF(number/shuttle_refuel_delay)
value = 12000
min_val = 0
CONFIG_DEF(flag/show_game_type_odds) //if set this allows players to see the odds of each roundtype on the get revision screen
CONFIG_DEF(flag/join_with_mutant_race) //players can choose their mutant race before joining the game
CONFIG_DEF(keyed_flag_list/roundstart_races) //races you can play as from the get go. If left undefined the game's roundstart var for species is used
var/first_edit = TRUE
/datum/config_entry/keyed_flag_list/roundstart_races/New()
for(var/I in subtypesof(/datum/species))
var/datum/species/S = I
if(initial(S.roundstart))
value[initial(S.id)] = TRUE
..()
/datum/config_entry/keyed_flag_list/roundstart_races/ValidateAndSet(str_val)
var/list/old_val
if(first_edit)
old_val = value
old_val = old_val.Copy()
. = ..()
if(first_edit)
if(!.)
value = old_val
else
first_edit = FALSE
CONFIG_DEF(flag/join_with_mutant_humans) //players can pick mutant bodyparts for humans before joining the game
CONFIG_DEF(flag/no_summon_guns) //No
CONFIG_DEF(flag/no_summon_magic) //Fun
CONFIG_DEF(flag/no_summon_events) //Allowed
CONFIG_DEF(flag/no_intercept_report) //Whether or not to send a communications intercept report roundstart. This may be overriden by gamemodes.
CONFIG_DEF(number/arrivals_shuttle_dock_window) //Time from when a player late joins on the arrivals shuttle to when the shuttle docks on the station
value = 55
min_val = 30
CONFIG_DEF(flag/arrivals_shuttle_require_undocked) //Require the arrivals shuttle to be undocked before latejoiners can join
CONFIG_DEF(flag/arrivals_shuttle_require_safe_latejoin) //Require the arrivals shuttle to be operational in order for latejoiners to join
CONFIG_DEF(string/alert_green)
value = "All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced."
CONFIG_DEF(string/alert_blue_upto)
value = "The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible, random searches are permitted."
CONFIG_DEF(string/alert_blue_downto)
value = "The immediate threat has passed. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still allowed."
CONFIG_DEF(string/alert_red_upto)
value = "There is an immediate serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised."
CONFIG_DEF(string/alert_red_downto)
value = "The station's destruction has been averted. There is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised."
CONFIG_DEF(string/alert_delta)
value = "Destruction of the station is imminent. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill."
CONFIG_DEF(flag/revival_pod_plants)
CONFIG_DEF(flag/revival_cloning)
CONFIG_DEF(number/revival_brain_life)
value = -1
min_val = -1
CONFIG_DEF(flag/rename_cyborg)
CONFIG_DEF(flag/ooc_during_round)
CONFIG_DEF(flag/emojis)
CONFIG_DEF(number/run_delay) //Used for modifying movement speed for mobs.
CONFIG_DEF(number/walk_delay)
CONFIG_DEF(number/human_delay) //Mob specific modifiers. NOTE: These will affect different mob types in different ways
CONFIG_DEF(number/robot_delay)
CONFIG_DEF(number/monkey_delay)
CONFIG_DEF(number/alien_delay)
CONFIG_DEF(number/slime_delay)
CONFIG_DEF(number/animal_delay)
CONFIG_DEF(number/gateway_delay) //How long the gateway takes before it activates. Default is half an hour.
value = 18000
min_val = 0
CONFIG_DEF(flag/ghost_interaction)
CONFIG_DEF(flag/silent_ai)
CONFIG_DEF(flag/silent_borg)
CONFIG_DEF(flag/sandbox_autoclose) // close the sandbox panel after spawning an item, potentially reducing griff
CONFIG_DEF(number/default_laws) //Controls what laws the AI spawns with.
value = 0
min_val = 0
max_val = 3
CONFIG_DEF(number/silicon_max_law_amount)
value = 12
min_val = 0
CONFIG_DEF(keyed_flag_list/random_laws)
CONFIG_DEF(keyed_number_list/law_weight)
splitter = ","
CONFIG_DEF(number/assistant_cap)
value = -1
min_val = -1
CONFIG_DEF(flag/starlight)
CONFIG_DEF(flag/grey_assistants)
CONFIG_DEF(number/lavaland_budget)
value = 60
min_val = 0
CONFIG_DEF(number/space_budget)
value = 16
min_val = 0
CONFIG_DEF(flag/allow_random_events) // Enables random events mid-round when set
CONFIG_DEF(number/events_min_time_mul) // Multipliers for random events minimal starting time and minimal players amounts
value = 1
min_val = 0
integer = FALSE
CONFIG_DEF(number/events_min_players_mul)
value = 1
min_val = 0
integer = FALSE
CONFIG_DEF(number/mice_roundstart)
value = 10
min_val = 0
CONFIG_DEF(number/bombcap)
value = 14
min_val = 4
/datum/config_entry/number/bombcap/ValidateAndSet(str_val)
. = ..()
if(.)
GLOB.MAX_EX_DEVESTATION_RANGE = round(value / 4)
GLOB.MAX_EX_HEAVY_RANGE = round(value / 2)
GLOB.MAX_EX_LIGHT_RANGE = value
GLOB.MAX_EX_FLASH_RANGE = value
GLOB.MAX_EX_FLAME_RANGE = value
+2 -2
View File
@@ -169,7 +169,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
var/start_timeofday = REALTIMEOFDAY
// Initialize subsystems.
current_ticklimit = config.tick_limit_mc_init
current_ticklimit = CONFIG_GET(number/tick_limit_mc_init)
for (var/datum/controller/subsystem/SS in subsystems)
if (SS.flags & SS_NO_INIT)
continue
@@ -189,7 +189,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
sortTim(subsystems, /proc/cmp_subsystem_display)
// Set world options.
world.sleep_offline = 1
world.fps = config.fps
world.fps = CONFIG_GET(number/fps)
var/initialized_tod = REALTIMEOFDAY
sleep(1)
initializations_finished_with_no_players_logged_in = initialized_tod < REALTIMEOFDAY - 10
+1 -1
View File
@@ -69,7 +69,7 @@
can_fire = 0
flags |= SS_NO_FIRE
Master.subsystems -= src
return ..()
//Queue it to run.
// (we loop thru a linked list until we get to the end or find the right point)
+1 -1
View File
@@ -38,7 +38,7 @@ SUBSYSTEM_DEF(blackbox)
var/datum/DBQuery/query_record_playercount = SSdbcore.NewQuery("INSERT INTO [format_table_name("legacy_population")] (playercount, admincount, time, server_ip, server_port, round_id) VALUES ([playercount], [admincount], '[SQLtime()]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', '[GLOB.round_id]')")
query_record_playercount.Execute()
if(config.use_exp_tracking)
if(CONFIG_GET(flag/use_exp_tracking))
if((triggertime < 0) || (world.time > (triggertime +3000))) //subsystem fires once at roundstart then once every 10 minutes. a 5 min check skips the first fire. The <0 is midnight rollover check
update_exp(10,FALSE)
+9 -14
View File
@@ -54,32 +54,27 @@ SUBSYSTEM_DEF(dbcore)
if(failed_connections > FAILED_DB_CONNECTION_CUTOFF) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to connect anymore.
return FALSE
if(!config.sql_enabled)
if(!CONFIG_GET(flag/sql_enabled))
return FALSE
var/user = global.sqlfdbklogin
var/pass = global.sqlfdbkpass
var/db = global.sqlfdbkdb
var/address = global.sqladdress
var/port = global.sqlport
var/user = CONFIG_GET(string/feedback_login)
var/pass = CONFIG_GET(string/feedback_password)
var/db = CONFIG_GET(string/feedback_database)
var/address = CONFIG_GET(string/address)
var/port = CONFIG_GET(number/port)
doConnect("dbi:mysql:[db]:[address]:[port]", user, pass)
_dm_db_connect(_db_con, "dbi:mysql:[db]:[address]:[port]", user, pass, Default_Cursor, null)
. = IsConnected()
if (!.)
log_sql("Connect() failed | [ErrorMsg()]")
++failed_connections
/datum/controller/subsystem/dbcore/proc/doConnect(dbi_handler, user_handler, password_handler)
if(!config.sql_enabled)
return FALSE
return _dm_db_connect(_db_con, dbi_handler, user_handler, password_handler, Default_Cursor, null)
/datum/controller/subsystem/dbcore/proc/Disconnect()
failed_connections = 0
return _dm_db_close(_db_con)
/datum/controller/subsystem/dbcore/proc/IsConnected()
if(!config.sql_enabled)
if(!CONFIG_GET(flag/sql_enabled))
return FALSE
return _dm_db_is_connected(_db_con)
@@ -87,7 +82,7 @@ SUBSYSTEM_DEF(dbcore)
return _dm_db_quote(_db_con, str)
/datum/controller/subsystem/dbcore/proc/ErrorMsg()
if(!config.sql_enabled)
if(!CONFIG_GET(flag/sql_enabled))
return "Database disabled by configuration"
return _dm_db_error_msg(_db_con)
+2 -2
View File
@@ -56,7 +56,7 @@ SUBSYSTEM_DEF(events)
//selects a random event based on whether it can occur and it's 'weight'(probability)
/datum/controller/subsystem/events/proc/spawnEvent()
set waitfor = FALSE //for the admin prompt
if(!config.allow_random_events)
if(!CONFIG_GET(flag/allow_random_events))
// var/datum/round_event_control/E = locate(/datum/round_event_control/dust) in control
// if(E) E.runEvent()
return
@@ -171,7 +171,7 @@ SUBSYSTEM_DEF(events)
//sets up the holidays and holidays list
/datum/controller/subsystem/events/proc/getHoliday()
if(!config.allow_holidays)
if(!CONFIG_GET(flag/allow_holidays))
return // Holiday stuff was not enabled in the config!
var/YY = text2num(time2text(world.timeofday, "YY")) // get the current year
+18 -14
View File
@@ -16,7 +16,7 @@ SUBSYSTEM_DEF(job)
/datum/controller/subsystem/job/Initialize(timeofday)
if(!occupations.len)
SetupOccupations()
if(config.load_jobs_from_txt)
if(CONFIG_GET(flag/load_jobs_from_txt))
LoadJobs()
..()
@@ -106,7 +106,7 @@ SUBSYSTEM_DEF(job)
if(player.mind && job.title in player.mind.restricted_roles)
Debug("FOC incompatible with antagonist role, Player: [player]")
continue
if(config.enforce_human_authority && !player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features))
if(CONFIG_GET(flag/enforce_human_authority) && !player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features))
Debug("FOC non-human failed, Player: [player]")
continue
if(player.client.prefs.GetJobDepartment(job, level) & job.flag)
@@ -143,7 +143,7 @@ SUBSYSTEM_DEF(job)
Debug("GRJ incompatible with antagonist role, Player: [player], Job: [job.title]")
continue
if(config.enforce_human_authority && !player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features))
if(CONFIG_GET(flag/enforce_human_authority) && !player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features))
Debug("GRJ non-human failed, Player: [player]")
continue
@@ -245,11 +245,12 @@ SUBSYSTEM_DEF(job)
setup_officer_positions()
//Jobs will have fewer access permissions if the number of players exceeds the threshold defined in game_options.txt
if(config.minimal_access_threshold)
if(config.minimal_access_threshold > unassigned.len)
config.jobs_have_minimal_access = 0
var/mat = CONFIG_GET(number/minimal_access_threshold)
if(mat)
if(mat > unassigned.len)
CONFIG_SET(flag/jobs_have_minimal_access, FALSE)
else
config.jobs_have_minimal_access = 1
CONFIG_SET(flag/jobs_have_minimal_access, TRUE)
//Shuffle players and jobs
unassigned = shuffle(unassigned)
@@ -317,7 +318,7 @@ SUBSYSTEM_DEF(job)
Debug("DO incompatible with antagonist role, Player: [player], Job:[job.title]")
continue
if(config.enforce_human_authority && !player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features))
if(CONFIG_GET(flag/enforce_human_authority) && !player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features))
Debug("DO non-human failed, Player: [player], Job:[job.title]")
continue
@@ -415,8 +416,8 @@ SUBSYSTEM_DEF(job)
to_chat(M, "<b>To speak on your departments radio, use the :h button. To see others, look closely at your headset.</b>")
if(job.req_admin_notify)
to_chat(M, "<b>You are playing a job that is important for Game Progression. If you have to disconnect, please notify the admins via adminhelp.</b>")
if(config.minimal_access_threshold)
to_chat(M, "<FONT color='blue'><B>As this station was initially staffed with a [config.jobs_have_minimal_access ? "full crew, only your job's necessities" : "skeleton crew, additional access may"] have been added to your ID card.</B></font>")
if(CONFIG_GET(number/minimal_access_threshold))
to_chat(M, "<FONT color='blue'><B>As this station was initially staffed with a [CONFIG_GET(flag/jobs_have_minimal_access) ? "full crew, only your job's necessities" : "skeleton crew, additional access may"] have been added to your ID card.</B></font>")
if(job && H)
job.after_spawn(H, M)
@@ -429,9 +430,10 @@ SUBSYSTEM_DEF(job)
if(!J)
throw EXCEPTION("setup_officer_positions(): Security officer job is missing")
if(config.security_scaling_coeff > 0)
var/ssc = CONFIG_GET(number/security_scaling_coeff)
if(ssc > 0)
if(J.spawn_positions > 0)
var/officer_positions = min(12, max(J.spawn_positions, round(unassigned.len/config.security_scaling_coeff))) //Scale between configured minimum and 12 officers
var/officer_positions = min(12, max(J.spawn_positions, round(unassigned.len / ssc))) //Scale between configured minimum and 12 officers
Debug("Setting open security officer positions to [officer_positions]")
J.total_positions = officer_positions
J.spawn_positions = officer_positions
@@ -491,8 +493,10 @@ SUBSYSTEM_DEF(job)
SSblackbox.add_details("job_preferences",tmp_str)
/datum/controller/subsystem/job/proc/PopcapReached()
if(config.hard_popcap || config.extreme_popcap)
var/relevent_cap = max(config.hard_popcap, config.extreme_popcap)
var/hpc = CONFIG_GET(number/hard_popcap)
var/epc = CONFIG_GET(number/extreme_popcap)
if(hpc || epc)
var/relevent_cap = max(hpc, epc)
if((initial_players_to_assign - unassigned.len) >= relevent_cap)
return 1
return 0
+1 -1
View File
@@ -16,7 +16,7 @@ SUBSYSTEM_DEF(lighting)
/datum/controller/subsystem/lighting/Initialize(timeofday)
if(!initialized)
if (config.starlight)
if (CONFIG_GET(flag/starlight))
for(var/I in GLOB.sortedAreas)
var/area/A = I
if (A.dynamic_lighting == DYNAMIC_LIGHTING_IFSTARLIGHT)
+6 -5
View File
@@ -43,19 +43,19 @@ SUBSYSTEM_DEF(mapping)
loading_ruins = TRUE
var/mining_type = config.minetype
if (mining_type == "lavaland")
seedRuins(list(ZLEVEL_LAVALAND), global.config.lavaland_budget, /area/lavaland/surface/outdoors/unexplored, lava_ruins_templates)
seedRuins(list(ZLEVEL_LAVALAND), CONFIG_GET(number/lavaland_budget), /area/lavaland/surface/outdoors/unexplored, lava_ruins_templates)
spawn_rivers()
// deep space ruins
var/space_zlevels = list()
for(var/i in ZLEVEL_SPACEMIN to ZLEVEL_SPACEMAX)
switch(i)
if(ZLEVEL_MINING, ZLEVEL_LAVALAND, ZLEVEL_EMPTY_SPACE, ZLEVEL_TRANSIT)
if(ZLEVEL_MINING, ZLEVEL_LAVALAND, ZLEVEL_EMPTY_SPACE, ZLEVEL_TRANSIT, ZLEVEL_CITYOFCOGS)
continue
else
space_zlevels += i
seedRuins(space_zlevels, global.config.space_budget, /area/space, space_ruins_templates)
seedRuins(space_zlevels, CONFIG_GET(number/space_budget), /area/space, space_ruins_templates)
loading_ruins = FALSE
repopulate_sorted_areas()
// Set up Z-level transistions.
@@ -141,7 +141,8 @@ SUBSYSTEM_DEF(mapping)
var/players = GLOB.clients.len
var/list/mapvotes = list()
//count votes
if(global.config.allow_map_voting)
var/amv = CONFIG_GET(flag/allow_map_voting)
if(amv)
for (var/client/c in GLOB.clients)
var/vote = c.prefs.preferred_map
if (!vote)
@@ -174,7 +175,7 @@ SUBSYSTEM_DEF(mapping)
mapvotes.Remove(map)
continue
if(global.config.allow_map_voting)
if(amv)
mapvotes[map] = mapvotes[map]*VM.voteweight
var/pickedmap = pickweight(mapvotes)
+1 -1
View File
@@ -9,7 +9,7 @@ SUBSYSTEM_DEF(minimap)
/datum/controller/subsystem/minimap/Initialize(timeofday)
var/hash = md5(SSmapping.config.GetFullMapPath())
if(config.generate_minimaps)
if(CONFIG_GET(flag/generate_minimaps))
if(hash == trim(file2text(hash_path())))
for(var/z in z_levels) //We have these files cached, let's register them
register_asset("minimap_[z].png", fcopy_rsc(map_path(z)))
+47 -39
View File
@@ -22,47 +22,54 @@ SUBSYSTEM_DEF(persistence)
/datum/controller/subsystem/persistence/proc/LoadSatchels()
var/placed_satchel = 0
var/path
var/obj/item/storage/backpack/satchel/flat/F = new()
if(fexists("data/npc_saves/SecretSatchels.sav")) //legacy compatability to convert old format to new
if(fexists("data/npc_saves/SecretSatchels.sav")) //legacy conversion. Will only ever run once.
var/savefile/secret_satchels = new /savefile("data/npc_saves/SecretSatchels.sav")
var/sav_text
secret_satchels[SSmapping.config.map_name] >> sav_text
fdel("data/npc_saves/SecretSatchels.sav")
if(sav_text)
old_secret_satchels = splittext(sav_text,"#")
if(old_secret_satchels.len >= 20)
var/satchel_string = pick_n_take(old_secret_satchels)
for(var/map in secret_satchels)
var/json_file = file("data/npc_saves/SecretSatchels[map].json")
var/list/legacy_secret_satchels = splittext(secret_satchels[map],"#")
var/list/satchels = list()
for(var/i=1,i<=legacy_secret_satchels.len,i++)
var/satchel_string = legacy_secret_satchels[i]
var/list/chosen_satchel = splittext(satchel_string,"|")
if(chosen_satchel.len == 3)
F.x = text2num(chosen_satchel[1])
F.y = text2num(chosen_satchel[2])
F.z = ZLEVEL_STATION_PRIMARY
path = text2path(chosen_satchel[3])
else
var/json_file = file("data/npc_saves/SecretSatchels[SSmapping.config.map_name].json")
if(!fexists(json_file))
return
var/list/json = json_decode(file2text(json_file))
old_secret_satchels = json["data"]
if(old_secret_satchels.len)
if(old_secret_satchels.len >= 20) //guards against low drop pools assuring that one player cannot reliably find his own gear.
var/pos = rand(1, old_secret_satchels.len)
old_secret_satchels.Cut(pos, pos+1)
F.x = old_secret_satchels[pos]["x"]
F.y = old_secret_satchels[pos]["y"]
F.z = ZLEVEL_STATION_PRIMARY
path = text2path(old_secret_satchels[pos]["saved_obj"])
if(!ispath(path))
return
if(isfloorturf(F.loc) && !istype(F.loc, /turf/open/floor/plating/))
F.hide(1)
new path(F)
placed_satchel++
var/list/free_satchels = list()
var/list/data = list()
data["x"] = text2num(chosen_satchel[1])
data["y"] = text2num(chosen_satchel[2])
data["saved_obj"] = chosen_satchel[3]
satchels += list(data)
var/list/file_data = list()
file_data["data"] = satchels
WRITE_FILE(json_file, json_encode(file_data))
fdel("data/npc_saves/SecretSatchels.sav")
var/json_file = file("data/npc_saves/SecretSatchels[SSmapping.config.map_name].json")
var/list/json = list()
if(fexists(json_file))
json = json_decode(file2text(json_file))
old_secret_satchels = json["data"]
var/obj/item/storage/backpack/satchel/flat/F
if(old_secret_satchels && old_secret_satchels.len >= 10) //guards against low drop pools assuring that one player cannot reliably find his own gear.
var/pos = rand(1, old_secret_satchels.len)
F = new()
old_secret_satchels.Cut(pos, pos+1 % old_secret_satchels.len)
F.x = old_secret_satchels[pos]["x"]
F.y = old_secret_satchels[pos]["y"]
F.z = ZLEVEL_STATION_PRIMARY
path = text2path(old_secret_satchels[pos]["saved_obj"])
if(F)
if(isfloorturf(F.loc) && !istype(F.loc, /turf/open/floor/plating/))
F.hide(1)
if(ispath(path))
new path(F)
placed_satchel++
var/free_satchels = 0
for(var/turf/T in shuffle(block(locate(TRANSITIONEDGE,TRANSITIONEDGE,ZLEVEL_STATION_PRIMARY), locate(world.maxx-TRANSITIONEDGE,world.maxy-TRANSITIONEDGE,ZLEVEL_STATION_PRIMARY)))) //Nontrivially expensive but it's roundstart only
if(isfloorturf(T) && !istype(T, /turf/open/floor/plating/))
free_satchels += new /obj/item/storage/backpack/satchel/flat/secret(T)
if(!isemptylist(free_satchels) && ((free_satchels.len + placed_satchel) >= (50 - old_secret_satchels.len) * 0.1)) //up to six tiles, more than enough to kill anything that moves
new /obj/item/storage/backpack/satchel/flat/secret(T)
free_satchels++
if((free_satchels + placed_satchel) == 10) //ten tiles, more than enough to kill anything that moves
break
/datum/controller/subsystem/persistence/proc/LoadPoly()
@@ -176,8 +183,8 @@ SUBSYSTEM_DEF(persistence)
CollectRoundtype()
/datum/controller/subsystem/persistence/proc/CollectSecretSatchels()
var/list/satchels = list()
satchel_blacklist = typecacheof(list(/obj/item/stack/tile/plasteel, /obj/item/crowbar))
var/list/satchels_to_add = list()
for(var/A in new_secret_satchels)
var/obj/item/storage/backpack/satchel/flat/F = A
if(QDELETED(F) || F.z != ZLEVEL_STATION_PRIMARY || F.invisibility != INVISIBILITY_MAXIMUM)
@@ -196,11 +203,12 @@ SUBSYSTEM_DEF(persistence)
data["x"] = F.x
data["y"] = F.y
data["saved_obj"] = pick(savable_obj)
satchels += list(data)
satchels_to_add += list(data)
var/json_file = file("data/npc_saves/SecretSatchels[SSmapping.config.map_name].json")
var/list/file_data = list()
file_data["data"] = satchels
fdel(json_file)
file_data["data"] = old_secret_satchels + satchels_to_add
WRITE_FILE(json_file, json_encode(file_data))
/datum/controller/subsystem/persistence/proc/CollectChiselMessages()
+12 -9
View File
@@ -10,7 +10,7 @@ SUBSYSTEM_DEF(server_maint)
var/list/currentrun
/datum/controller/subsystem/server_maint/Initialize(timeofday)
if (config.hub)
if (CONFIG_GET(flag/hub))
world.update_hub_visibility(TRUE)
..()
@@ -21,16 +21,19 @@ SUBSYSTEM_DEF(server_maint)
var/list/currentrun = src.currentrun
var/round_started = SSticker.HasRoundStarted()
var/kick_inactive = CONFIG_GET(flag/kick_inactive)
var/afk_period
if(kick_inactive)
afk_period = CONFIG_GET(number/afk_period)
for(var/I in currentrun)
var/client/C = I
//handle kicking inactive players
if(round_started && config.kick_inactive)
if(C.is_afk(config.afk_period))
var/cmob = C.mob
if(!(isobserver(cmob) || (isdead(cmob) && C.holder)))
log_access("AFK: [key_name(C)]")
to_chat(C, "<span class='danger'>You have been inactive for more than [DisplayTimeText(config.afk_period)] and have been disconnected.</span>")
qdel(C)
if(round_started && kick_inactive && C.is_afk(afk_period))
var/cmob = C.mob
if(!(isobserver(cmob) || (isdead(cmob) && C.holder)))
log_access("AFK: [key_name(C)]")
to_chat(C, "<span class='danger'>You have been inactive for more than [DisplayTimeText(afk_period)] and have been disconnected.</span>")
qdel(C)
if (!(!C || world.time - C.connection_time < PING_BUFFER_TIME || C.inactivity >= (wait-1)))
winset(C, null, "command=.update_ping+[world.time+world.tick_lag*TICK_USAGE_REAL/100]")
@@ -40,7 +43,7 @@ SUBSYSTEM_DEF(server_maint)
/datum/controller/subsystem/server_maint/Shutdown()
kick_clients_in_lobby("<span class='boldannounce'>The round came to an end with you in the lobby.</span>", TRUE) //second parameter ensures only afk clients are kicked
var/server = config.server
var/server = CONFIG_GET(string/server)
for(var/thing in GLOB.clients)
if(!thing)
continue
+3 -3
View File
@@ -176,9 +176,9 @@ SUBSYSTEM_DEF(shuttle)
Good luck.")
return
emergency = backup_shuttle
if(world.time - SSticker.round_start_time < config.shuttle_refuel_delay)
to_chat(user, "The emergency shuttle is refueling. Please wait [DisplayTimeText((world.time - SSticker.round_start_time) - config.shuttle_refuel_delay)] before trying again.")
var/srd = CONFIG_GET(number/shuttle_refuel_delay)
if(world.time - SSticker.round_start_time < srd)
to_chat(user, "The emergency shuttle is refueling. Please wait [DisplayTimeText(srd - (world.time - SSticker.round_start_time))] before trying again.")
return
switch(emergency.mode)
+2 -1
View File
@@ -10,7 +10,8 @@ SUBSYSTEM_DEF(squeak)
var/list/exposed_wires = list()
/datum/controller/subsystem/squeak/Initialize(timeofday)
trigger_migration(config.mice_roundstart)
trigger_migration(CONFIG_GET(number/mice_roundstart))
return ..()
/datum/controller/subsystem/squeak/proc/trigger_migration(num_mice=10)
if(!num_mice)
+10 -1
View File
@@ -57,6 +57,9 @@ SUBSYSTEM_DEF(throwing)
var/pure_diagonal
var/diagonal_error
var/datum/callback/callback
var/paused = FALSE
var/delayed_time = 0
var/last_move = 0
/datum/thrownthing/proc/tick()
var/atom/movable/AM = thrownthing
@@ -64,14 +67,20 @@ SUBSYSTEM_DEF(throwing)
finalize()
return
if(paused)
delayed_time += world.time - last_move
return
if (dist_travelled && hitcheck()) //to catch sneaky things moving on our tile while we slept
finalize()
return
var/atom/step
last_move = world.time
//calculate how many tiles to move, making up for any missed ticks.
var/tilestomove = Ceiling(min(((((world.time+world.tick_lag) - start_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed*MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait))
var/tilestomove = Ceiling(min(((((world.time+world.tick_lag) - start_time + delayed_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed*MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait))
while (tilestomove-- > 0)
if ((dist_travelled >= maxrange || AM.loc == target_turf) && AM.has_gravity(AM.loc))
finalize()
+16 -152
View File
@@ -51,14 +51,14 @@ SUBSYSTEM_DEF(ticker)
var/queue_delay = 0
var/list/queued_players = list() //used for join queues when the server exceeds the hard population cap
var/obj/screen/cinematic = null //used for station explosion cinematic
var/maprotatechecked = 0
var/news_report
var/late_join_disabled
var/roundend_check_paused = FALSE
var/round_start_time = 0
var/list/round_start_events
var/mode_result = "undefined"
@@ -79,16 +79,18 @@ SUBSYSTEM_DEF(ticker)
if(!GLOB.syndicate_code_response)
GLOB.syndicate_code_response = generate_code_phrase()
..()
start_at = world.time + (config.lobby_countdown * 10)
start_at = world.time + (CONFIG_GET(number/lobby_countdown) * 10)
/datum/controller/subsystem/ticker/fire()
switch(current_state)
if(GAME_STATE_STARTUP)
if(Master.initializations_finished_with_no_players_logged_in)
start_at = world.time + (config.lobby_countdown * 10)
start_at = world.time + (CONFIG_GET(number/lobby_countdown) * 10)
for(var/client/C in GLOB.clients)
window_flash(C, ignorepref = TRUE) //let them know lobby has opened up.
to_chat(world, "<span class='boldnotice'>Welcome to [station_name()]!</span>")
if(CONFIG_GET(flag/irc_announce_new_game))
SERVER_TOOLS_CHAT_BROADCAST("New round starting on [SSmapping.config.map_name]!")
current_state = GAME_STATE_PREGAME
//Everyone who wants to be an observer is now spawned
create_observers()
@@ -137,7 +139,7 @@ SUBSYSTEM_DEF(ticker)
scripture_states = scripture_unlock_alert(scripture_states)
SSshuttle.autoEnd()
if(!mode.explosion_in_progress && mode.check_finished(force_ending) || force_ending)
if(!roundend_check_paused && mode.check_finished(force_ending) || force_ending)
current_state = GAME_STATE_FINISHED
toggle_ooc(TRUE) // Turn it on
toggle_dooc(TRUE)
@@ -207,7 +209,7 @@ SUBSYSTEM_DEF(ticker)
else
mode.announce()
if(!config.ooc_during_round)
if(!CONFIG_GET(flag/ooc_during_round))
toggle_ooc(FALSE) // Turn it off
CHECK_TICK
@@ -280,144 +282,7 @@ SUBSYSTEM_DEF(ticker)
qdel(bomb)
if(epi)
explosion(epi, 0, 256, 512, 0, TRUE, TRUE, 0, TRUE)
//Plus it provides an easy way to make cinematics for other events. Just use this as a template
/datum/controller/subsystem/ticker/proc/station_explosion_cinematic(station_missed=0, override = null, atom/bomb = null)
if( cinematic )
return //already a cinematic in progress!
for (var/datum/html_interface/hi in GLOB.html_interfaces)
hi.closeAll()
SStgui.close_all_uis()
//Turn off the shuttles, there's no escape now
if(!station_missed && bomb)
SSshuttle.registerHostileEnvironment(src)
SSshuttle.lockdown = TRUE
//initialise our cinematic screen object
cinematic = new /obj/screen{icon='icons/effects/station_explosion.dmi';icon_state="station_intact";layer=21;mouse_opacity = MOUSE_OPACITY_TRANSPARENT;screen_loc="1,0";}(src)
for(var/mob/M in GLOB.mob_list)
M.notransform = TRUE //stop everything moving
if(M.client)
M.client.screen += cinematic //show every client the cinematic
var/actually_blew_up = TRUE
//Now animate the cinematic
switch(station_missed)
if(NUKE_NEAR_MISS) //nuke was nearby but (mostly) missed
if(mode && !override )
override = mode.name
switch( override )
if("nuclear emergency") //Nuke wasn't on station when it blew up
flick("intro_nuke",cinematic)
sleep(35)
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
station_explosion_detonation(bomb)
flick("station_intact_fade_red",cinematic)
cinematic.icon_state = "summary_nukefail"
if("cult")
cinematic.icon_state = null
flick("intro_cult",cinematic)
sleep(25)
SEND_SOUND(world, sound('sound/magic/enter_blood.ogg'))
sleep(28)
SEND_SOUND(world, sound('sound/machines/terminal_off.ogg'))
sleep(20)
flick("station_corrupted",cinematic)
SEND_SOUND(world, sound('sound/effects/ghost.ogg'))
actually_blew_up = FALSE
if("fake") //The round isn't over, we're just freaking people out for fun
flick("intro_nuke",cinematic)
sleep(35)
SEND_SOUND(world, sound('sound/items/bikehorn.ogg'))
flick("summary_selfdes",cinematic)
actually_blew_up = FALSE
else
flick("intro_nuke",cinematic)
sleep(35)
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
station_explosion_detonation(bomb)
if(NUKE_MISS_STATION || NUKE_SYNDICATE_BASE) //nuke was nowhere nearby //TODO: a really distant explosion animation
sleep(50)
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
station_explosion_detonation(bomb)
actually_blew_up = station_missed == NUKE_SYNDICATE_BASE //don't kill everyone on station if it detonated off station
else //station was destroyed
if( mode && !override )
override = mode.name
switch( override )
if("nuclear emergency") //Nuke Ops successfully bombed the station
flick("intro_nuke",cinematic)
sleep(35)
flick("station_explode_fade_red",cinematic)
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
station_explosion_detonation(bomb)
cinematic.icon_state = "summary_nukewin"
if("AI malfunction") //Malf (screen,explosion,summary)
flick("intro_malf",cinematic)
sleep(76)
flick("station_explode_fade_red",cinematic)
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
station_explosion_detonation(bomb) //TODO: If we ever decide to actually detonate the vault bomb
cinematic.icon_state = "summary_malf"
if("blob") //Station nuked (nuke,explosion,summary)
flick("intro_nuke",cinematic)
sleep(35)
flick("station_explode_fade_red",cinematic)
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
station_explosion_detonation(bomb) //TODO: no idea what this case could be
cinematic.icon_state = "summary_selfdes"
if("cult") //Station nuked (nuke,explosion,summary)
flick("intro_nuke",cinematic)
sleep(35)
flick("station_explode_fade_red",cinematic)
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
station_explosion_detonation(bomb) //TODO: no idea what this case could be
cinematic.icon_state = "summary_cult"
if("no_core") //Nuke failed to detonate as it had no core
flick("intro_nuke",cinematic)
sleep(35)
flick("station_intact",cinematic)
SEND_SOUND(world, sound('sound/ambience/signal.ogg'))
addtimer(CALLBACK(src, .proc/finish_cinematic, null, FALSE), 100)
return //Faster exit, since nothing happened
else //Station nuked (nuke,explosion,summary)
flick("intro_nuke",cinematic)
sleep(35)
flick("station_explode_fade_red", cinematic)
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
station_explosion_detonation(bomb)
cinematic.icon_state = "summary_selfdes"
//If its actually the end of the round, wait for it to end.
//Otherwise if its a verb it will continue on afterwards.
var/bombloc = null
if(actually_blew_up)
if(bomb && bomb.loc)
bombloc = bomb.z
else if(!station_missed)
bombloc = ZLEVEL_STATION_PRIMARY
if(mode)
mode.explosion_in_progress = 0
to_chat(world, "<B>The station was destoyed by the nuclear blast!</B>")
mode.station_was_nuked = (station_missed<2) //station_missed==1 is a draw. the station becomes irradiated and needs to be evacuated.
addtimer(CALLBACK(src, .proc/finish_cinematic, bombloc, actually_blew_up), 300)
/datum/controller/subsystem/ticker/proc/finish_cinematic(killz, actually_blew_up)
if(cinematic)
qdel(cinematic) //end the cinematic
cinematic = null
for(var/mob/M in GLOB.mob_list)
M.notransform = FALSE
if(actually_blew_up && !isnull(killz) && M.stat != DEAD && M.z == killz)
M.gib()
/datum/controller/subsystem/ticker/proc/create_characters()
for(var/mob/dead/new_player/player in GLOB.player_list)
if(player.ready == PLAYER_READY_TO_PLAY && player.mind)
@@ -575,7 +440,7 @@ SUBSYSTEM_DEF(ticker)
CHECK_TICK
if(config.cross_allowed)
if(CONFIG_GET(string/cross_server_address))
send_news_report()
CHECK_TICK
@@ -672,7 +537,8 @@ SUBSYSTEM_DEF(ticker)
to_chat(world, "<font color='purple'><b>Tip of the round: </b>[html_encode(m)]</font>")
/datum/controller/subsystem/ticker/proc/check_queue()
if(!queued_players.len || !config.hard_popcap)
var/hpc = CONFIG_GET(number/hard_popcap)
if(!queued_players.len || !hpc)
return
queue_delay++
@@ -680,7 +546,7 @@ SUBSYSTEM_DEF(ticker)
switch(queue_delay)
if(5) //every 5 ticks check if there is a slot available
if(living_player_count() < config.hard_popcap)
if(living_player_count() < hpc)
if(next_in_line && next_in_line.client)
to_chat(next_in_line, "<span class='userdanger'>A slot has opened! You have approximately 20 seconds to join. <a href='?src=\ref[next_in_line];late_join=override'>\>\>Join Game\<\<</a></span>")
SEND_SOUND(next_in_line, sound('sound/misc/notice1.ogg'))
@@ -694,7 +560,7 @@ SUBSYSTEM_DEF(ticker)
queue_delay = 0
/datum/controller/subsystem/ticker/proc/check_maprotate()
if (!config.maprotation)
if (!CONFIG_GET(flag/maprotation))
return
if (SSshuttle.emergency && SSshuttle.emergency.mode != SHUTTLE_ESCAPE || SSshuttle.canRecall())
return
@@ -704,7 +570,7 @@ SUBSYSTEM_DEF(ticker)
maprotatechecked = 1
//map rotate chance defaults to 75% of the length of the round (in minutes)
if (!prob((world.time/600)*config.maprotatechancedelta))
if (!prob((world.time/600)*CONFIG_GET(number/maprotatechancedelta)))
return
INVOKE_ASYNC(SSmapping, /datum/controller/subsystem/mapping/.proc/maprotate)
@@ -751,13 +617,11 @@ SUBSYSTEM_DEF(ticker)
queue_delay = SSticker.queue_delay
queued_players = SSticker.queued_players
cinematic = SSticker.cinematic
maprotatechecked = SSticker.maprotatechecked
round_start_time = SSticker.round_start_time
queue_delay = SSticker.queue_delay
queued_players = SSticker.queued_players
cinematic = SSticker.cinematic
maprotatechecked = SSticker.maprotatechecked
modevoted = SSticker.modevoted
@@ -866,7 +730,7 @@ SUBSYSTEM_DEF(ticker)
return
if(!delay)
delay = config.round_end_countdown * 10
delay = CONFIG_GET(number/round_end_countdown) * 10
var/skip_delay = check_rights()
if(delay_end && !skip_delay)
+17 -14
View File
@@ -18,7 +18,7 @@ SUBSYSTEM_DEF(vote)
/datum/controller/subsystem/vote/fire() //called by master_controller
if(mode)
time_remaining = round((started_time + config.vote_period - world.time)/10)
time_remaining = round((started_time + CONFIG_GET(number/vote_period) - world.time)/10)
if(time_remaining < 0)
result()
@@ -54,7 +54,7 @@ SUBSYSTEM_DEF(vote)
if(votes > greatest_votes)
greatest_votes = votes
//default-vote for everyone who didn't vote
if(!config.vote_no_default && choices.len)
if(!CONFIG_GET(flag/default_no_vote) && choices.len)
var/list/non_voters = GLOB.directory.Copy()
non_voters -= voted
for (var/non_voter_ckey in non_voters)
@@ -146,7 +146,7 @@ SUBSYSTEM_DEF(vote)
/datum/controller/subsystem/vote/proc/submit_vote(vote)
if(mode)
if(config.vote_no_dead && usr.stat == DEAD && !usr.client.holder)
if(CONFIG_GET(flag/no_dead_vote) && usr.stat == DEAD && !usr.client.holder)
return 0
if(!(usr.ckey in voted))
if(vote && 1<=vote && vote<=choices.len)
@@ -158,7 +158,7 @@ SUBSYSTEM_DEF(vote)
/datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key)
if(!mode)
if(started_time)
var/next_allowed_time = (started_time + config.vote_delay)
var/next_allowed_time = (started_time + CONFIG_GET(number/vote_delay))
if(mode)
to_chat(usr, "<span class='warning'>There is already a vote in progress! please wait for it to finish.</span>")
return 0
@@ -198,8 +198,9 @@ SUBSYSTEM_DEF(vote)
if(mode == "custom")
text += "\n[question]"
log_vote(text)
to_chat(world, "\n<font color='purple'><b>[text]</b>\nType <b>vote</b> or click <a href='?src=\ref[src]'>here</a> to place your votes.\nYou have [DisplayTimeText(config.vote_period)] to vote.</font>")
time_remaining = round(config.vote_period/10)
var/vp = CONFIG_GET(number/vote_period)
to_chat(world, "\n<font color='purple'><b>[text]</b>\nType <b>vote</b> or click <a href='?src=\ref[src]'>here</a> to place your votes.\nYou have [DisplayTimeText(vp)] to vote.</font>")
time_remaining = round(vp/10)
for(var/c in GLOB.clients)
var/client/C = c
var/datum/action/vote/V = new
@@ -238,20 +239,22 @@ SUBSYSTEM_DEF(vote)
else
. += "<h2>Start a vote:</h2><hr><ul><li>"
//restart
if(trialmin || config.allow_vote_restart)
var/avr = CONFIG_GET(flag/allow_vote_restart)
if(trialmin || avr)
. += "<a href='?src=\ref[src];vote=restart'>Restart</a>"
else
. += "<font color='grey'>Restart (Disallowed)</font>"
if(trialmin)
. += "\t(<a href='?src=\ref[src];vote=toggle_restart'>[config.allow_vote_restart?"Allowed":"Disallowed"]</a>)"
. += "\t(<a href='?src=\ref[src];vote=toggle_restart'>[avr ? "Allowed" : "Disallowed"]</a>)"
. += "</li><li>"
//gamemode
if(trialmin || config.allow_vote_mode)
var/avm = CONFIG_GET(flag/allow_vote_mode)
if(trialmin || avm)
. += "<a href='?src=\ref[src];vote=gamemode'>GameMode</a>"
else
. += "<font color='grey'>GameMode (Disallowed)</font>"
if(trialmin)
. += "\t(<a href='?src=\ref[src];vote=toggle_gamemode'>[config.allow_vote_mode?"Allowed":"Disallowed"]</a>)"
. += "\t(<a href='?src=\ref[src];vote=toggle_gamemode'>[avm ? "Allowed" : "Disallowed"]</a>)"
. += "</li>"
//custom
@@ -275,15 +278,15 @@ SUBSYSTEM_DEF(vote)
reset()
if("toggle_restart")
if(usr.client.holder)
config.allow_vote_restart = !config.allow_vote_restart
CONFIG_SET(flag/allow_vote_restart, !CONFIG_GET(flag/allow_vote_restart))
if("toggle_gamemode")
if(usr.client.holder)
config.allow_vote_mode = !config.allow_vote_mode
CONFIG_SET(flag/allow_vote_mode, !CONFIG_GET(flag/allow_vote_mode))
if("restart")
if(config.allow_vote_restart || usr.client.holder)
if(CONFIG_GET(flag/allow_vote_restart) || usr.client.holder)
initiate_vote("restart",usr.key)
if("gamemode")
if(config.allow_vote_mode || usr.client.holder)
if(CONFIG_GET(flag/allow_vote_mode) || usr.client.holder)
initiate_vote("gamemode",usr.key)
if("custom")
if(usr.client.holder)
+17 -13
View File
@@ -485,7 +485,7 @@
/datum/action/spell_action/New(Target)
..()
var/obj/effect/proc_holder/spell/S = target
var/obj/effect/proc_holder/S = target
S.action = src
name = S.name
desc = S.desc
@@ -495,36 +495,40 @@
button.name = name
/datum/action/spell_action/Destroy()
var/obj/effect/proc_holder/spell/S = target
var/obj/effect/proc_holder/S = target
S.action = null
return ..()
/datum/action/spell_action/Trigger()
if(!..())
return 0
return FALSE
if(target)
var/obj/effect/proc_holder/spell = target
spell.Click()
return 1
var/obj/effect/proc_holder/S = target
S.Click()
return TRUE
/datum/action/spell_action/IsAvailable()
if(!target)
return 0
var/obj/effect/proc_holder/spell/spell = target
if(owner)
return spell.can_cast(owner)
return 0
return FALSE
return TRUE
/datum/action/spell_action/spell/IsAvailable()
if(!target)
return FALSE
var/obj/effect/proc_holder/spell/S = target
if(owner)
return S.can_cast(owner)
return FALSE
/datum/action/spell_action/alien
/datum/action/spell_action/alien/IsAvailable()
if(!target)
return 0
return FALSE
var/obj/effect/proc_holder/alien/ab = target
if(owner)
return ab.cost_check(ab.check_turf,owner,1)
return 0
return FALSE
+7 -13
View File
@@ -208,7 +208,8 @@
/* General ai_law functions */
/datum/ai_laws/proc/set_laws_config()
switch(config.default_laws)
var/list/law_ids = CONFIG_GET(keyed_flag_list/random_laws)
switch(CONFIG_GET(number/default_laws))
if(0)
add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.")
add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.")
@@ -220,7 +221,7 @@
var/list/randlaws = list()
for(var/lpath in subtypesof(/datum/ai_laws))
var/datum/ai_laws/L = lpath
if(initial(L.id) in config.lawids)
if(initial(L.id) in law_ids)
randlaws += lpath
var/datum/ai_laws/lawtype
if(randlaws.len)
@@ -234,21 +235,14 @@
if(3)
pick_weighted_lawset()
else:
log_law("Invalid law config. Please check silicon_laws.txt")
add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.")
add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.")
add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.")
WARNING("Invalid custom AI laws, check silicon_laws.txt")
/datum/ai_laws/proc/pick_weighted_lawset()
var/datum/ai_laws/lawtype
while(!lawtype && config.law_weights.len)
var/possible_id = pickweight(config.law_weights)
var/list/law_weights = CONFIG_GET(keyed_number_list/law_weight)
while(!lawtype && law_weights.len)
var/possible_id = pickweight(law_weights)
lawtype = lawid_to_type(possible_id)
if(!lawtype)
config.law_weights -= possible_id
law_weights -= possible_id
WARNING("Bad lawid in game_options.txt: [possible_id]")
if(!lawtype)
+10 -8
View File
@@ -103,23 +103,22 @@
S.laws.associate(S)
S.update_icons()
S.show_laws()
hierophant_network.Grant(S)
hierophant_network.title = "Silicon"
hierophant_network.span_for_name = "nezbere"
hierophant_network.span_for_message = "brass"
else if(isbrain(current))
hierophant_network.Grant(current)
hierophant_network.title = "Vessel"
hierophant_network.span_for_name = "nezbere"
hierophant_network.span_for_message = "alloy"
else if(isclockmob(current))
hierophant_network.Grant(current)
hierophant_network.title = "Construct"
hierophant_network.span_for_name = "nezbere"
hierophant_network.span_for_message = "brass"
hierophant_network.Grant(current)
current.throw_alert("clockinfo", /obj/screen/alert/clockwork/infodump)
if(!GLOB.clockwork_gateway_activated)
current.throw_alert("scripturereq", /obj/screen/alert/clockwork/scripture_reqs)
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
if(G.active && ishuman(current))
current.add_overlay(mutable_appearance('icons/effects/genetics.dmi', "servitude", -MUTATIONS_LAYER))
/datum/antagonist/clockcult/remove_innate_effects(mob/living/mob_override)
var/mob/living/current = owner.current
@@ -129,9 +128,10 @@
current.faction -= "ratvar"
current.remove_language(/datum/language/ratvar)
current.clear_alert("clockinfo")
current.clear_alert("scripturereq")
for(var/datum/action/innate/function_call/F in owner.current.actions) //Removes any bound Ratvarian spears
qdel(F)
for(var/datum/action/innate/clockwork_arnaments/C in owner.current.actions) //Removes any bound clockwork armor
qdel(C)
for(var/datum/action/innate/call_weapon/W in owner.current.actions) //and weapons too
qdel(W)
if(issilicon(current))
var/mob/living/silicon/S = current
if(isAI(S))
@@ -149,6 +149,8 @@
R.module.rebuild_modules()
if(temp_owner)
temp_owner.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them, we need to update buttons
temp_owner.cut_overlays()
temp_owner.regenerate_icons()
/datum/antagonist/clockcult/on_removal()
SSticker.mode.servants_of_ratvar -= owner
+19 -19
View File
@@ -85,7 +85,7 @@
if(owner.assigned_role == "Clown")
var/mob/living/carbon/human/traitor_mob = owner.current
if(traitor_mob&&istype(traitor_mob))
if(!silent)
if(!silent)
to_chat(traitor_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
traitor_mob.dna.remove_mutation(CLOWNMUT)
@@ -138,10 +138,11 @@
assign_exchange_role(SSticker.mode.exchange_red)
assign_exchange_role(SSticker.mode.exchange_blue)
objective_count += 1 //Exchange counts towards number of objectives
for(var/i = objective_count, i < config.traitor_objectives_amount, i++)
var/toa = CONFIG_GET(number/traitor_objectives_amount)
for(var/i = objective_count, i < toa, i++)
forge_single_objective()
if(is_hijacker && objective_count <= config.traitor_objectives_amount) //Don't assign hijack if it would exceed the number of objectives set in config.traitor_objectives_amount
if(is_hijacker && objective_count <= toa) //Don't assign hijack if it would exceed the number of objectives set in config.traitor_objectives_amount
if (!(locate(/datum/objective/hijack) in owner.objectives))
var/datum/objective/hijack/hijack_objective = new
hijack_objective.owner = owner
@@ -173,18 +174,11 @@
if(prob(30))
objective_count += forge_single_objective()
for(var/i = objective_count, i < config.traitor_objectives_amount, i++)
if(prob(20)) //AI's are less likely to look for a late-joiner than normal traitors
var/datum/objective/assassinate/late/late_objective = new
late_objective.owner = owner
late_objective.find_target()
add_objective(late_objective)
else
var/datum/objective/assassinate/kill_objective = new
kill_objective.owner = owner
kill_objective.find_target()
add_objective(kill_objective)
for(var/i = objective_count, i < CONFIG_GET(number/traitor_objectives_amount), i++)
var/datum/objective/assassinate/kill_objective = new
kill_objective.owner = owner
kill_objective.find_target()
add_objective(kill_objective)
var/datum/objective/survive/exist/exist_objective = new
exist_objective.owner = owner
@@ -216,10 +210,16 @@
kill_objective.find_target()
add_objective(kill_objective)
else
var/datum/objective/steal/steal_objective = new
steal_objective.owner = owner
steal_objective.find_target()
add_objective(steal_objective)
if(prob(15) && !(locate(/datum/objective/download in owner.objectives)))
var/datum/objective/download/download_objective = new
download_objective.owner = owner
download_objective.gen_amount_goal()
add_objective(download_objective)
else
var/datum/objective/steal/steal_objective = new
steal_objective.owner = owner
steal_objective.find_target()
add_objective(steal_objective)
/datum/antagonist/traitor/AI/forge_single_objective()
.=1
+2 -2
View File
@@ -205,7 +205,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
/datum/antagonist/devil/proc/regress_blood_lizard()
var/mob/living/carbon/true_devil/D = owner.current
to_chat(D, "<span class='warning'>Your powers weaken, have more contracts be signed to regain power.</span>")
D.oldform.loc = D.loc
D.oldform.forceMove(D.drop_location())
owner.transfer_to(D.oldform)
give_appropriate_spells()
qdel(D)
@@ -236,7 +236,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
sleep(50)
var/mob/living/carbon/true_devil/A = new /mob/living/carbon/true_devil(owner.current.loc)
A.faction |= "hell"
owner.current.loc = A
owner.current.forceMove(A)
A.oldform = owner.current
owner.transfer_to(A)
A.set_name()
+2 -31
View File
@@ -1,6 +1,5 @@
/datum/antagonist/ninja
name = "Ninja"
var/team
var/helping_station = 0
var/give_objectives = TRUE
@@ -19,36 +18,8 @@
..(new_owner)
helping_station = rand(0,1)
/datum/antagonist/ninja/proc/equip_space_ninja(mob/living/carbon/human/H = owner.current, safety=0)//Safety in case you need to unequip stuff for existing characters.
if(safety)
qdel(H.w_uniform)
qdel(H.wear_suit)
qdel(H.wear_mask)
qdel(H.head)
qdel(H.shoes)
qdel(H.gloves)
var/obj/item/clothing/suit/space/space_ninja/theSuit = new(H)
var/obj/item/dash/energy_katana/EK = new(H)
theSuit.energyKatana = EK
H.equip_to_slot_or_del(new /obj/item/device/radio/headset(H), slot_ears)
H.equip_to_slot_or_del(new /obj/item/clothing/under/color/black(H), slot_w_uniform)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/space_ninja(H), slot_shoes)
H.equip_to_slot_or_del(theSuit, slot_wear_suit)
H.equip_to_slot_or_del(new /obj/item/clothing/gloves/space_ninja(H), slot_gloves)
H.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/space_ninja(H), slot_head)
H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/space_ninja(H), slot_wear_mask)
H.equip_to_slot_or_del(new /obj/item/clothing/glasses/night(H), slot_glasses)
H.equip_to_slot_or_del(EK, slot_belt)
H.equip_to_slot_or_del(new /obj/item/grenade/plastic/x4(H), slot_l_store)
H.equip_to_slot_or_del(new /obj/item/tank/internals/emergency_oxygen(H), slot_s_store)
H.equip_to_slot_or_del(new /obj/item/tank/jetpack/carbondioxide(H), slot_back)
theSuit.randomize_param()
var/obj/item/implant/explosive/E = new/obj/item/implant/explosive(H)
E.implant(H)
return 1
/datum/antagonist/ninja/proc/equip_space_ninja(mob/living/carbon/human/H = owner.current)
return H.equipOutfit(/datum/outfit/ninja)
/datum/antagonist/ninja/proc/addMemories()
owner.store_memory("I am an elite mercenary assassin of the mighty Spider Clan. A <font color='red'><B>SPACE NINJA</B></font>!")
+223
View File
@@ -0,0 +1,223 @@
GLOBAL_LIST_EMPTY(cinematics)
// Use to play cinematics.
// Watcher can be world,mob, or a list of mobs
// Blocks until sequence is done.
/proc/Cinematic(id,watcher,datum/callback/special_callback)
var/datum/cinematic/playing
for(var/V in subtypesof(/datum/cinematic))
var/datum/cinematic/C = V
if(initial(C.id) == id)
playing = new V()
break
if(!playing)
CRASH("Cinematic type not found")
if(special_callback)
playing.special_callback = special_callback
if(watcher == world)
playing.is_global = TRUE
watcher = GLOB.mob_list
playing.play(watcher)
/obj/screen/cinematic
icon = 'icons/effects/station_explosion.dmi'
icon_state = "station_intact"
layer = 21
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
screen_loc = "1,1"
/datum/cinematic
var/id = CINEMATIC_DEFAULT
var/list/watching = list() //List of clients watching this
var/list/locked = list() //Who had notransform set during the cinematic
var/is_global = FALSE //Global cinematics will override mob-specific ones
var/obj/screen/cinematic/screen
var/datum/callback/special_callback //For special effects synced with animation (explosions after the countdown etc)
var/cleanup_time = 300 //How long for the final screen to remain
/datum/cinematic/New()
GLOB.cinematics += src
screen = new(src)
/datum/cinematic/Destroy()
GLOB.cinematics -= src
QDEL_NULL(screen)
for(var/mob/M in locked)
M.notransform = FALSE
return ..()
/datum/cinematic/proc/play(watchers)
//Check if you can actually play it (stop mob cinematics for global ones) and create screen objects
for(var/A in GLOB.cinematics)
var/datum/cinematic/C = A
if(C == src)
continue
if(C.is_global || !is_global)
return //Can't play two global or local cinematics at the same time
//Close all open windows if global
if(is_global)
for (var/datum/html_interface/hi in GLOB.html_interfaces)
hi.closeAll()
SStgui.close_all_uis()
for(var/mob/M in GLOB.mob_list)
if(M in watchers)
M.notransform = TRUE //Should this be done for non-global cinematics or even at all ?
locked += M
//Close watcher ui's
SStgui.close_user_uis(M)
if(M.client)
watching += M.client
M.client.screen += screen
else
if(is_global)
M.notransform = TRUE
locked += M
//Actually play it
content()
//Cleanup
sleep(cleanup_time)
qdel(src)
//Sound helper
/datum/cinematic/proc/cinematic_sound(s)
if(is_global)
SEND_SOUND(world,s)
else
for(var/C in watching)
SEND_SOUND(C,s)
//Fire up special callback for actual effects synchronized with animation (eg real nuke explosion happens midway)
/datum/cinematic/proc/special()
if(special_callback)
special_callback.Invoke()
//Actual cinematic goes in here
/datum/cinematic/proc/content()
sleep(50)
/datum/cinematic/nuke_win
id = CINEMATIC_NUKE_WIN
/datum/cinematic/nuke_win/content()
flick("intro_nuke",screen)
sleep(35)
flick("station_explode_fade_red",screen)
cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
special()
screen.icon_state = "summary_nukewin"
/datum/cinematic/nuke_miss
id = CINEMATIC_NUKE_MISS
/datum/cinematic/nuke_miss/content()
flick("intro_nuke",screen)
sleep(35)
cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
special()
flick("station_intact_fade_red",screen)
screen.icon_state = "summary_nukefail"
//Also used for blob
/datum/cinematic/nuke_selfdestruct
id = CINEMATIC_SELFDESTRUCT
/datum/cinematic/nuke_selfdestruct/content()
flick("intro_nuke",screen)
sleep(35)
flick("station_explode_fade_red", screen)
cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
special()
screen.icon_state = "summary_selfdes"
/datum/cinematic/nuke_selfdestruct_miss
id = CINEMATIC_SELFDESTRUCT_MISS
/datum/cinematic/nuke_selfdestruct_miss/content()
flick("intro_nuke",screen)
sleep(35)
cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
special()
screen.icon_state = "station_intact"
/datum/cinematic/malf
id = CINEMATIC_MALF
/datum/cinematic/malf/content()
flick("intro_malf",screen)
sleep(76)
flick("station_explode_fade_red",screen)
cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
special()
screen.icon_state = "summary_malf"
/datum/cinematic/cult
id = CINEMATIC_CULT
/datum/cinematic/cult/content()
screen.icon_state = null
flick("intro_cult",screen)
sleep(25)
cinematic_sound(sound('sound/magic/enter_blood.ogg'))
sleep(28)
cinematic_sound(sound('sound/machines/terminal_off.ogg'))
sleep(20)
flick("station_corrupted",screen)
cinematic_sound(sound('sound/effects/ghost.ogg'))
sleep(70)
special()
/datum/cinematic/nuke_annihilation
id = CINEMATIC_ANNIHILATION
/datum/cinematic/nuke_annihilation/content()
flick("intro_nuke",screen)
sleep(35)
flick("station_explode_fade_red",screen)
cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
special()
screen.icon_state = "summary_totala"
/datum/cinematic/fake
id = CINEMATIC_NUKE_FAKE
cleanup_time = 100
/datum/cinematic/fake/content()
flick("intro_nuke",screen)
sleep(35)
cinematic_sound(sound('sound/items/bikehorn.ogg'))
flick("summary_selfdes",screen) //???
special()
/datum/cinematic/no_core
id = CINEMATIC_NUKE_NO_CORE
cleanup_time = 100
/datum/cinematic/no_core/content()
flick("intro_nuke",screen)
sleep(35)
flick("station_intact",screen)
cinematic_sound(sound('sound/ambience/signal.ogg'))
sleep(100)
/datum/cinematic/nuke_far
id = CINEMATIC_NUKE_FAR
cleanup_time = 0
/datum/cinematic/nuke_far/content()
cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
special()
/* Intended usage.
Nuke.Explosion()
-> Cinematic(NUKE_BOOM,world)
-> ActualExplosion()
-> Mode.OnExplosion()
Narsie()
-> Cinematic(CULT,world)
*/
+2 -1
View File
@@ -94,7 +94,8 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
* Allows the component to react to ownership transfers
1. `/datum/component/proc/_RemoveNoSignal()` (private, final)
* Internal, clears the parent var and removes the component from the parents component list
1. `/datum/component/proc/RegisterSignal(signal(string), proc_ref(type), override(boolean))` (protected, final) (Consider removing for performance gainz)
1. `/datum/component/proc/RegisterSignal(signal(string/list of strings), proc_ref(type), override(boolean))` (protected, final) (Consider removing for performance gainz)
* If signal is a list it will be as if RegisterSignal was called for each of the entries with the same following arguments
* Makes a component listen for the specified `signal` on it's `parent` datum.
* When that signal is recieved `proc_ref` will be called on the component, along with associated arguments
* Example proc ref: `.proc/OnEvent`
+9 -7
View File
@@ -95,7 +95,7 @@
P.datum_components = null
parent = null
/datum/component/proc/RegisterSignal(sig_type, proc_on_self, override = FALSE)
/datum/component/proc/RegisterSignal(sig_type_or_types, proc_on_self, override = FALSE)
if(QDELETED(src))
return
var/list/procs = signal_procs
@@ -103,12 +103,14 @@
procs = list()
signal_procs = procs
if(!override)
. = procs[sig_type]
if(.)
stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning")
procs[sig_type] = CALLBACK(src, proc_on_self)
var/list/sig_types = islist(sig_type_or_types) ? sig_type_or_types : list(sig_type_or_types)
for(var/sig_type in sig_types)
if(!override)
. = procs[sig_type]
if(.)
stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning")
procs[sig_type] = CALLBACK(src, proc_on_self)
/datum/component/proc/InheritComponent(datum/component/C, i_am_original)
return
+4 -1
View File
@@ -52,7 +52,10 @@
/datum/component/material_container/proc/OnAttackBy(obj/item/I, mob/living/user)
var/list/tc = allowed_typecache
if(user.a_intent == INTENT_HARM || (I.flags_2 & HOLOGRAM_2) || (tc && !is_type_in_typecache(I, tc)))
if(user.a_intent == INTENT_HARM)
return FALSE
if((I.flags_2 & (HOLOGRAM_2 | NO_MAT_REDEMPTION_2)) || (tc && !is_type_in_typecache(I, tc)))
to_chat(user, "<span class='warning'>[parent] won't accept [I]!</span>")
return FALSE
. = TRUE
last_insert_success = FALSE
+1 -4
View File
@@ -6,10 +6,7 @@
/datum/component/slippery/Initialize(_intensity, _lube_flags = NONE)
intensity = max(_intensity, 0)
lube_flags = _lube_flags
if(ismovableatom(parent))
RegisterSignal(COMSIG_MOVABLE_CROSSED, .proc/Slip)
else
RegisterSignal(COMSIG_ATOM_ENTERED, .proc/Slip)
RegisterSignal(list(COMSIG_MOVABLE_CROSSED, COMSIG_ATOM_ENTERED), .proc/Slip)
/datum/component/slippery/proc/Slip(atom/movable/AM)
var/mob/victim = AM
+3 -16
View File
@@ -24,22 +24,9 @@
if(use_delay_override)
use_delay = use_delay_override
if(istype(parent, /atom))
RegisterSignal(COMSIG_ATOM_BLOB_ACT, .proc/play_squeak)
RegisterSignal(COMSIG_ATOM_HULK_ATTACK, .proc/play_squeak)
RegisterSignal(COMSIG_PARENT_ATTACKBY, .proc/play_squeak)
if(istype(parent, /atom/movable))
RegisterSignal(COMSIG_MOVABLE_CROSSED, .proc/play_squeak)
RegisterSignal(COMSIG_MOVABLE_COLLIDE, .proc/play_squeak)
RegisterSignal(COMSIG_MOVABLE_IMPACT, .proc/play_squeak)
if(istype(parent, /obj/item))
RegisterSignal(COMSIG_ITEM_ATTACK, .proc/play_squeak)
RegisterSignal(COMSIG_ITEM_ATTACK_SELF, .proc/use_squeak)
RegisterSignal(COMSIG_ITEM_ATTACK_OBJ, .proc/play_squeak)
if(istype(parent, /obj/item/clothing/shoes))
RegisterSignal(COMSIG_SHOES_STEP_ACTION, .proc/step_squeak)
else
RegisterSignal(COMSIG_ATOM_ENTERED, .proc/play_squeak)
RegisterSignal(list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_BLOB_ACT, COMSIG_ATOM_HULK_ATTACK, COMSIG_PARENT_ATTACKBY, COMSIG_MOVABLE_CROSSED, COMSIG_MOVABLE_COLLIDE, COMSIG_MOVABLE_IMPACT, COMSIG_ITEM_ATTACK, COMSIG_ITEM_ATTACK_OBJ), .proc/play_squeak)
RegisterSignal(COMSIG_ITEM_ATTACK_SELF, .proc/use_squeak)
RegisterSignal(COMSIG_SHOES_STEP_ACTION, .proc/step_squeak)
/datum/component/squeak/proc/play_squeak()
if(prob(squeak_chance))
+1 -1
View File
@@ -222,7 +222,7 @@
G.fields["name"] = H.real_name
G.fields["rank"] = assignment
G.fields["age"] = H.age
if(config.mutant_races)
if(CONFIG_GET(flag/join_with_mutant_race))
G.fields["species"] = H.dna.species.name
G.fields["fingerprint"] = md5(H.dna.uni_identity)
G.fields["p_stat"] = "Active"
@@ -68,8 +68,8 @@ Bonus
/datum/symptom/viralreverse
name = "Viral aggressive metabolism"
desc = "The virus sacrifices its long term survivability to gain a near-instant spread when inside a host. \
The virus will start at the lastest stage, but will eventually decay and die off by itself."
desc = "The virus sacrifices its long term survivability to nearly instantly fully spread inside a host. \
The virus will start at the last stage, but will eventually decay and die off by itself."
stealth = -2
resistance = 1
stage_speed = 3
+1 -1
View File
@@ -22,6 +22,6 @@
/datum/disease/parrot_possession/cure()
if(parrot && parrot.loc == affected_mob)
parrot.loc = affected_mob.loc
parrot.forceMove(affected_mob.drop_location())
affected_mob.visible_message("<span class='danger'>[parrot] is violently driven out of [affected_mob]!</span>", "<span class='userdanger'>[parrot] bursts out of your chest!</span>")
..()
+115 -115
View File
@@ -1,115 +1,115 @@
/datum/disease/wizarditis
name = "Wizarditis"
max_stages = 4
spread_text = "Airborne"
cure_text = "The Manly Dorf"
cures = list("manlydorf")
cure_chance = 100
agent = "Rincewindus Vulgaris"
viable_mobtypes = list(/mob/living/carbon/human)
disease_flags = CAN_CARRY|CAN_RESIST|CURABLE
permeability_mod = 0.75
desc = "Some speculate that this virus is the cause of the Space Wizard Federation's existence. Subjects affected show the signs of mental retardation, yelling obscure sentences or total gibberish. On late stages subjects sometime express the feelings of inner power, and, cite, 'the ability to control the forces of cosmos themselves!' A gulp of strong, manly spirits usually reverts them to normal, humanlike, condition."
severity = HARMFUL
required_organs = list(/obj/item/bodypart/head)
/*
BIRUZ BENNAR
SCYAR NILA - teleport
NEC CANTIO - dis techno
EI NATH - shocking grasp
AULIE OXIN FIERA - knock
TARCOL MINTI ZHERI - forcewall
STI KALY - blind
*/
/datum/disease/wizarditis/stage_act()
..()
switch(stage)
if(2)
if(prob(1)&&prob(50))
affected_mob.say(pick("You shall not pass!", "Expeliarmus!", "By Merlins beard!", "Feel the power of the Dark Side!"))
if(prob(1)&&prob(50))
to_chat(affected_mob, "<span class='danger'>You feel [pick("that you don't have enough mana", "that the winds of magic are gone", "an urge to summon familiar")].</span>")
if(3)
if(prob(1)&&prob(50))
affected_mob.say(pick("NEC CANTIO!","AULIE OXIN FIERA!", "STI KALY!", "TARCOL MINTI ZHERI!"))
if(prob(1)&&prob(50))
to_chat(affected_mob, "<span class='danger'>You feel [pick("the magic bubbling in your veins","that this location gives you a +1 to INT","an urge to summon familiar")].</span>")
if(4)
if(prob(1))
affected_mob.say(pick("NEC CANTIO!","AULIE OXIN FIERA!","STI KALY!","EI NATH!"))
return
if(prob(1)&&prob(50))
to_chat(affected_mob, "<span class='danger'>You feel [pick("the tidal wave of raw power building inside","that this location gives you a +2 to INT and +1 to WIS","an urge to teleport")].</span>")
spawn_wizard_clothes(50)
if(prob(1)&&prob(1))
teleport()
return
/datum/disease/wizarditis/proc/spawn_wizard_clothes(chance = 0)
if(ishuman(affected_mob))
var/mob/living/carbon/human/H = affected_mob
if(prob(chance))
if(!istype(H.head, /obj/item/clothing/head/wizard))
if(!H.dropItemToGround(H.head))
qdel(H.head)
H.equip_to_slot_or_del(new /obj/item/clothing/head/wizard(H), slot_head)
return
if(prob(chance))
if(!istype(H.wear_suit, /obj/item/clothing/suit/wizrobe))
if(!H.dropItemToGround(H.wear_suit))
qdel(H.wear_suit)
H.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe(H), slot_wear_suit)
return
if(prob(chance))
if(!istype(H.shoes, /obj/item/clothing/shoes/sandal/magic))
if(!H.dropItemToGround(H.shoes))
qdel(H.shoes)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal/magic(H), slot_shoes)
return
else
var/mob/living/carbon/H = affected_mob
if(prob(chance))
var/obj/item/staff/S = new(H)
if(!H.put_in_hands(S))
qdel(S)
/datum/disease/wizarditis/proc/teleport()
var/list/theareas = get_areas_in_range(80, affected_mob)
for(var/area/space/S in theareas)
theareas -= S
if(!theareas||!theareas.len)
return
var/area/thearea = pick(theareas)
var/list/L = list()
for(var/turf/T in get_area_turfs(thearea.type))
if(T.z != affected_mob.z) continue
if(T.name == "space") continue
if(!T.density)
var/clear = 1
for(var/obj/O in T)
if(O.density)
clear = 0
break
if(clear)
L+=T
if(!L)
return
affected_mob.say("SCYAR NILA [uppertext(thearea.name)]!")
affected_mob.loc = pick(L)
return
/datum/disease/wizarditis
name = "Wizarditis"
max_stages = 4
spread_text = "Airborne"
cure_text = "The Manly Dorf"
cures = list("manlydorf")
cure_chance = 100
agent = "Rincewindus Vulgaris"
viable_mobtypes = list(/mob/living/carbon/human)
disease_flags = CAN_CARRY|CAN_RESIST|CURABLE
permeability_mod = 0.75
desc = "Some speculate that this virus is the cause of the Space Wizard Federation's existence. Subjects affected show the signs of mental retardation, yelling obscure sentences or total gibberish. On late stages subjects sometime express the feelings of inner power, and, cite, 'the ability to control the forces of cosmos themselves!' A gulp of strong, manly spirits usually reverts them to normal, humanlike, condition."
severity = HARMFUL
required_organs = list(/obj/item/bodypart/head)
/*
BIRUZ BENNAR
SCYAR NILA - teleport
NEC CANTIO - dis techno
EI NATH - shocking grasp
AULIE OXIN FIERA - knock
TARCOL MINTI ZHERI - forcewall
STI KALY - blind
*/
/datum/disease/wizarditis/stage_act()
..()
switch(stage)
if(2)
if(prob(1)&&prob(50))
affected_mob.say(pick("You shall not pass!", "Expeliarmus!", "By Merlins beard!", "Feel the power of the Dark Side!"))
if(prob(1)&&prob(50))
to_chat(affected_mob, "<span class='danger'>You feel [pick("that you don't have enough mana", "that the winds of magic are gone", "an urge to summon familiar")].</span>")
if(3)
if(prob(1)&&prob(50))
affected_mob.say(pick("NEC CANTIO!","AULIE OXIN FIERA!", "STI KALY!", "TARCOL MINTI ZHERI!"))
if(prob(1)&&prob(50))
to_chat(affected_mob, "<span class='danger'>You feel [pick("the magic bubbling in your veins","that this location gives you a +1 to INT","an urge to summon familiar")].</span>")
if(4)
if(prob(1))
affected_mob.say(pick("NEC CANTIO!","AULIE OXIN FIERA!","STI KALY!","EI NATH!"))
return
if(prob(1)&&prob(50))
to_chat(affected_mob, "<span class='danger'>You feel [pick("the tidal wave of raw power building inside","that this location gives you a +2 to INT and +1 to WIS","an urge to teleport")].</span>")
spawn_wizard_clothes(50)
if(prob(1)&&prob(1))
teleport()
return
/datum/disease/wizarditis/proc/spawn_wizard_clothes(chance = 0)
if(ishuman(affected_mob))
var/mob/living/carbon/human/H = affected_mob
if(prob(chance))
if(!istype(H.head, /obj/item/clothing/head/wizard))
if(!H.dropItemToGround(H.head))
qdel(H.head)
H.equip_to_slot_or_del(new /obj/item/clothing/head/wizard(H), slot_head)
return
if(prob(chance))
if(!istype(H.wear_suit, /obj/item/clothing/suit/wizrobe))
if(!H.dropItemToGround(H.wear_suit))
qdel(H.wear_suit)
H.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe(H), slot_wear_suit)
return
if(prob(chance))
if(!istype(H.shoes, /obj/item/clothing/shoes/sandal/magic))
if(!H.dropItemToGround(H.shoes))
qdel(H.shoes)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal/magic(H), slot_shoes)
return
else
var/mob/living/carbon/H = affected_mob
if(prob(chance))
var/obj/item/staff/S = new(H)
if(!H.put_in_hands(S))
qdel(S)
/datum/disease/wizarditis/proc/teleport()
var/list/theareas = get_areas_in_range(80, affected_mob)
for(var/area/space/S in theareas)
theareas -= S
if(!theareas||!theareas.len)
return
var/area/thearea = pick(theareas)
var/list/L = list()
for(var/turf/T in get_area_turfs(thearea.type))
if(T.z != affected_mob.z) continue
if(T.name == "space") continue
if(!T.density)
var/clear = 1
for(var/obj/O in T)
if(O.density)
clear = 0
break
if(clear)
L+=T
if(!L)
return
affected_mob.say("SCYAR NILA [uppertext(thearea.name)]!")
affected_mob.forceMove(pick(L))
return
+393 -401
View File
@@ -1,401 +1,393 @@
/////////////////////////// DNA DATUM
/datum/dna
var/unique_enzymes
var/struc_enzymes
var/uni_identity
var/blood_type
var/datum/species/species = new /datum/species/human() //The type of mutant race the player is if applicable (i.e. potato-man)
var/list/features = list("FFF") //first value is mutant color
var/real_name //Stores the real name of the person who originally got this dna datum. Used primarely for changelings,
var/list/mutations = list() //All mutations are from now on here
var/list/temporary_mutations = list() //Timers for temporary mutations
var/list/previous = list() //For temporary name/ui/ue/blood_type modifications
var/mob/living/holder
/datum/dna/New(mob/living/new_holder)
if(new_holder)
holder = new_holder
/datum/dna/proc/transfer_identity(mob/living/carbon/destination, transfer_SE = 0)
if(!istype(destination))
return
destination.dna.unique_enzymes = unique_enzymes
destination.dna.uni_identity = uni_identity
destination.dna.blood_type = blood_type
destination.set_species(species.type, icon_update=0)
destination.dna.features = features.Copy()
destination.dna.real_name = real_name
destination.dna.temporary_mutations = temporary_mutations.Copy()
if(transfer_SE)
destination.dna.struc_enzymes = struc_enzymes
if(ishuman(destination))
var/mob/living/carbon/human/H = destination
H.give_genitals(TRUE)//This gives the body the genitals of this DNA. Used for any transformations based on DNA
destination.flavor_text = destination.dna.features["flavor_text"] //Update the flavor_text to use new dna text
/datum/dna/proc/copy_dna(datum/dna/new_dna)
new_dna.unique_enzymes = unique_enzymes
new_dna.struc_enzymes = struc_enzymes
new_dna.uni_identity = uni_identity
new_dna.blood_type = blood_type
new_dna.features = features.Copy()
new_dna.species = new species.type
new_dna.real_name = real_name
new_dna.mutations = mutations.Copy()
/datum/dna/proc/add_mutation(mutation_name)
var/datum/mutation/human/HM = GLOB.mutations_list[mutation_name]
HM.on_acquiring(holder)
/datum/dna/proc/remove_mutation(mutation_name)
var/datum/mutation/human/HM = GLOB.mutations_list[mutation_name]
HM.on_losing(holder)
/datum/dna/proc/check_mutation(mutation_name)
var/datum/mutation/human/HM = GLOB.mutations_list[mutation_name]
return mutations.Find(HM)
/datum/dna/proc/remove_all_mutations()
remove_mutation_group(mutations)
/datum/dna/proc/remove_mutation_group(list/group)
if(!group)
return
for(var/datum/mutation/human/HM in group)
HM.force_lose(holder)
/datum/dna/proc/generate_uni_identity()
. = ""
var/list/L = new /list(DNA_UNI_IDENTITY_BLOCKS)
L[DNA_GENDER_BLOCK] = construct_block((holder.gender!=MALE)+1, 2)
if(ishuman(holder))
var/mob/living/carbon/human/H = holder
if(!GLOB.hair_styles_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/hair,GLOB.hair_styles_list, GLOB.hair_styles_male_list, GLOB.hair_styles_female_list)
L[DNA_HAIR_STYLE_BLOCK] = construct_block(GLOB.hair_styles_list.Find(H.hair_style), GLOB.hair_styles_list.len)
L[DNA_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.hair_color)
if(!GLOB.facial_hair_styles_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_hair, GLOB.facial_hair_styles_list, GLOB.facial_hair_styles_male_list, GLOB.facial_hair_styles_female_list)
L[DNA_FACIAL_HAIR_STYLE_BLOCK] = construct_block(GLOB.facial_hair_styles_list.Find(H.facial_hair_style), GLOB.facial_hair_styles_list.len)
L[DNA_FACIAL_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.facial_hair_color)
L[DNA_SKIN_TONE_BLOCK] = construct_block(GLOB.skin_tones.Find(H.skin_tone), GLOB.skin_tones.len)
L[DNA_EYE_COLOR_BLOCK] = sanitize_hexcolor(H.eye_color)
for(var/i=1, i<=DNA_UNI_IDENTITY_BLOCKS, i++)
if(L[i])
. += L[i]
else
. += random_string(DNA_BLOCK_SIZE,GLOB.hex_characters)
return .
/datum/dna/proc/generate_struc_enzymes()
var/list/sorting = new /list(DNA_STRUC_ENZYMES_BLOCKS)
var/result = ""
for(var/datum/mutation/human/A in GLOB.good_mutations + GLOB.bad_mutations + GLOB.not_good_mutations)
if(A.name == RACEMUT && ismonkey(holder))
sorting[A.dna_block] = num2hex(A.lowest_value + rand(0, 256 * 6), DNA_BLOCK_SIZE)
mutations |= A
else
sorting[A.dna_block] = random_string(DNA_BLOCK_SIZE, list("0","1","2","3","4","5","6"))
for(var/B in sorting)
result += B
return result
/datum/dna/proc/generate_unique_enzymes()
. = ""
if(istype(holder))
real_name = holder.real_name
. += md5(holder.real_name)
else
. += random_string(DNA_UNIQUE_ENZYMES_LEN, GLOB.hex_characters)
return .
/datum/dna/proc/update_ui_block(blocknumber)
if(!blocknumber || !ishuman(holder))
return
var/mob/living/carbon/human/H = holder
switch(blocknumber)
if(DNA_HAIR_COLOR_BLOCK)
setblock(uni_identity, blocknumber, sanitize_hexcolor(H.hair_color))
if(DNA_FACIAL_HAIR_COLOR_BLOCK)
setblock(uni_identity, blocknumber, sanitize_hexcolor(H.facial_hair_color))
if(DNA_SKIN_TONE_BLOCK)
setblock(uni_identity, blocknumber, construct_block(GLOB.skin_tones.Find(H.skin_tone), GLOB.skin_tones.len))
if(DNA_EYE_COLOR_BLOCK)
setblock(uni_identity, blocknumber, sanitize_hexcolor(H.eye_color))
if(DNA_GENDER_BLOCK)
setblock(uni_identity, blocknumber, construct_block((H.gender!=MALE)+1, 2))
if(DNA_FACIAL_HAIR_STYLE_BLOCK)
setblock(uni_identity, blocknumber, construct_block(GLOB.facial_hair_styles_list.Find(H.facial_hair_style), GLOB.facial_hair_styles_list.len))
if(DNA_HAIR_STYLE_BLOCK)
setblock(uni_identity, blocknumber, construct_block(GLOB.hair_styles_list.Find(H.hair_style), GLOB.hair_styles_list.len))
/datum/dna/proc/mutations_say_mods(message)
if(message)
for(var/datum/mutation/human/M in mutations)
message = M.say_mod(message)
return message
/datum/dna/proc/mutations_get_spans()
var/list/spans = list()
for(var/datum/mutation/human/M in mutations)
spans |= M.get_spans()
return spans
/datum/dna/proc/species_get_spans()
var/list/spans = list()
if(species)
spans |= species.get_spans()
return spans
/datum/dna/proc/is_same_as(datum/dna/D)
if(uni_identity == D.uni_identity && struc_enzymes == D.struc_enzymes && real_name == D.real_name)
if(species.type == D.species.type && features == D.features && blood_type == D.blood_type)
return 1
return 0
//used to update dna UI, UE, and dna.real_name.
/datum/dna/proc/update_dna_identity()
uni_identity = generate_uni_identity()
unique_enzymes = generate_unique_enzymes()
/datum/dna/proc/initialize_dna(newblood_type)
if(newblood_type)
blood_type = newblood_type
unique_enzymes = generate_unique_enzymes()
uni_identity = generate_uni_identity()
struc_enzymes = generate_struc_enzymes()
features = random_features()
/datum/dna/stored //subtype used by brain mob's stored_dna
/datum/dna/stored/add_mutation(mutation_name) //no mutation changes on stored dna.
return
/datum/dna/stored/remove_mutation(mutation_name)
return
/datum/dna/stored/check_mutation(mutation_name)
return
/datum/dna/stored/remove_all_mutations()
return
/datum/dna/stored/remove_mutation_group(list/group)
return
/////////////////////////// DNA MOB-PROCS //////////////////////
/mob/proc/set_species(datum/species/mrace, icon_update = 1)
return
/mob/living/brain/set_species(datum/species/mrace, icon_update = 1)
if(mrace)
if(ispath(mrace))
stored_dna.species = new mrace()
else
stored_dna.species = mrace //not calling any species update procs since we're a brain, not a monkey/human
/mob/living/carbon/set_species(datum/species/mrace, icon_update = 1)
if(mrace && has_dna())
dna.species.on_species_loss(src)
var/old_species = dna.species
if(ispath(mrace))
dna.species = new mrace()
else
dna.species = mrace
dna.species.on_species_gain(src, old_species)
/mob/living/carbon/human/set_species(datum/species/mrace, icon_update = 1)
..()
if(icon_update)
update_body()
update_hair()
update_body_parts()
update_mutations_overlay()// no lizard with human hulk overlay please.
/mob/proc/has_dna()
return
/mob/living/carbon/has_dna()
return dna
/mob/living/carbon/human/proc/hardset_dna(ui, se, newreal_name, newblood_type, datum/species/mrace, newfeatures)
if(newfeatures)
dna.features = newfeatures
flavor_text = dna.features["flavor_text"] //Update the flavor_text to use new dna text
if(mrace)
var/datum/species/newrace = new mrace.type
newrace.copy_properties_from(mrace)
set_species(newrace, icon_update=0)
if(newreal_name)
real_name = newreal_name
dna.generate_unique_enzymes()
if(newblood_type)
dna.blood_type = newblood_type
if(ui)
dna.uni_identity = ui
updateappearance(icon_update=0)
if(se)
dna.struc_enzymes = se
domutcheck()
give_genitals(TRUE)//Give all genitalia that DNA says you should have, remove any pre-existing ones as this is a hardset!
if(mrace || newfeatures || ui)
update_body()
update_hair()
update_body_parts()
update_mutations_overlay()
/mob/living/carbon/proc/create_dna()
dna = new /datum/dna(src)
if(!dna.species)
var/rando_race = pick(config.roundstart_races)
dna.species = new rando_race()
//proc used to update the mob's appearance after its dna UI has been changed
/mob/living/carbon/proc/updateappearance(icon_update=1, mutcolor_update=0, mutations_overlay_update=0)
if(!has_dna())
return
gender = (deconstruct_block(getblock(dna.uni_identity, DNA_GENDER_BLOCK), 2)-1) ? FEMALE : MALE
/mob/living/carbon/human/updateappearance(icon_update=1, mutcolor_update=0, mutations_overlay_update=0)
..()
var/structure = dna.uni_identity
hair_color = sanitize_hexcolor(getblock(structure, DNA_HAIR_COLOR_BLOCK))
facial_hair_color = sanitize_hexcolor(getblock(structure, DNA_FACIAL_HAIR_COLOR_BLOCK))
skin_tone = GLOB.skin_tones[deconstruct_block(getblock(structure, DNA_SKIN_TONE_BLOCK), GLOB.skin_tones.len)]
eye_color = sanitize_hexcolor(getblock(structure, DNA_EYE_COLOR_BLOCK))
facial_hair_style = GLOB.facial_hair_styles_list[deconstruct_block(getblock(structure, DNA_FACIAL_HAIR_STYLE_BLOCK), GLOB.facial_hair_styles_list.len)]
hair_style = GLOB.hair_styles_list[deconstruct_block(getblock(structure, DNA_HAIR_STYLE_BLOCK), GLOB.hair_styles_list.len)]
if(icon_update)
update_body()
update_hair()
if(mutcolor_update)
update_body_parts()
if(mutations_overlay_update)
update_mutations_overlay()
/mob/proc/domutcheck()
return
/mob/living/carbon/domutcheck(force_powers=0) //Set force_powers to 1 to bypass the power chance
if(!has_dna())
return
for(var/datum/mutation/human/A in GLOB.good_mutations | GLOB.bad_mutations | GLOB.not_good_mutations)
if(ismob(A.check_block(src, force_powers)))
return //we got monkeyized/humanized, this mob will be deleted, no need to continue.
update_mutations_overlay()
/////////////////////////// DNA HELPER-PROCS //////////////////////////////
/proc/getleftblocks(input,blocknumber,blocksize)
if(blocknumber > 1)
return copytext(input,1,((blocksize*blocknumber)-(blocksize-1)))
/proc/getrightblocks(input,blocknumber,blocksize)
if(blocknumber < (length(input)/blocksize))
return copytext(input,blocksize*blocknumber+1,length(input)+1)
/proc/getblock(input, blocknumber, blocksize=DNA_BLOCK_SIZE)
return copytext(input, blocksize*(blocknumber-1)+1, (blocksize*blocknumber)+1)
/proc/setblock(istring, blocknumber, replacement, blocksize=DNA_BLOCK_SIZE)
if(!istring || !blocknumber || !replacement || !blocksize)
return 0
return getleftblocks(istring, blocknumber, blocksize) + replacement + getrightblocks(istring, blocknumber, blocksize)
/mob/living/carbon/proc/randmut(list/candidates, difficulty = 2)
if(!has_dna())
return
var/datum/mutation/human/num = pick(candidates)
. = num.force_give(src)
/mob/living/carbon/proc/randmutb()
if(!has_dna())
return
var/datum/mutation/human/HM = pick((GLOB.bad_mutations | GLOB.not_good_mutations) - GLOB.mutations_list[RACEMUT])
. = HM.force_give(src)
/mob/living/carbon/proc/randmutg()
if(!has_dna())
return
var/datum/mutation/human/HM = pick(GLOB.good_mutations)
. = HM.force_give(src)
/mob/living/carbon/proc/randmutvg()
if(!has_dna())
return
var/datum/mutation/human/HM = pick((GLOB.good_mutations) - GLOB.mutations_list[HULK] - GLOB.mutations_list[DWARFISM])
. = HM.force_give(src)
/mob/living/carbon/proc/randmuti()
if(!has_dna())
return
var/num = rand(1, DNA_UNI_IDENTITY_BLOCKS)
var/newdna = setblock(dna.uni_identity, num, random_string(DNA_BLOCK_SIZE, GLOB.hex_characters))
dna.uni_identity = newdna
updateappearance(mutations_overlay_update=1)
/mob/living/carbon/proc/clean_dna()
if(!has_dna())
return
dna.remove_all_mutations()
/mob/living/carbon/proc/clean_randmut(list/candidates, difficulty = 2)
clean_dna()
randmut(candidates, difficulty)
/proc/scramble_dna(mob/living/carbon/M, ui=FALSE, se=FALSE, probability)
if(!M.has_dna())
return 0
if(se)
for(var/i=1, i<=DNA_STRUC_ENZYMES_BLOCKS, i++)
if(prob(probability))
M.dna.struc_enzymes = setblock(M.dna.struc_enzymes, i, random_string(DNA_BLOCK_SIZE, GLOB.hex_characters))
M.domutcheck()
if(ui)
for(var/i=1, i<=DNA_UNI_IDENTITY_BLOCKS, i++)
if(prob(probability))
M.dna.uni_identity = setblock(M.dna.uni_identity, i, random_string(DNA_BLOCK_SIZE, GLOB.hex_characters))
M.updateappearance(mutations_overlay_update=1)
return 1
//value in range 1 to values. values must be greater than 0
//all arguments assumed to be positive integers
/proc/construct_block(value, values, blocksize=DNA_BLOCK_SIZE)
var/width = round((16**blocksize)/values)
if(value < 1)
value = 1
value = (value * width) - rand(1,width)
return num2hex(value, blocksize)
//value is hex
/proc/deconstruct_block(value, values, blocksize=DNA_BLOCK_SIZE)
var/width = round((16**blocksize)/values)
value = round(hex2num(value) / width) + 1
if(value > values)
value = values
return value
/////////////////////////// DNA HELPER-PROCS
/////////////////////////// DNA DATUM
/datum/dna
var/unique_enzymes
var/struc_enzymes
var/uni_identity
var/blood_type
var/datum/species/species = new /datum/species/human() //The type of mutant race the player is if applicable (i.e. potato-man)
var/list/features = list("FFF") //first value is mutant color
var/real_name //Stores the real name of the person who originally got this dna datum. Used primarely for changelings,
var/list/mutations = list() //All mutations are from now on here
var/list/temporary_mutations = list() //Timers for temporary mutations
var/list/previous = list() //For temporary name/ui/ue/blood_type modifications
var/mob/living/holder
/datum/dna/New(mob/living/new_holder)
if(new_holder)
holder = new_holder
/datum/dna/proc/transfer_identity(mob/living/carbon/destination, transfer_SE = 0)
if(!istype(destination))
return
destination.dna.unique_enzymes = unique_enzymes
destination.dna.uni_identity = uni_identity
destination.dna.blood_type = blood_type
destination.set_species(species.type, icon_update=0)
destination.dna.features = features.Copy()
destination.dna.real_name = real_name
destination.dna.temporary_mutations = temporary_mutations.Copy()
if(transfer_SE)
destination.dna.struc_enzymes = struc_enzymes
/datum/dna/proc/copy_dna(datum/dna/new_dna)
new_dna.unique_enzymes = unique_enzymes
new_dna.struc_enzymes = struc_enzymes
new_dna.uni_identity = uni_identity
new_dna.blood_type = blood_type
new_dna.features = features.Copy()
new_dna.species = new species.type
new_dna.real_name = real_name
new_dna.mutations = mutations.Copy()
/datum/dna/proc/add_mutation(mutation_name)
var/datum/mutation/human/HM = GLOB.mutations_list[mutation_name]
HM.on_acquiring(holder)
/datum/dna/proc/remove_mutation(mutation_name)
var/datum/mutation/human/HM = GLOB.mutations_list[mutation_name]
HM.on_losing(holder)
/datum/dna/proc/check_mutation(mutation_name)
var/datum/mutation/human/HM = GLOB.mutations_list[mutation_name]
return mutations.Find(HM)
/datum/dna/proc/remove_all_mutations()
remove_mutation_group(mutations)
/datum/dna/proc/remove_mutation_group(list/group)
if(!group)
return
for(var/datum/mutation/human/HM in group)
HM.force_lose(holder)
/datum/dna/proc/generate_uni_identity()
. = ""
var/list/L = new /list(DNA_UNI_IDENTITY_BLOCKS)
L[DNA_GENDER_BLOCK] = construct_block((holder.gender!=MALE)+1, 2)
if(ishuman(holder))
var/mob/living/carbon/human/H = holder
if(!GLOB.hair_styles_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/hair,GLOB.hair_styles_list, GLOB.hair_styles_male_list, GLOB.hair_styles_female_list)
L[DNA_HAIR_STYLE_BLOCK] = construct_block(GLOB.hair_styles_list.Find(H.hair_style), GLOB.hair_styles_list.len)
L[DNA_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.hair_color)
if(!GLOB.facial_hair_styles_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_hair, GLOB.facial_hair_styles_list, GLOB.facial_hair_styles_male_list, GLOB.facial_hair_styles_female_list)
L[DNA_FACIAL_HAIR_STYLE_BLOCK] = construct_block(GLOB.facial_hair_styles_list.Find(H.facial_hair_style), GLOB.facial_hair_styles_list.len)
L[DNA_FACIAL_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.facial_hair_color)
L[DNA_SKIN_TONE_BLOCK] = construct_block(GLOB.skin_tones.Find(H.skin_tone), GLOB.skin_tones.len)
L[DNA_EYE_COLOR_BLOCK] = sanitize_hexcolor(H.eye_color)
for(var/i=1, i<=DNA_UNI_IDENTITY_BLOCKS, i++)
if(L[i])
. += L[i]
else
. += random_string(DNA_BLOCK_SIZE,GLOB.hex_characters)
return .
/datum/dna/proc/generate_struc_enzymes()
var/list/sorting = new /list(DNA_STRUC_ENZYMES_BLOCKS)
var/result = ""
for(var/datum/mutation/human/A in GLOB.good_mutations + GLOB.bad_mutations + GLOB.not_good_mutations)
if(A.name == RACEMUT && ismonkey(holder))
sorting[A.dna_block] = num2hex(A.lowest_value + rand(0, 256 * 6), DNA_BLOCK_SIZE)
mutations |= A
else
sorting[A.dna_block] = random_string(DNA_BLOCK_SIZE, list("0","1","2","3","4","5","6"))
for(var/B in sorting)
result += B
return result
/datum/dna/proc/generate_unique_enzymes()
. = ""
if(istype(holder))
real_name = holder.real_name
. += md5(holder.real_name)
else
. += random_string(DNA_UNIQUE_ENZYMES_LEN, GLOB.hex_characters)
return .
/datum/dna/proc/update_ui_block(blocknumber)
if(!blocknumber || !ishuman(holder))
return
var/mob/living/carbon/human/H = holder
switch(blocknumber)
if(DNA_HAIR_COLOR_BLOCK)
setblock(uni_identity, blocknumber, sanitize_hexcolor(H.hair_color))
if(DNA_FACIAL_HAIR_COLOR_BLOCK)
setblock(uni_identity, blocknumber, sanitize_hexcolor(H.facial_hair_color))
if(DNA_SKIN_TONE_BLOCK)
setblock(uni_identity, blocknumber, construct_block(GLOB.skin_tones.Find(H.skin_tone), GLOB.skin_tones.len))
if(DNA_EYE_COLOR_BLOCK)
setblock(uni_identity, blocknumber, sanitize_hexcolor(H.eye_color))
if(DNA_GENDER_BLOCK)
setblock(uni_identity, blocknumber, construct_block((H.gender!=MALE)+1, 2))
if(DNA_FACIAL_HAIR_STYLE_BLOCK)
setblock(uni_identity, blocknumber, construct_block(GLOB.facial_hair_styles_list.Find(H.facial_hair_style), GLOB.facial_hair_styles_list.len))
if(DNA_HAIR_STYLE_BLOCK)
setblock(uni_identity, blocknumber, construct_block(GLOB.hair_styles_list.Find(H.hair_style), GLOB.hair_styles_list.len))
/datum/dna/proc/mutations_say_mods(message)
if(message)
for(var/datum/mutation/human/M in mutations)
message = M.say_mod(message)
return message
/datum/dna/proc/mutations_get_spans()
var/list/spans = list()
for(var/datum/mutation/human/M in mutations)
spans |= M.get_spans()
return spans
/datum/dna/proc/species_get_spans()
var/list/spans = list()
if(species)
spans |= species.get_spans()
return spans
/datum/dna/proc/is_same_as(datum/dna/D)
if(uni_identity == D.uni_identity && struc_enzymes == D.struc_enzymes && real_name == D.real_name)
if(species.type == D.species.type && features == D.features && blood_type == D.blood_type)
return 1
return 0
//used to update dna UI, UE, and dna.real_name.
/datum/dna/proc/update_dna_identity()
uni_identity = generate_uni_identity()
unique_enzymes = generate_unique_enzymes()
/datum/dna/proc/initialize_dna(newblood_type)
if(newblood_type)
blood_type = newblood_type
unique_enzymes = generate_unique_enzymes()
uni_identity = generate_uni_identity()
struc_enzymes = generate_struc_enzymes()
features = random_features()
/datum/dna/stored //subtype used by brain mob's stored_dna
/datum/dna/stored/add_mutation(mutation_name) //no mutation changes on stored dna.
return
/datum/dna/stored/remove_mutation(mutation_name)
return
/datum/dna/stored/check_mutation(mutation_name)
return
/datum/dna/stored/remove_all_mutations()
return
/datum/dna/stored/remove_mutation_group(list/group)
return
/////////////////////////// DNA MOB-PROCS //////////////////////
/mob/proc/set_species(datum/species/mrace, icon_update = 1)
return
/mob/living/brain/set_species(datum/species/mrace, icon_update = 1)
if(mrace)
if(ispath(mrace))
stored_dna.species = new mrace()
else
stored_dna.species = mrace //not calling any species update procs since we're a brain, not a monkey/human
/mob/living/carbon/set_species(datum/species/mrace, icon_update = 1)
if(mrace && has_dna())
dna.species.on_species_loss(src)
var/old_species = dna.species
if(ispath(mrace))
dna.species = new mrace()
else
dna.species = mrace
dna.species.on_species_gain(src, old_species)
/mob/living/carbon/human/set_species(datum/species/mrace, icon_update = 1)
..()
if(icon_update)
update_body()
update_hair()
update_body_parts()
update_mutations_overlay()// no lizard with human hulk overlay please.
/mob/proc/has_dna()
return
/mob/living/carbon/has_dna()
return dna
/mob/living/carbon/human/proc/hardset_dna(ui, se, newreal_name, newblood_type, datum/species/mrace, newfeatures)
if(newfeatures)
dna.features = newfeatures
if(mrace)
var/datum/species/newrace = new mrace.type
newrace.copy_properties_from(mrace)
set_species(newrace, icon_update=0)
if(newreal_name)
real_name = newreal_name
dna.generate_unique_enzymes()
if(newblood_type)
dna.blood_type = newblood_type
if(ui)
dna.uni_identity = ui
updateappearance(icon_update=0)
if(se)
dna.struc_enzymes = se
domutcheck()
if(mrace || newfeatures || ui)
update_body()
update_hair()
update_body_parts()
update_mutations_overlay()
/mob/living/carbon/proc/create_dna()
dna = new /datum/dna(src)
if(!dna.species)
var/rando_race = pick(CONFIG_GET(keyed_flag_list/roundstart_races))
dna.species = new rando_race()
//proc used to update the mob's appearance after its dna UI has been changed
/mob/living/carbon/proc/updateappearance(icon_update=1, mutcolor_update=0, mutations_overlay_update=0)
if(!has_dna())
return
gender = (deconstruct_block(getblock(dna.uni_identity, DNA_GENDER_BLOCK), 2)-1) ? FEMALE : MALE
/mob/living/carbon/human/updateappearance(icon_update=1, mutcolor_update=0, mutations_overlay_update=0)
..()
var/structure = dna.uni_identity
hair_color = sanitize_hexcolor(getblock(structure, DNA_HAIR_COLOR_BLOCK))
facial_hair_color = sanitize_hexcolor(getblock(structure, DNA_FACIAL_HAIR_COLOR_BLOCK))
skin_tone = GLOB.skin_tones[deconstruct_block(getblock(structure, DNA_SKIN_TONE_BLOCK), GLOB.skin_tones.len)]
eye_color = sanitize_hexcolor(getblock(structure, DNA_EYE_COLOR_BLOCK))
facial_hair_style = GLOB.facial_hair_styles_list[deconstruct_block(getblock(structure, DNA_FACIAL_HAIR_STYLE_BLOCK), GLOB.facial_hair_styles_list.len)]
hair_style = GLOB.hair_styles_list[deconstruct_block(getblock(structure, DNA_HAIR_STYLE_BLOCK), GLOB.hair_styles_list.len)]
if(icon_update)
update_body()
update_hair()
if(mutcolor_update)
update_body_parts()
if(mutations_overlay_update)
update_mutations_overlay()
/mob/proc/domutcheck()
return
/mob/living/carbon/domutcheck(force_powers=0) //Set force_powers to 1 to bypass the power chance
if(!has_dna())
return
for(var/datum/mutation/human/A in GLOB.good_mutations | GLOB.bad_mutations | GLOB.not_good_mutations)
if(ismob(A.check_block(src, force_powers)))
return //we got monkeyized/humanized, this mob will be deleted, no need to continue.
update_mutations_overlay()
/////////////////////////// DNA HELPER-PROCS //////////////////////////////
/proc/getleftblocks(input,blocknumber,blocksize)
if(blocknumber > 1)
return copytext(input,1,((blocksize*blocknumber)-(blocksize-1)))
/proc/getrightblocks(input,blocknumber,blocksize)
if(blocknumber < (length(input)/blocksize))
return copytext(input,blocksize*blocknumber+1,length(input)+1)
/proc/getblock(input, blocknumber, blocksize=DNA_BLOCK_SIZE)
return copytext(input, blocksize*(blocknumber-1)+1, (blocksize*blocknumber)+1)
/proc/setblock(istring, blocknumber, replacement, blocksize=DNA_BLOCK_SIZE)
if(!istring || !blocknumber || !replacement || !blocksize)
return 0
return getleftblocks(istring, blocknumber, blocksize) + replacement + getrightblocks(istring, blocknumber, blocksize)
/mob/living/carbon/proc/randmut(list/candidates, difficulty = 2)
if(!has_dna())
return
var/datum/mutation/human/num = pick(candidates)
. = num.force_give(src)
/mob/living/carbon/proc/randmutb()
if(!has_dna())
return
var/datum/mutation/human/HM = pick((GLOB.bad_mutations | GLOB.not_good_mutations) - GLOB.mutations_list[RACEMUT])
. = HM.force_give(src)
/mob/living/carbon/proc/randmutg()
if(!has_dna())
return
var/datum/mutation/human/HM = pick(GLOB.good_mutations)
. = HM.force_give(src)
/mob/living/carbon/proc/randmutvg()
if(!has_dna())
return
var/datum/mutation/human/HM = pick((GLOB.good_mutations) - GLOB.mutations_list[HULK] - GLOB.mutations_list[DWARFISM])
. = HM.force_give(src)
/mob/living/carbon/proc/randmuti()
if(!has_dna())
return
var/num = rand(1, DNA_UNI_IDENTITY_BLOCKS)
var/newdna = setblock(dna.uni_identity, num, random_string(DNA_BLOCK_SIZE, GLOB.hex_characters))
dna.uni_identity = newdna
updateappearance(mutations_overlay_update=1)
/mob/living/carbon/proc/clean_dna()
if(!has_dna())
return
dna.remove_all_mutations()
/mob/living/carbon/proc/clean_randmut(list/candidates, difficulty = 2)
clean_dna()
randmut(candidates, difficulty)
/proc/scramble_dna(mob/living/carbon/M, ui=FALSE, se=FALSE, probability)
if(!M.has_dna())
return 0
if(se)
for(var/i=1, i<=DNA_STRUC_ENZYMES_BLOCKS, i++)
if(prob(probability))
M.dna.struc_enzymes = setblock(M.dna.struc_enzymes, i, random_string(DNA_BLOCK_SIZE, GLOB.hex_characters))
M.domutcheck()
if(ui)
for(var/i=1, i<=DNA_UNI_IDENTITY_BLOCKS, i++)
if(prob(probability))
M.dna.uni_identity = setblock(M.dna.uni_identity, i, random_string(DNA_BLOCK_SIZE, GLOB.hex_characters))
M.updateappearance(mutations_overlay_update=1)
return 1
//value in range 1 to values. values must be greater than 0
//all arguments assumed to be positive integers
/proc/construct_block(value, values, blocksize=DNA_BLOCK_SIZE)
var/width = round((16**blocksize)/values)
if(value < 1)
value = 1
value = (value * width) - rand(1,width)
return num2hex(value, blocksize)
//value is hex
/proc/deconstruct_block(value, values, blocksize=DNA_BLOCK_SIZE)
var/width = round((16**blocksize)/values)
value = round(hex2num(value) / width) + 1
if(value > values)
value = values
return value
/////////////////////////// DNA HELPER-PROCS
+1 -1
View File
@@ -140,7 +140,7 @@ GLOBAL_LIST_EMPTY(explosions)
var/list/exploded_this_tick = list() //open turfs that need to be blocked off while we sleep
var/list/affected_turfs = GatherSpiralTurfs(max_range, epicenter)
var/reactionary = config.reactionary_explosions
var/reactionary = CONFIG_GET(flag/reactionary_explosions)
var/list/cached_exp_block
if(reactionary)
+89 -89
View File
@@ -1,90 +1,90 @@
//Just new and forget
/datum/forced_movement
var/atom/movable/victim
var/atom/target
var/last_processed
var/steps_per_tick
var/allow_climbing
var/datum/callback/on_step
var/moved_at_all = FALSE
//as fast as ssfastprocess
/datum/forced_movement/New(atom/movable/_victim, atom/_target, _steps_per_tick = 0.5, _allow_climbing = FALSE, datum/callback/_on_step = null)
victim = _victim
target = _target
steps_per_tick = _steps_per_tick
allow_climbing = _allow_climbing
on_step = _on_step
. = ..()
if(_victim && _target && _steps_per_tick && !_victim.force_moving)
last_processed = world.time
_victim.force_moving = src
START_PROCESSING(SSfastprocess, src)
else
qdel(src) //if you want to overwrite the current forced movement, call qdel(victim.force_moving) before creating this
/datum/forced_movement/Destroy()
if(victim.force_moving == src)
victim.force_moving = null
if(moved_at_all)
victim.forceMove(victim.loc) //get the side effects of moving here that require us to currently not be force_moving aka reslipping on ice
STOP_PROCESSING(SSfastprocess, src)
victim = null
target = null
return ..()
/datum/forced_movement/process()
if(QDELETED(victim) || !victim.loc || QDELETED(target) || !target.loc)
qdel(src)
return
var/steps_to_take = round(steps_per_tick * (world.time - last_processed))
if(steps_to_take)
for(var/i in 1 to steps_to_take)
if(TryMove())
moved_at_all = TRUE
if(on_step)
on_step.InvokeAsync()
else
qdel(src)
return
last_processed = world.time
/datum/forced_movement/proc/TryMove(recursive = FALSE)
var/atom/movable/vic = victim //sanic
var/atom/tar = target
if(!recursive)
. = step_towards(vic, tar)
//shit way for getting around corners
if(!.)
if(tar.x > vic.x)
if(step(vic, EAST))
. = TRUE
else if(tar.x < vic.x)
if(step(vic, WEST))
. = TRUE
if(!.)
if(tar.y > vic.y)
if(step(vic, NORTH))
. = TRUE
else if(tar.y < vic.y)
if(step(vic, SOUTH))
. = TRUE
if(!.)
if(recursive)
return FALSE
else
. = TryMove(TRUE)
. = . && (vic.loc != tar.loc)
//Just new and forget
/datum/forced_movement
var/atom/movable/victim
var/atom/target
var/last_processed
var/steps_per_tick
var/allow_climbing
var/datum/callback/on_step
var/moved_at_all = FALSE
//as fast as ssfastprocess
/datum/forced_movement/New(atom/movable/_victim, atom/_target, _steps_per_tick = 0.5, _allow_climbing = FALSE, datum/callback/_on_step = null)
victim = _victim
target = _target
steps_per_tick = _steps_per_tick
allow_climbing = _allow_climbing
on_step = _on_step
. = ..()
if(_victim && _target && _steps_per_tick && !_victim.force_moving)
last_processed = world.time
_victim.force_moving = src
START_PROCESSING(SSfastprocess, src)
else
qdel(src) //if you want to overwrite the current forced movement, call qdel(victim.force_moving) before creating this
/datum/forced_movement/Destroy()
if(victim.force_moving == src)
victim.force_moving = null
if(moved_at_all)
victim.forceMove(victim.loc) //get the side effects of moving here that require us to currently not be force_moving aka reslipping on ice
STOP_PROCESSING(SSfastprocess, src)
victim = null
target = null
return ..()
/datum/forced_movement/process()
if(QDELETED(victim) || !victim.loc || QDELETED(target) || !target.loc)
qdel(src)
return
var/steps_to_take = round(steps_per_tick * (world.time - last_processed))
if(steps_to_take)
for(var/i in 1 to steps_to_take)
if(TryMove())
moved_at_all = TRUE
if(on_step)
on_step.InvokeAsync()
else
qdel(src)
return
last_processed = world.time
/datum/forced_movement/proc/TryMove(recursive = FALSE)
var/atom/movable/vic = victim //sanic
var/atom/tar = target
if(!recursive)
. = step_towards(vic, tar)
//shit way for getting around corners
if(!.)
if(tar.x > vic.x)
if(step(vic, EAST))
. = TRUE
else if(tar.x < vic.x)
if(step(vic, WEST))
. = TRUE
if(!.)
if(tar.y > vic.y)
if(step(vic, NORTH))
. = TRUE
else if(tar.y < vic.y)
if(step(vic, SOUTH))
. = TRUE
if(!.)
if(recursive)
return FALSE
else
. = TryMove(TRUE)
. = . && (vic.loc != tar.loc)
/mob/Collide(atom/A)
. = ..()
if(force_moving && force_moving.allow_climbing && istype(A, /obj/structure))
var/obj/structure/S = A
if(S.climbable)
S.do_climb(src)
. = ..()
if(force_moving && force_moving.allow_climbing && isstructure(A))
var/obj/structure/S = A
if(S.climbable)
S.do_climb(src)
+111 -103
View File
@@ -1,103 +1,111 @@
#define FORWARD -1
#define BACKWARD 1
/datum/construction
var/list/steps
var/atom/holder
var/result
var/list/steps_desc
/datum/construction/New(atom)
..()
holder = atom
if(!holder) //don't want this without a holder
qdel(src)
set_desc(steps.len)
return
/datum/construction/proc/next_step()
steps.len--
if(!steps.len)
spawn_result()
else
set_desc(steps.len)
return
/datum/construction/proc/action(atom/used_atom,mob/user)
return
/datum/construction/proc/check_step(atom/used_atom,mob/user) //check last step only
var/valid_step = is_right_key(used_atom)
if(valid_step)
if(custom_action(valid_step, used_atom, user))
next_step()
return 1
return 0
/datum/construction/proc/is_right_key(atom/used_atom) // returns current step num if used_atom is of the right type.
var/list/L = steps[steps.len]
if(istype(used_atom, L["key"]))
return steps.len
return 0
/datum/construction/proc/custom_action(step, used_atom, user)
return 1
/datum/construction/proc/check_all_steps(atom/used_atom,mob/user) //check all steps, remove matching one.
for(var/i=1;i<=steps.len;i++)
var/list/L = steps[i];
if(istype(used_atom, L["key"]))
if(custom_action(i, used_atom, user))
steps[i]=null;//stupid byond list from list removal...
listclearnulls(steps);
if(!steps.len)
spawn_result()
return 1
return 0
/datum/construction/proc/spawn_result()
if(result)
new result(get_turf(holder))
qdel(holder)
return
/datum/construction/proc/set_desc(index as num)
var/list/step = steps[index]
holder.desc = step["desc"]
return
/datum/construction/reversible
var/index
/datum/construction/reversible/New(atom)
..()
index = steps.len
return
/datum/construction/reversible/proc/update_index(diff as num)
index+=diff
if(index==0)
spawn_result()
else
set_desc(index)
return
/datum/construction/reversible/is_right_key(atom/used_atom) // returns index step
var/list/L = steps[index]
if(istype(used_atom, L["key"]))
return FORWARD //to the first step -> forward
else if(L["backkey"] && istype(used_atom, L["backkey"]))
return BACKWARD //to the last step -> backwards
return 0
/datum/construction/reversible/check_step(atom/used_atom,mob/user)
var/diff = is_right_key(used_atom)
if(diff)
if(custom_action(index, diff, used_atom, user))
update_index(diff)
return 1
return 0
/datum/construction/reversible/custom_action(index, diff, used_atom, user)
return 1
#define FORWARD -1
#define BACKWARD 1
/datum/construction
var/list/steps
var/atom/holder
var/result
var/list/steps_desc
/datum/construction/New(atom)
..()
holder = atom
if(!holder) //don't want this without a holder
qdel(src)
set_desc(steps.len)
return
/datum/construction/proc/next_step()
steps.len--
if(!steps.len)
spawn_result()
else
set_desc(steps.len)
return
/datum/construction/proc/action(atom/used_atom,mob/user)
return
/datum/construction/proc/check_step(atom/used_atom,mob/user) //check last step only
var/valid_step = is_right_key(used_atom)
if(valid_step)
if(custom_action(valid_step, used_atom, user))
next_step()
return 1
return 0
/datum/construction/proc/is_right_key(atom/used_atom) // returns current step num if used_atom is of the right type.
var/list/L = steps[steps.len]
if(istype(used_atom, L["key"]))
return steps.len
return 0
/datum/construction/proc/custom_action(step, used_atom, user)
return 1
/datum/construction/proc/check_all_steps(atom/used_atom,mob/user) //check all steps, remove matching one.
for(var/i=1;i<=steps.len;i++)
var/list/L = steps[i];
if(istype(used_atom, L["key"]))
if(custom_action(i, used_atom, user))
steps[i]=null;//stupid byond list from list removal...
listclearnulls(steps);
if(!steps.len)
spawn_result()
return 1
return 0
/datum/construction/proc/spawn_result()
if(result)
new result(get_turf(holder))
qdel(holder)
return
/datum/construction/proc/spawn_mecha_result()
if(result)
var/obj/mecha/m = new result(get_turf(holder))
var/obj/item/oldcell = locate (/obj/item/stock_parts/cell) in m
QDEL_NULL(oldcell)
m.CheckParts(holder.contents)
QDEL_NULL(holder)
/datum/construction/proc/set_desc(index as num)
var/list/step = steps[index]
holder.desc = step["desc"]
return
/datum/construction/reversible
var/index
/datum/construction/reversible/New(atom)
..()
index = steps.len
return
/datum/construction/reversible/proc/update_index(diff as num)
index+=diff
if(index==0)
spawn_result()
else
set_desc(index)
return
/datum/construction/reversible/is_right_key(atom/used_atom) // returns index step
var/list/L = steps[index]
if(istype(used_atom, L["key"]))
return FORWARD //to the first step -> forward
else if(L["backkey"] && istype(used_atom, L["backkey"]))
return BACKWARD //to the last step -> backwards
return 0
/datum/construction/reversible/check_step(atom/used_atom,mob/user)
var/diff = is_right_key(used_atom)
if(diff)
if(custom_action(index, diff, used_atom, user))
update_index(diff)
return 1
return 0
/datum/construction/reversible/custom_action(index, diff, used_atom, user)
return 1
+28 -74
View File
@@ -2,25 +2,10 @@
var/originmastercommit
var/commit
var/list/testmerge = list()
var/has_pr_details = FALSE //tgs2 support
var/date
/datum/getrev/New()
if(world.RunningService())
var/file_name
if(ServiceVersion()) //will return null for versions < 3.0.91.0
file_name = SERVICE_PR_TEST_JSON_OLD
else
file_name = SERVICE_PR_TEST_JSON
if(fexists(file_name))
testmerge = json_decode(file2text(file_name))
#ifdef SERVERTOOLS
else if(!world.RunningService() && fexists("../prtestjob.lk")) //tgs2 support
var/list/tmp = world.file2list("..\\prtestjob.lk")
for(var/I in tmp)
if(I)
testmerge |= I
#endif
testmerge = SERVER_TOOLS_PR_LIST
log_world("Running /tg/ revision:")
var/list/logs = world.file2list(".git/logs/HEAD")
if(logs)
@@ -36,58 +21,24 @@
log_world(commit)
for(var/line in testmerge)
if(line)
if(world.RunningService())
var/tmcommit = testmerge[line]["commit"]
log_world("Test merge active of PR #[line] commit [tmcommit]")
SSblackbox.add_details("testmerged_prs","[line]|[tmcommit]")
else //tgs2 support
log_world("Test merge active of PR #[line]")
SSblackbox.add_details("testmerged_prs","[line]")
var/tmcommit = testmerge[line]["commit"]
log_world("Test merge active of PR #[line] commit [tmcommit]")
SSblackbox.add_details("testmerged_prs","[line]|[tmcommit]")
log_world("Based off origin/master commit [originmastercommit]")
else
log_world(originmastercommit)
/datum/getrev/proc/DownloadPRDetails()
if(!config.githubrepoid)
if(testmerge.len)
log_world("PR details download failed: No github repo config set")
return
if(!isnum(text2num(config.githubrepoid)))
log_world("PR details download failed: Invalid github repo id: [config.githubrepoid]")
return
for(var/line in testmerge)
if(!isnum(text2num(line)))
log_world("PR details download failed: Invalid PR number: [line]")
return
var/url = "https://api.github.com/repositories/[config.githubrepoid]/pulls/[line].json"
GLOB.valid_HTTPSGet = TRUE
var/json = HTTPSGet(url)
if(!json)
return
testmerge[line] = json_decode(json)
if(!testmerge[line])
log_world("PR details download failed: null details returned")
return
CHECK_TICK
log_world("PR details successfully downloaded")
has_pr_details = TRUE
/datum/getrev/proc/GetTestMergeInfo(header = TRUE)
if(!testmerge.len)
return ""
. = header ? "The following pull requests are currently test merged:<br>" : ""
for(var/line in testmerge)
var/details
if(world.RunningService())
var/cm = testmerge[line]["commit"]
details = ": '" + html_encode(testmerge[line]["title"]) + "' by " + html_encode(testmerge[line]["author"]) + " at commit " + html_encode(copytext(cm, 1, min(length(cm), 7)))
else if(has_pr_details) //tgs2 support
details = ": '" + html_encode(testmerge[line]["title"]) + "' by " + html_encode(testmerge[line]["user"]["login"])
var/cm = testmerge[line]["commit"]
var/details = ": '" + html_encode(testmerge[line]["title"]) + "' by " + html_encode(testmerge[line]["author"]) + " at commit " + html_encode(copytext(cm, 1, min(length(cm), 7)))
if(details && findtext(details, "\[s\]") && (!usr || !usr.client.holder))
continue
. += "<a href=\"[config.githuburl]/pull/[line]\">#[line][details]</a><br>"
. += "<a href=\"[CONFIG_GET(string/githuburl)]/pull/[line]\">#[line][details]</a><br>"
/client/verb/showrevinfo()
set category = "OOC"
@@ -101,44 +52,47 @@
to_chat(src, GLOB.revdata.GetTestMergeInfo())
prefix = "Based off origin/master commit: "
var/pc = GLOB.revdata.originmastercommit
to_chat(src, "[prefix]<a href=\"[config.githuburl]/commit/[pc]\">[copytext(pc, 1, min(length(pc), 7))]</a>")
to_chat(src, "[prefix]<a href=\"[CONFIG_GET(string/githuburl)]/commit/[pc]\">[copytext(pc, 1, min(length(pc), 7))]</a>")
else
to_chat(src, "Revision unknown")
to_chat(src, "<b>Current Informational Settings:</b>")
to_chat(src, "Protect Authority Roles From Traitor: [config.protect_roles_from_antagonist]")
to_chat(src, "Protect Assistant Role From Traitor: [config.protect_assistant_from_antagonist]")
to_chat(src, "Enforce Human Authority: [config.enforce_human_authority]")
to_chat(src, "Allow Latejoin Antagonists: [config.allow_latejoin_antagonists]")
to_chat(src, "Enforce Continuous Rounds: [config.continuous.len] of [config.modes.len] roundtypes")
to_chat(src, "Allow Midround Antagonists: [config.midround_antag.len] of [config.modes.len] roundtypes")
if(config.show_game_type_odds)
to_chat(src, "Protect Authority Roles From Traitor: [CONFIG_GET(flag/protect_roles_from_antagonist)]")
to_chat(src, "Protect Assistant Role From Traitor: [CONFIG_GET(flag/protect_assistant_from_antagonist)]")
to_chat(src, "Enforce Human Authority: [CONFIG_GET(flag/enforce_human_authority)]")
to_chat(src, "Allow Latejoin Antagonists: [CONFIG_GET(flag/allow_latejoin_antagonists)]")
to_chat(src, "Enforce Continuous Rounds: [length(CONFIG_GET(keyed_flag_list/continuous))] of [config.modes.len] roundtypes")
to_chat(src, "Allow Midround Antagonists: [length(CONFIG_GET(keyed_flag_list/midround_antag))] of [config.modes.len] roundtypes")
if(CONFIG_GET(flag/show_game_type_odds))
var/list/probabilities = CONFIG_GET(keyed_number_list/probability)
if(SSticker.IsRoundInProgress())
var/prob_sum = 0
var/current_odds_differ = FALSE
var/list/probs = list()
var/list/modes = config.gamemode_cache
var/list/min_pop = CONFIG_GET(keyed_number_list/min_pop)
var/list/max_pop = CONFIG_GET(keyed_number_list/max_pop)
for(var/mode in modes)
var/datum/game_mode/M = mode
var/ctag = initial(M.config_tag)
if(!(ctag in config.probabilities))
if(!(ctag in probabilities))
continue
if((config.min_pop[ctag] && (config.min_pop[ctag] > SSticker.totalPlayersReady)) || (config.max_pop[ctag] && (config.max_pop[ctag] < SSticker.totalPlayersReady)) || (initial(M.required_players) > SSticker.totalPlayersReady))
if((min_pop[ctag] && (min_pop[ctag] > SSticker.totalPlayersReady)) || (max_pop[ctag] && (max_pop[ctag] < SSticker.totalPlayersReady)) || (initial(M.required_players) > SSticker.totalPlayersReady))
current_odds_differ = TRUE
continue
probs[ctag] = 1
prob_sum += config.probabilities[ctag]
prob_sum += probabilities[ctag]
if(current_odds_differ)
to_chat(src, "<b>Game Mode Odds for current round:</b>")
for(var/ctag in probs)
if(config.probabilities[ctag] > 0)
var/percentage = round(config.probabilities[ctag] / prob_sum * 100, 0.1)
if(probabilities[ctag] > 0)
var/percentage = round(probabilities[ctag] / prob_sum * 100, 0.1)
to_chat(src, "[ctag] [percentage]%")
to_chat(src, "<b>All Game Mode Odds:</b>")
var/sum = 0
for(var/ctag in config.probabilities)
sum += config.probabilities[ctag]
for(var/ctag in config.probabilities)
if(config.probabilities[ctag] > 0)
var/percentage = round(config.probabilities[ctag] / sum * 100, 0.1)
for(var/ctag in probabilities)
sum += probabilities[ctag]
for(var/ctag in probabilities)
if(probabilities[ctag] > 0)
var/percentage = round(probabilities[ctag] / sum * 100, 0.1)
to_chat(src, "[ctag] [percentage]%")
+6
View File
@@ -11,11 +11,14 @@
var/minetype = "lavaland"
//Order matters here.
var/list/transition_config = list(CENTCOM = SELFLOOPING,
CITY_OF_COGS = SELFLOOPING,
MAIN_STATION = CROSSLINKED,
EMPTY_AREA_1 = CROSSLINKED,
EMPTY_AREA_2 = CROSSLINKED,
MINING = SELFLOOPING,
CITY_OF_COGS = SELFLOOPING,
EMPTY_AREA_3 = CROSSLINKED,
EMPTY_AREA_4 = CROSSLINKED,
EMPTY_AREA_5 = CROSSLINKED,
@@ -28,6 +31,7 @@
var/config_min_users = 0
var/voteweight = 1
var/allow_custom_shuttles = "yes"
/datum/map_config/New(filename = "data/next_map.json", default_to_box, delete_after)
if(default_to_box)
return
@@ -119,6 +123,8 @@
return MAIN_STATION
if("CENTCOM")
return CENTCOM
if("CITY_OF_COGS")
return CITY_OF_COGS
if("MINING")
return MINING
if("EMPTY_AREA_1")
+8 -4
View File
@@ -211,7 +211,7 @@
/datum/mind/proc/remove_wizard()
if(src in SSticker.mode.wizards)
SSticker.mode.wizards -= src
current.spellremove(current)
RemoveAllSpells()
special_role = null
remove_antag_equip()
@@ -672,7 +672,7 @@
text = "<i><b>[text]</b></i>: "
if(is_servant_of_ratvar(current))
text += "not mindshielded | <a href='?src=\ref[src];clockcult=clear'>employee</a> | <b>SERVANT</b>"
text += "<br><a href='?src=\ref[src];clockcult=slab'>Give slab</a>"
text += "<br><a href='?src=\ref[src];clockcult=slab'>Equip</a>"
else if(is_eligible_servant(current))
text += "not mindshielded | <b>EMPLOYEE</b> | <a href='?src=\ref[src];clockcult=servant'>servant</a>"
else
@@ -1035,9 +1035,9 @@
log_admin("[key_name(usr)] has made [current] into a servant of Ratvar.")
if("slab")
if(!SSticker.mode.equip_servant(current))
to_chat(usr, "<span class='warning'>Failed to outfit [current] with a slab!</span>")
to_chat(usr, "<span class='warning'>Failed to outfit [current]!</span>")
else
to_chat(usr, "<span class='notice'>Successfully gave [current] a clockwork slab!</span>")
to_chat(usr, "<span class='notice'>Successfully gave [current] servant equipment!</span>")
else if (href_list["wizard"])
switch(href_list["wizard"])
@@ -1505,6 +1505,10 @@
spell_list -= S
qdel(S)
/datum/mind/proc/RemoveAllSpells()
for(var/obj/effect/proc_holder/S in spell_list)
RemoveSpell(S)
/datum/mind/proc/transfer_martial_arts(mob/living/new_character)
if(!ishuman(new_character))
return
+2 -2
View File
@@ -102,10 +102,10 @@
if(implants)
for(var/implant_type in implants)
var/obj/item/implant/I = new implant_type(H)
I.implant(H, null, silent=TRUE)
I.implant(H, null, TRUE)
H.update_body()
return 1
return TRUE
/datum/outfit/proc/apply_fingerprints(mob/living/carbon/human/H)
if(!istype(H))
+38 -16
View File
@@ -148,21 +148,6 @@
if(owner.m_intent == MOVE_INTENT_WALK)
owner.toggle_move_intent()
/datum/status_effect/geis_tracker
id = "geis_tracker"
duration = -1
alert_type = null
var/obj/structure/destructible/clockwork/geis_binding/binding
/datum/status_effect/geis_tracker/on_creation(mob/living/new_owner, obj/structure/destructible/clockwork/geis_binding/new_binding)
. = ..()
if(.)
binding = new_binding
/datum/status_effect/geis_tracker/tick()
if(QDELETED(binding))
qdel(src)
/datum/status_effect/maniamotor
id = "maniamotor"
duration = -1
@@ -200,7 +185,7 @@
return
if(!motor.active) //it being off makes it fall off much faster
if(!is_servant && !warned_turnoff)
if(motor.total_accessable_power() > motor.mania_cost)
if(can_access_clockwork_power(motor, motor.mania_cost))
to_chat(owner, "<span class='sevtug[span_part]'>\"[text2ratvar(pick(turnoff_messages))]\"</span>")
else
var/pickedmessage = pick(powerloss_messages)
@@ -461,3 +446,40 @@
/obj/effect/temp_visual/curse/Initialize()
. = ..()
deltimer(timerid)
//Kindle: Used by servants of Ratvar. 10-second knockdown, reduced by 1 second per 5 damage taken while the effect is active.
/datum/status_effect/kindle
id = "kindle"
status_type = STATUS_EFFECT_UNIQUE
tick_interval = 5
duration = 100
alert_type = /obj/screen/alert/status_effect/kindle
var/old_health
/datum/status_effect/kindle/tick()
owner.Knockdown(15)
if(iscarbon(owner))
var/mob/living/carbon/C = owner
C.silent = max(2, C.silent)
C.stuttering = max(5, C.stuttering)
if(!old_health)
old_health = owner.health
var/health_difference = old_health - owner.health
if(!health_difference)
return
owner.visible_message("<span class='warning'>The light in [owner]'s eyes dims as they're harmed!</span>", \
"<span class='boldannounce'>The dazzling lights dim as you're harmed!</span>")
health_difference *= 2 //so 10 health difference translates to 20 deciseconds of stun reduction
duration -= health_difference
old_health = owner.health
/datum/status_effect/kindle/on_remove()
owner.visible_message("<span class='warning'>The light in [owner]'s eyes fades!</span>", \
"<span class='boldannounce'>You snap out of your daze!</span>")
/obj/screen/alert/status_effect/kindle
name = "Dazzling Lights"
desc = "Blinding light dances in your vision, stunning and silencing you. <i>Any damage taken will shorten the light's effects!</i>"
icon_state = "kindle"
alerttooltipstyle = "clockcult"
+253 -253
View File
@@ -1,260 +1,260 @@
#define MAXIMUM_EMP_WIRES 3
/proc/is_wire_tool(obj/item/I)
if(istype(I, /obj/item/device/multitool))
return TRUE
if(istype(I, /obj/item/wirecutters))
return TRUE
if(istype(I, /obj/item/device/assembly))
var/obj/item/device/assembly/A = I
if(A.attachable)
return TRUE
return
/atom
var/datum/wires/wires = null
/datum/wires
var/atom/holder = null // The holder (atom that contains these wires).
var/holder_type = null // The holder's typepath (used to make wire colors common to all holders).
var/proper_name = "Unknown" // The display name for the wire set shown in station blueprints. Not used if randomize is true or it's an item NT wouldn't know about (Explosives/Nuke)
var/list/wires = list() // List of wires.
var/list/cut_wires = list() // List of wires that have been cut.
var/list/colors = list() // Dictionary of colors to wire.
var/list/assemblies = list() // List of attached assemblies.
var/randomize = 0 // If every instance of these wires should be random.
// Prevents wires from showing up in station blueprints
/datum/wires/New(atom/holder)
..()
if(!istype(holder, holder_type))
CRASH("Wire holder is not of the expected type!")
return
src.holder = holder
if(randomize)
randomize()
else
if(!GLOB.wire_color_directory[holder_type])
randomize()
GLOB.wire_color_directory[holder_type] = colors
GLOB.wire_name_directory[holder_type] = proper_name
else
colors = GLOB.wire_color_directory[holder_type]
/datum/wires/Destroy()
holder = null
assemblies = list()
return ..()
/datum/wires/proc/add_duds(duds)
while(duds)
var/dud = WIRE_DUD_PREFIX + "[--duds]"
if(dud in wires)
continue
wires += dud
/datum/wires/proc/randomize()
var/static/list/possible_colors = list(
"blue",
"brown",
"crimson",
"cyan",
"gold",
"grey",
"green",
"magenta",
"orange",
"pink",
"purple",
"red",
"silver",
"violet",
"white",
"yellow"
)
var/list/my_possible_colors = possible_colors.Copy()
for(var/wire in shuffle(wires))
colors[pick_n_take(my_possible_colors)] = wire
/datum/wires/proc/shuffle_wires()
colors.Cut()
randomize()
/datum/wires/proc/repair()
cut_wires.Cut()
/datum/wires/proc/get_wire(color)
return colors[color]
/datum/wires/proc/get_attached(color)
if(assemblies[color])
return assemblies[color]
return null
/datum/wires/proc/is_attached(color)
if(assemblies[color])
return TRUE
/datum/wires/proc/is_cut(wire)
return (wire in cut_wires)
/datum/wires/proc/is_color_cut(color)
return is_cut(get_wire(color))
/datum/wires/proc/is_all_cut()
if(cut_wires.len == wires.len)
return TRUE
/datum/wires/proc/cut(wire)
if(is_cut(wire))
cut_wires -= wire
on_cut(wire, mend = TRUE)
else
cut_wires += wire
on_cut(wire, mend = FALSE)
/datum/wires/proc/cut_color(color)
cut(get_wire(color))
/datum/wires/proc/cut_random()
cut(wires[rand(1, wires.len)])
/datum/wires/proc/cut_all()
for(var/wire in wires)
cut(wire)
#define MAXIMUM_EMP_WIRES 3
/proc/is_wire_tool(obj/item/I)
if(istype(I, /obj/item/device/multitool))
return TRUE
if(istype(I, /obj/item/wirecutters))
return TRUE
if(istype(I, /obj/item/device/assembly))
var/obj/item/device/assembly/A = I
if(A.attachable)
return TRUE
return
/atom
var/datum/wires/wires = null
/datum/wires
var/atom/holder = null // The holder (atom that contains these wires).
var/holder_type = null // The holder's typepath (used to make wire colors common to all holders).
var/proper_name = "Unknown" // The display name for the wire set shown in station blueprints. Not used if randomize is true or it's an item NT wouldn't know about (Explosives/Nuke)
var/list/wires = list() // List of wires.
var/list/cut_wires = list() // List of wires that have been cut.
var/list/colors = list() // Dictionary of colors to wire.
var/list/assemblies = list() // List of attached assemblies.
var/randomize = 0 // If every instance of these wires should be random.
// Prevents wires from showing up in station blueprints
/datum/wires/New(atom/holder)
..()
if(!istype(holder, holder_type))
CRASH("Wire holder is not of the expected type!")
return
src.holder = holder
if(randomize)
randomize()
else
if(!GLOB.wire_color_directory[holder_type])
randomize()
GLOB.wire_color_directory[holder_type] = colors
GLOB.wire_name_directory[holder_type] = proper_name
else
colors = GLOB.wire_color_directory[holder_type]
/datum/wires/Destroy()
holder = null
assemblies = list()
return ..()
/datum/wires/proc/add_duds(duds)
while(duds)
var/dud = WIRE_DUD_PREFIX + "[--duds]"
if(dud in wires)
continue
wires += dud
/datum/wires/proc/randomize()
var/static/list/possible_colors = list(
"blue",
"brown",
"crimson",
"cyan",
"gold",
"grey",
"green",
"magenta",
"orange",
"pink",
"purple",
"red",
"silver",
"violet",
"white",
"yellow"
)
var/list/my_possible_colors = possible_colors.Copy()
for(var/wire in shuffle(wires))
colors[pick_n_take(my_possible_colors)] = wire
/datum/wires/proc/shuffle_wires()
colors.Cut()
randomize()
/datum/wires/proc/repair()
cut_wires.Cut()
/datum/wires/proc/get_wire(color)
return colors[color]
/datum/wires/proc/get_attached(color)
if(assemblies[color])
return assemblies[color]
return null
/datum/wires/proc/is_attached(color)
if(assemblies[color])
return TRUE
/datum/wires/proc/is_cut(wire)
return (wire in cut_wires)
/datum/wires/proc/is_color_cut(color)
return is_cut(get_wire(color))
/datum/wires/proc/is_all_cut()
if(cut_wires.len == wires.len)
return TRUE
/datum/wires/proc/cut(wire)
if(is_cut(wire))
cut_wires -= wire
on_cut(wire, mend = TRUE)
else
cut_wires += wire
on_cut(wire, mend = FALSE)
/datum/wires/proc/cut_color(color)
cut(get_wire(color))
/datum/wires/proc/cut_random()
cut(wires[rand(1, wires.len)])
/datum/wires/proc/cut_all()
for(var/wire in wires)
cut(wire)
/datum/wires/proc/pulse(wire, user)
if(is_cut(wire))
return
if(is_cut(wire))
return
on_pulse(wire, user)
/datum/wires/proc/pulse_color(color, mob/living/user)
pulse(get_wire(color), user)
/datum/wires/proc/pulse_assembly(obj/item/device/assembly/S)
for(var/color in assemblies)
if(S == assemblies[color])
pulse_color(color)
return TRUE
/datum/wires/proc/attach_assembly(color, obj/item/device/assembly/S)
if(S && istype(S) && S.attachable && !is_attached(color))
assemblies[color] = S
S.loc = holder
S.connected = src
return S
/datum/wires/proc/detach_assembly(color)
var/obj/item/device/assembly/S = get_attached(color)
if(S && istype(S))
assemblies -= color
S.connected = null
S.loc = holder.loc
return S
/datum/wires/proc/emp_pulse()
var/list/possible_wires = shuffle(wires)
var/remaining_pulses = MAXIMUM_EMP_WIRES
for(var/wire in possible_wires)
if(prob(33))
pulse(wire)
remaining_pulses--
if(remaining_pulses >= 0)
break
// Overridable Procs
/datum/wires/proc/interactable(mob/user)
return TRUE
/datum/wires/proc/get_status()
return list()
/datum/wires/proc/on_cut(wire, mend = FALSE)
return
/datum/wires/proc/pulse_assembly(obj/item/device/assembly/S)
for(var/color in assemblies)
if(S == assemblies[color])
pulse_color(color)
return TRUE
/datum/wires/proc/attach_assembly(color, obj/item/device/assembly/S)
if(S && istype(S) && S.attachable && !is_attached(color))
assemblies[color] = S
S.forceMove(holder)
S.connected = src
return S
/datum/wires/proc/detach_assembly(color)
var/obj/item/device/assembly/S = get_attached(color)
if(S && istype(S))
assemblies -= color
S.connected = null
S.forceMove(holder.drop_location())
return S
/datum/wires/proc/emp_pulse()
var/list/possible_wires = shuffle(wires)
var/remaining_pulses = MAXIMUM_EMP_WIRES
for(var/wire in possible_wires)
if(prob(33))
pulse(wire)
remaining_pulses--
if(remaining_pulses >= 0)
break
// Overridable Procs
/datum/wires/proc/interactable(mob/user)
return TRUE
/datum/wires/proc/get_status()
return list()
/datum/wires/proc/on_cut(wire, mend = FALSE)
return
/datum/wires/proc/on_pulse(wire, user)
return
// End Overridable Procs
/datum/wires/proc/interact(mob/user)
if(!interactable(user))
return
ui_interact(user)
for(var/A in assemblies)
var/obj/item/I = assemblies[A]
if(istype(I) && I.on_found(user))
return
/datum/wires/ui_host()
return holder
/datum/wires/ui_status(mob/user)
if(interactable(user))
return ..()
return UI_CLOSE
return
// End Overridable Procs
/datum/wires/proc/interact(mob/user)
if(!interactable(user))
return
ui_interact(user)
for(var/A in assemblies)
var/obj/item/I = assemblies[A]
if(istype(I) && I.on_found(user))
return
/datum/wires/ui_host()
return holder
/datum/wires/ui_status(mob/user)
if(interactable(user))
return ..()
return UI_CLOSE
/datum/wires/ui_interact(mob/user, ui_key = "wires", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if (!ui)
ui = new(user, src, ui_key, "wires", "[holder.name] wires", 350, 150 + wires.len * 30, master_ui, state)
ui.open()
/datum/wires/ui_data(mob/user)
var/list/data = list()
var/list/payload = list()
for(var/color in colors)
payload.Add(list(list(
"color" = color,
"wire" = (IsAdminGhost(user) || (user.is_holding_item_of_type(/obj/item/device/multitool/abductor)) ? get_wire(color) : null),
"cut" = is_color_cut(color),
"attached" = is_attached(color)
)))
data["wires"] = payload
data["status"] = get_status()
return data
/datum/wires/ui_act(action, params)
if(..() || !interactable(usr))
return
var/target_wire = params["wire"]
var/mob/living/L = usr
var/obj/item/I = L.get_active_held_item()
switch(action)
if("cut")
if(istype(I, /obj/item/wirecutters) || IsAdminGhost(usr))
playsound(holder, I.usesound, 20, 1)
cut_color(target_wire)
. = TRUE
else
to_chat(L, "<span class='warning'>You need wirecutters!</span>")
if("pulse")
if(istype(I, /obj/item/device/multitool) || IsAdminGhost(usr))
playsound(holder, 'sound/weapons/empty.ogg', 20, 1)
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if (!ui)
ui = new(user, src, ui_key, "wires", "[holder.name] wires", 350, 150 + wires.len * 30, master_ui, state)
ui.open()
/datum/wires/ui_data(mob/user)
var/list/data = list()
var/list/payload = list()
for(var/color in colors)
payload.Add(list(list(
"color" = color,
"wire" = (IsAdminGhost(user) || (user.is_holding_item_of_type(/obj/item/device/multitool/abductor)) ? get_wire(color) : null),
"cut" = is_color_cut(color),
"attached" = is_attached(color)
)))
data["wires"] = payload
data["status"] = get_status()
return data
/datum/wires/ui_act(action, params)
if(..() || !interactable(usr))
return
var/target_wire = params["wire"]
var/mob/living/L = usr
var/obj/item/I = L.get_active_held_item()
switch(action)
if("cut")
if(istype(I, /obj/item/wirecutters) || IsAdminGhost(usr))
playsound(holder, I.usesound, 20, 1)
cut_color(target_wire)
. = TRUE
else
to_chat(L, "<span class='warning'>You need wirecutters!</span>")
if("pulse")
if(istype(I, /obj/item/device/multitool) || IsAdminGhost(usr))
playsound(holder, 'sound/weapons/empty.ogg', 20, 1)
pulse_color(target_wire, L)
. = TRUE
else
to_chat(L, "<span class='warning'>You need a multitool!</span>")
if("attach")
if(is_attached(target_wire))
var/obj/item/O = detach_assembly(target_wire)
if(O)
L.put_in_hands(O)
. = TRUE
else
if(istype(I, /obj/item/device/assembly))
var/obj/item/device/assembly/A = I
if(A.attachable)
if(!L.drop_item())
return
attach_assembly(target_wire, A)
. = TRUE
else
to_chat(L, "<span class='warning'>You need an attachable assembly!</span>")
#undef MAXIMUM_EMP_WIRES
. = TRUE
else
to_chat(L, "<span class='warning'>You need a multitool!</span>")
if("attach")
if(is_attached(target_wire))
var/obj/item/O = detach_assembly(target_wire)
if(O)
L.put_in_hands(O)
. = TRUE
else
if(istype(I, /obj/item/device/assembly))
var/obj/item/device/assembly/A = I
if(A.attachable)
if(!L.drop_item())
return
attach_assembly(target_wire, A)
. = TRUE
else
to_chat(L, "<span class='warning'>You need an attachable assembly!</span>")
#undef MAXIMUM_EMP_WIRES
+1 -1
View File
@@ -118,7 +118,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
else if(dynamic_lighting != DYNAMIC_LIGHTING_IFSTARLIGHT)
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
if(dynamic_lighting == DYNAMIC_LIGHTING_IFSTARLIGHT)
dynamic_lighting = config.starlight ? DYNAMIC_LIGHTING_ENABLED : DYNAMIC_LIGHTING_DISABLED
dynamic_lighting = CONFIG_GET(flag/starlight) ? DYNAMIC_LIGHTING_ENABLED : DYNAMIC_LIGHTING_DISABLED
. = ..()
+15
View File
@@ -143,3 +143,18 @@
/area/ctf/flag_room2
name = "Flag Room B"
// REEBE
/area/reebe
name = "Reebe"
icon_state = "yellow"
requires_power = FALSE
has_gravity = TRUE
noteleport = TRUE
hidden = TRUE
/area/reebe/city_of_cogs
name = "City of Cogs"
icon_state = "purple"
hidden = FALSE
+26 -5
View File
@@ -225,6 +225,17 @@
A.CollidedWith(src)
/atom/movable/proc/forceMove(atom/destination)
. = FALSE
if(destination)
. = doMove(destination)
else
CRASH("No valid destination passed into forceMove")
/atom/movable/proc/moveToNullspace()
return doMove(null)
/atom/movable/proc/doMove(atom/destination)
. = FALSE
if(destination)
if(pulledby)
pulledby.stop_pulling()
@@ -251,8 +262,17 @@
AM.Crossed(src, oldloc)
Moved(oldloc, 0)
return 1
return 0
. = TRUE
//If no destination, move the atom into nullspace (don't do this unless you know what you're doing)
else
. = TRUE
var/atom/oldloc = loc
var/area/old_area = get_area(oldloc)
oldloc.Exited(src, null)
if(old_area)
old_area.Exited(src, null)
loc = null
/mob/living/forceMove(atom/destination)
stop_pulling()
@@ -261,9 +281,10 @@
if(has_buckled_mobs())
unbuckle_all_mobs(force=1)
. = ..()
if(client)
reset_perspective(destination)
update_canmove() //if the mob was asleep inside a container and then got forceMoved out we need to make them fall.
if(.)
if(client)
reset_perspective(destination)
update_canmove() //if the mob was asleep inside a container and then got forceMoved out we need to make them fall.
/mob/living/brain/forceMove(atom/destination)
if(container)
+2 -2
View File
@@ -203,9 +203,9 @@
var/mob/living/silicon/robot/R
switch(borg_to_spawn)
if("Medical")
R = new /mob/living/silicon/robot/syndicate/medical(T)
R = new /mob/living/silicon/robot/modules/syndicate/medical(T)
else
R = new /mob/living/silicon/robot/syndicate(T) //Assault borg by default
R = new /mob/living/silicon/robot/modules/syndicate(T) //Assault borg by default
var/brainfirstname = pick(GLOB.first_names_male)
if(prob(50))
+1 -1
View File
@@ -78,7 +78,7 @@ GLOBAL_LIST_EMPTY(blobs_legit) //used for win-score calculations, contains only
var/mob/camera/blob/B = blob.current.become_overmind(TRUE, round(blob_base_starting_points/blob_overminds.len))
B.mind.name = B.name
var/turf/T = pick(GLOB.blobstart)
B.loc = T
B.forceMove(T)
B.base_point_rate = blob_point_rate
SSshuttle.registerHostileEnvironment(src)
+1 -1
View File
@@ -7,7 +7,7 @@
if(B.blob_core || !B.placed)
return 0
if(!GLOB.blob_cores.len) //blob is dead
if(config.continuous["blob"])
if(CONFIG_GET(keyed_flag_list/continuous)["blob"])
message_sent = FALSE //disable the win count at this point
continuous_sanity_checked = 1 //Nonstandard definition of "alive" gets past the check otherwise
SSshuttle.clearHostileEnvironment(src)
+1 -1
View File
@@ -59,7 +59,7 @@
set name = "Jump to Core"
set desc = "Move your camera to your core."
if(blob_core)
src.loc = blob_core.loc
forceMove(blob_core.drop_location())
/mob/camera/blob/verb/jump_to_node()
set category = "Blob"
+1 -1
View File
@@ -190,7 +190,7 @@
B.density = TRUE
if(T.Enter(B,src)) //NOW we can attempt to move into the tile
B.density = initial(B.density)
B.loc = T
B.forceMove(T)
B.update_icon()
if(B.overmind && expand_reaction)
B.overmind.blob_reagent_datum.expand_reaction(src, B, T, controller)
+6 -5
View File
@@ -17,7 +17,7 @@
/datum/objective_team/brother_team/proc/forge_brother_objectives()
objectives = list()
var/is_hijacker = prob(10)
for(var/i = 1 to max(1, config.brother_objectives_amount + (members.len > 2) - is_hijacker))
for(var/i = 1 to max(1, CONFIG_GET(number/brother_objectives_amount) + (members.len > 2) - is_hijacker))
forge_single_objective()
if(is_hijacker)
if(!locate(/datum/objective/hijack) in objectives)
@@ -58,16 +58,17 @@
var/meeting_areas = list("The Bar", "Dorms", "Escape Dock", "Arrivals", "Holodeck", "Primary Tool Storage", "Recreation Area", "Chapel", "Library")
/datum/game_mode/traitor/bros/pre_setup()
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/list/datum/mind/possible_brothers = get_players_for_role(ROLE_BROTHER)
var/num_teams = team_amount
if(config.brother_scaling_coeff)
num_teams = max(1, round(num_players()/config.brother_scaling_coeff))
var/bsc = CONFIG_GET(number/brother_scaling_coeff)
if(bsc)
num_teams = max(1, round(num_players() / bsc))
for(var/j = 1 to num_teams)
if(possible_brothers.len < min_team_size || antag_candidates.len <= required_enemies)
+18 -10
View File
@@ -52,16 +52,17 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
/datum/game_mode/changeling/pre_setup()
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/num_changelings = 1
if(config.changeling_scaling_coeff)
num_changelings = max(1, min( round(num_players()/(config.changeling_scaling_coeff*2))+2, round(num_players()/config.changeling_scaling_coeff) ))
var/csc = CONFIG_GET(number/changeling_scaling_coeff)
if(csc)
num_changelings = max(1, min(round(num_players() / (csc * 2)) + 2, round(num_players() / csc)))
else
num_changelings = max(1, min(num_players(), changeling_amount))
@@ -102,10 +103,11 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
..()
/datum/game_mode/changeling/make_antag_chance(mob/living/carbon/human/character) //Assigns changeling to latejoiners
var/changelingcap = min( round(GLOB.joined_player_list.len/(config.changeling_scaling_coeff*2))+2, round(GLOB.joined_player_list.len/config.changeling_scaling_coeff) )
var/csc = CONFIG_GET(number/changeling_scaling_coeff)
var/changelingcap = min(round(GLOB.joined_player_list.len / (csc * 2)) + 2, round(GLOB.joined_player_list.len / csc))
if(SSticker.mode.changelings.len >= changelingcap) //Caps number of latejoin antagonists
return
if(SSticker.mode.changelings.len <= (changelingcap - 2) || prob(100 - (config.changeling_scaling_coeff*2)))
if(SSticker.mode.changelings.len <= (changelingcap - 2) || prob(100 - (csc * 2)))
if(ROLE_CHANGELING in character.client.prefs.be_special)
if(!jobban_isbanned(character, ROLE_CHANGELING) && !jobban_isbanned(character, "Syndicate"))
if(age_check(character.client))
@@ -131,10 +133,16 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
changeling.objectives += absorb_objective
if(prob(60))
var/datum/objective/steal/steal_objective = new
steal_objective.owner = changeling
steal_objective.find_target()
changeling.objectives += steal_objective
if(prob(85))
var/datum/objective/steal/steal_objective = new
steal_objective.owner = changeling
steal_objective.find_target()
changeling.objectives += steal_objective
else
var/datum/objective/download/download_objective = new
download_objective.owner = changeling
download_objective.gen_amount_goal()
changeling.objectives += download_objective
var/list/active_ais = active_ais()
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
@@ -30,7 +30,7 @@
sleep(5) // So it's not killed in explosion
var/mob/living/simple_animal/hostile/headcrab/crab = new(turf)
for(var/obj/item/organ/I in organs)
I.loc = crab
I.forceMove(crab)
crab.origin = M
if(crab.origin)
crab.origin.active = 1
@@ -77,10 +77,10 @@
return
..()
/obj/effect/proc_holder/changeling/sting/transformation/can_sting(mob/user, mob/target)
/obj/effect/proc_holder/changeling/sting/transformation/can_sting(mob/user, mob/living/carbon/target)
if(!..())
return
if((target.disabilities & HUSK) || !target.has_dna())
if((target.disabilities & HUSK) || !iscarbon(target) || (NOTRANSSTING in target.dna.species.species_traits))
to_chat(user, "<span class='warning'>Our sting appears ineffective against its DNA.</span>")
return 0
return 1
@@ -25,18 +25,19 @@
return 1
/datum/game_mode/traitor/changeling/pre_setup()
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/list/datum/mind/possible_changelings = get_players_for_role(ROLE_CHANGELING)
var/num_changelings = 1
if(config.changeling_scaling_coeff)
num_changelings = max(1, min( round(num_players()/(config.changeling_scaling_coeff*4))+2, round(num_players()/(config.changeling_scaling_coeff*2)) ))
var/csc = CONFIG_GET(number/changeling_scaling_coeff)
if(csc)
num_changelings = max(1, min(round(num_players() / (csc * 4)) + 2, round(num_players() / (csc * 2))))
else
num_changelings = max(1, min(num_players(), changeling_amount/2))
@@ -64,11 +65,12 @@
return
/datum/game_mode/traitor/changeling/make_antag_chance(mob/living/carbon/human/character) //Assigns changeling to latejoiners
var/changelingcap = min( round(GLOB.joined_player_list.len/(config.changeling_scaling_coeff*4))+2, round(GLOB.joined_player_list.len/(config.changeling_scaling_coeff*2)) )
var/csc = CONFIG_GET(number/changeling_scaling_coeff)
var/changelingcap = min( round(GLOB.joined_player_list.len / (csc * 4)) + 2, round(GLOB.joined_player_list.len / (csc * 2)))
if(SSticker.mode.changelings.len >= changelingcap) //Caps number of latejoin antagonists
..()
return
if(SSticker.mode.changelings.len <= (changelingcap - 2) || prob(100 / (config.changeling_scaling_coeff * 4)))
if(SSticker.mode.changelings.len <= (changelingcap - 2) || prob(100 / (csc * 4)))
if(ROLE_CHANGELING in character.client.prefs.be_special)
if(!jobban_isbanned(character, ROLE_CHANGELING) && !jobban_isbanned(character, "Syndicate"))
if(age_check(character.client))
+106 -44
View File
@@ -8,12 +8,9 @@ Imprisoned within a massive construct known as the Celestial Derelict - or Reebe
Ratvar, unable to act in the mortal plane, seeks to return and forms covenants with mortals in order to bolster his influence.
Due to his mechanical nature, Ratvar is also capable of influencing silicon-based lifeforms, unlike Nar-Sie, who can only influence natural life.
This is a team-based gamemode, and the team's objective is shared by all cultists. It can include summoning Ratvar, escaping on the shuttle, or converting the AI and its cyborgs.
This is a team-based gamemode, and the team's objective is shared by all cultists. Their goal is to defend an object called the Ark on a separate z-level.
The clockwork version of an arcane tome is the clockwork slab.
While it can perform certain actions, it consumes a resource called components.
Components, which are fallen fragments of Ratvar's body as he rusts in Reebe, are powerful and have various effects.
Game-wise, clockwork slabs will generate components over time, with more powerful components being slower.
This file's folder contains:
clock_cult.dm: Core gamemode files.
@@ -36,8 +33,8 @@ Credit where due:
2. SkowronX from /vg/ for MANY of the assets
3. FuryMcFlurry from /vg/ for many of the assets
4. PJB3005 from /vg/ for the failed continuation PR
5. Xhuis from /tg/ for coding the basic gamemode as it is today
6. ChangelingRain from /tg/ for maintaining the gamemode for months after its release
5. Xhuis from /tg/ for coding the first iteration of the mode, and the new, reworked version
6. ChangelingRain from /tg/ for maintaining the gamemode for months after its release prior to its rework
*/
@@ -88,7 +85,7 @@ Credit where due:
/datum/game_mode
var/list/servants_of_ratvar = list() //The Enlightened servants of Ratvar
var/clockwork_explanation = "Construct a Gateway to the Celestial Derelict and free Ratvar." //The description of the current objective
var/clockwork_explanation = "Defend the Ark of the Clockwork Justiciar and free Ratvar." //The description of the current objective
/datum/game_mode/clockwork_cult
name = "clockwork cult"
@@ -103,30 +100,34 @@ Credit where due:
restricted_jobs = list("Chaplain", "Captain")
announce_span = "brass"
announce_text = "Servants of Ratvar are trying to summon the Justiciar!\n\
<span class='brass'>Servants</span>: Take over the station and summon Ratvar.\n\
<span class='brass'>Servants</span>: Construct defenses to protect the Ark. Sabotage the station!\n\
<span class='notice'>Crew</span>: Stop the servants before they can summon the Clockwork Justiciar."
var/servants_to_serve = list()
var/roundstart_player_count
var/ark_time //In minutes, how long the Ark waits before activation; this is equal to 30 + (number of players / 5) (max 40 mins.)
/datum/game_mode/clockwork_cult/pre_setup()
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/starter_servants = 3 //Guaranteed three servants
var/starter_servants = 4 //Guaranteed four servants
var/number_players = num_players()
roundstart_player_count = number_players
if(number_players > 30) //plus one servant for every additional 15 players
if(number_players > 30) //plus one servant for every additional 10 players above 30
number_players -= 30
starter_servants += round(number_players/15)
starter_servants += round(number_players / 10)
starter_servants = min(starter_servants, 8) //max 8 servants (that sould only happen with a ton of players)
while(starter_servants)
var/datum/mind/servant = pick(antag_candidates)
servants_to_serve += servant
antag_candidates -= servant
modePlayer += servant
servant.assigned_role = "Servant of Ratvar"
servant.special_role = "Servant of Ratvar"
servant.restricted_roles = restricted_jobs
starter_servants--
ark_time = 30 + round((roundstart_player_count / 5)) //In minutes, how long the Ark will wait before activation
ark_time = min(ark_time, 35) //35 minute maximum for the activation timer
return 1
/datum/game_mode/clockwork_cult/post_setup()
@@ -134,26 +135,35 @@ Credit where due:
var/datum/mind/servant = S
log_game("[servant.key] was made an initial servant of Ratvar")
var/mob/living/L = servant.current
var/turf/T = pick(GLOB.servant_spawns)
L.forceMove(T)
GLOB.servant_spawns -= T
greet_servant(L)
equip_servant(L)
add_servant_of_ratvar(L, TRUE)
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar //that's a mouthful
G.initial_activation_delay = ark_time * 60
G.seconds_until_activation = ark_time * 60 //60 seconds in a minute * number of minutes
..()
return 1
/datum/game_mode/clockwork_cult/proc/greet_servant(mob/M) //Description of their role
if(!M)
return 0
var/greeting_text = "<br><b><span class='large_brass'>You are a servant of Ratvar, the Clockwork Justiciar.</span>\n\
Rusting eternally in the Celestial Derelict, Ratvar has formed a covenant of mortals, with you as one of its members. As one of the Justiciar's servants, you are to work to the best of your \
ability to assist in completion of His agenda. You may not know the specifics of how to do so, but luckily you have a vessel to help you learn.</b>"
to_chat(M, greeting_text)
to_chat(M, "<span class='bold large_brass'>You are a servant of Ratvar, the Clockwork Justiciar!</span>")
to_chat(M, "<span class='brass'>You have approximately <b>[ark_time]</b> minutes until the Ark activates.</span>")
to_chat(M, "<span class='brass'>Unlock <b>Script</b> scripture by converting a new servant.</span>")
to_chat(M, "<span class='brass'><b>Application</b> scripture will be unlocked halfway until the Ark's activation.</span>")
M.playsound_local(get_turf(M), 'sound/ambience/antag/clockcultalr.ogg', 100, FALSE, pressure_affected = FALSE)
return 1
/datum/game_mode/proc/equip_servant(mob/living/L) //Grants a clockwork slab to the mob, with one of each component
if(!L || !istype(L))
/datum/game_mode/proc/equip_servant(mob/living/M) //Grants a clockwork slab to the mob, with one of each component
if(!M || !ishuman(M))
return FALSE
var/obj/item/clockwork/slab/starter/S = new/obj/item/clockwork/slab/starter(null) //start it off in null
var/mob/living/carbon/human/L = M
L.set_species(/datum/species/human)
L.equipOutfit(/datum/outfit/servant_of_ratvar)
var/obj/item/clockwork/slab/S = new
var/slot = "At your feet"
var/list/slots = list("In your left pocket" = slot_l_store, "In your right pocket" = slot_r_store, "In your backpack" = slot_in_backpack, "On your belt" = slot_belt)
if(ishuman(L))
@@ -165,26 +175,24 @@ Credit where due:
if(!S.forceMove(get_turf(L)))
qdel(S)
if(S && !QDELETED(S))
to_chat(L, "<b>[slot] is a link to the halls of Reebe and your master. You may use it to perform many tasks, but also become oriented with the workings of Ratvar and how to best complete your \
tasks. This clockwork slab will be instrumental in your triumph. Remember: you can speak discreetly with your fellow servants by using the <span class='brass'>Hierophant Network</span> action button, \
and you can find a concise tutorial by using the slab in-hand and selecting Recollection.</b>")
to_chat(L, "<i>Alternatively, check out the wiki page at </i><b>https://tgstation13.org/wiki/Clockwork_Cult</b><i>, which contains additional information.</i>")
to_chat(L, "<span class='bold large_brass'>There is a paper in your backpack! Read it!</span>")
to_chat(L, "<span class='alloy'>[slot] is a <b>clockwork slab</b>, a multipurpose tool used to construct machines and invoke ancient words of power. If this is your first time \
as a servant, you can find a concise tutorial in the Recollection category of its interface.</span>")
to_chat(L, "<span class='alloy italics'>If you want more information, you can find a wiki link here!</span> https://tgstation13.org/wiki/Clockwork_Cult")
return TRUE
return FALSE
/datum/game_mode/clockwork_cult/proc/check_clockwork_victory()
if(GLOB.clockwork_gateway_activated)
SSticker.news_report = CLOCK_PROSELYTIZATION //failure, technically, but we have the station
if(GLOB.ratvar_awakens)
SSticker.news_report = CLOCK_SUMMON
return TRUE
if(GLOB.clockwork_gateway_activated || SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
SSticker.news_report = CLOCK_SUMMON
return TRUE
else
SSticker.news_report = CULT_FAILURE
return FALSE
/datum/game_mode/clockwork_cult/declare_completion()
..()
return 0 //Doesn't end until the round does
return //Doesn't end until the round does
/datum/game_mode/clockwork_cult/generate_report()
return "We have lost contact with multiple stations in your sector. They have gone dark and do not respond to all transmissions, although they appear intact and the crew's life \
@@ -198,21 +206,12 @@ Credit where due:
if(istype(SSticker.mode, /datum/game_mode/clockwork_cult)) //Possibly hacky?
var/datum/game_mode/clockwork_cult/C = SSticker.mode
if(C.check_clockwork_victory())
text += "<span class='large_brass'><b>Ratvar's servants have succeeded in fulfilling His goals!</b></span>"
text += "<span class='large_brass'><b>Ratvar's servants defended the Ark until its activation!</b></span>"
SSticker.mode_result = "win - servants completed their objective (summon ratvar)"
else
var/half_victory = FALSE
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = locate() in GLOB.all_clockwork_objects
if(G)
half_victory = TRUE
if(half_victory)
text += "<span class='large_brass'><b>The crew escaped before Ratvar could rise, but the gateway \
was successfully constructed!</b></span>"
SSticker.mode_result = "halfwin - servants constructed the gateway but their objective was not completed (summon ratvar)"
else
text += "<span class='userdanger'>Ratvar's servants have failed!</span>"
SSticker.mode_result = "loss - servants failed their objective (summon ratvar)"
text += "<br><b>The servants' objective was:</b> <br>[CLOCKCULT_OBJECTIVE]"
text += "<span class='userdanger'>The Ark was destroyed! Ratvar will rust away for all eternity!</span>"
SSticker.mode_result = "loss - servants failed their objective (summon ratvar)"
text += "<br><b>The servants' objective was:</b> [CLOCKCULT_OBJECTIVE]."
text += "<br>Ratvar's servants had <b>[GLOB.clockwork_caches]</b> Tinkerer's Caches."
text += "<br><b>Construction Value(CV)</b> was: <b>[GLOB.clockwork_construction_value]</b>"
for(var/i in SSticker.scripture_states)
@@ -233,3 +232,66 @@ Credit where due:
var/datum/atom_hud/antag/A = GLOB.huds[ANTAG_HUD_CLOCKWORK]
A.leave_hud(M.current)
set_antag_hud(M.current, null)
//Servant of Ratvar outfit
/datum/outfit/servant_of_ratvar
uniform = /obj/item/clothing/under/chameleon/ratvar
shoes = /obj/item/clothing/shoes/workboots
back = /obj/item/storage/backpack
ears = /obj/item/device/radio/headset
gloves = /obj/item/clothing/gloves/color/yellow
belt = /obj/item/storage/belt/utility/servant
backpack_contents = list(/obj/item/storage/box/engineer = 1, \
/obj/item/clockwork/replica_fabricator = 1, /obj/item/stack/tile/brass/fifty = 1, /obj/item/paper/servant_primer = 1)
id = /obj/item/card/id
/datum/outfit/servant_of_ratvar/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
var/obj/item/card/id/W = H.wear_id
W.assignment = "Assistant"
W.access += ACCESS_MAINT_TUNNELS
W.registered_name = H.real_name
W.update_label()
/obj/item/paper/servant_primer
name = "The Ark And You: A Primer On Servitude"
color = "#DAAA18"
info = "<b>DON'T PANIC.</b><br><br>\
Here's a quick primer on what you should know here.\
<ol>\
<li>You're in a place called Reebe right now. The crew can't get here normally.</li>\
<li>In the north is your base camp, with supplies, consoles, and the Ark. In the south is an inaccessible area that the crew can walk between \
once they arrive (more on that later.) Everything between that space is an open area.</li>\
<li>Your job as a servant is to build fortifications and defenses to protect the Ark and your base once the Ark activates. You can do this \
however you like, but work with your allies and coordinate your efforts.</li>\
<li>Once the Ark activates, the station will be alerted. Portals to Reebe will open up in nearly every room. When they take these portals, \
the crewmembers will arrive in the area that you can't access, but can get through it freely - whereas you can't. Treat this as the \"spawn\" of the \
crew and defend it accordingly.</li>\
</ol>\
<hr>\
Here is the layout of Reebe, from left to right:\
<ul>\
<li><b>Dressing Room:</b> Contains clothing, a dresser, and a mirror. There are spare slabs and absconders here.</li>\
<li><b>Listening Station:</b> Contains intercoms, a telecomms relay, and a list of frequencies.</li>\
<li><b>Ark Chamber:</b> Houses the Ark.</li>\
<li><b>Observation Room:</b> Contains five camera observers. These can be used to watch the station through its cameras, as well as to teleport down \
to most areas. To do this, use the Warp action while hovering over the tile you want to warp to.</li>\
<li><b>Infirmary:</b> Contains sleepers and basic medical supplies for superficial wounds. The sleepers can consume Vitality to heal any occupants. \
This room is generally more useful during the preparation phase; when defending the Ark, scripture is more useful.</li>\
</ul>\
<hr>\
<h2>Things that have changed:</h2>\
<ul>\
<li><b><i>Scripture no longer requires components, and instead uses power.</i></b></li>\
<li>Added a <b>5-minute grace period</b> for the crew to prepare for the assault when the Ark activates.</li>\
<li>Script and Application scriptures can now be unlocked with enough power.</li>\
<li><b>Added the Hateful Manacles scripture</b>, which handcuffs targets!</li>\
</ul>\
<hr>\
<b>Good luck!</b>"
/obj/item/paper/servant_primer/examine(mob/user)
if(!is_servant_of_ratvar(user) && !isobserver(user))
to_chat(user, "<span class='danger'>You can't understand any of the words on [src].</span>")
..()
@@ -0,0 +1,50 @@
//These spawn across the station when the Ark activates. Anyone can walk through one to teleport to Reebe.
/obj/effect/clockwork/city_of_cogs_rift
name = "celestial rift"
desc = "A stable bluespace rip. You're not sure it where leads."
clockwork_desc = "A one-way rift to the City of Cogs. Because it's linked to the Ark, it can't be closed."
icon_state = "city_of_cogs_rift"
resistance_flags = INDESTRUCTIBLE
density = TRUE
light_range = 2
light_power = 3
light_color = "#6A4D2F"
/obj/effect/clockwork/city_of_cogs_rift/Initialize()
. = ..()
visible_message("<span class='warning'>The air above [loc] shimmers and pops as a [name] forms there!</span>")
for(var/mob/M in GLOB.player_list)
if(M.z == z)
if(get_dist(src, M) >= 7)
M.playsound_local(src, 'sound/magic/blink.ogg', 10, FALSE, falloff = 10)
else
M.playsound_local(src, 'sound/magic/blink.ogg', 50, FALSE)
/obj/effect/clockwork/city_of_cogs_rift/Destroy()
visible_message("<span class='warning'>[src] cracks as it destabilizes and breaks apart!</span>")
return ..()
/obj/effect/clockwork/city_of_cogs_rift/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/nullrod))
to_chat(user, "<span class='warning'>Your [I.name] seems to have no effect on [src]!</span>")
return
. = ..()
/obj/effect/clockwork/city_of_cogs_rift/attack_hand(atom/movable/AM)
beckon(AM)
/obj/effect/clockwork/city_of_cogs_rift/CollidedWith(atom/movable/AM)
if(!QDELETED(AM))
beckon(AM)
/obj/effect/clockwork/city_of_cogs_rift/proc/beckon(atom/movable/AM)
AM.visible_message("<span class='danger'>[AM] passes through [src]!</span>", ignore_mob = AM)
AM.forceMove(pick(!is_servant_of_ratvar(AM) ? GLOB.city_of_cogs_spawns : GLOB.servant_spawns))
AM.visible_message("<span class='danger'>[AM] materializes from the air!</span>", \
"<span class='boldannounce'>You pass through [src] and appear [is_servant_of_ratvar(AM) ? "back at the City of Cogs" : "somewhere unfamiliar. Looks like it was a one-way trip.."].</span>")
do_sparks(5, TRUE, src)
do_sparks(5, TRUE, AM)
if(isliving(AM))
var/mob/living/L = AM
L.overlay_fullscreen("flash", /obj/screen/fullscreen/flash/static)
L.clear_fullscreen("flash", 5)
@@ -11,21 +11,11 @@
var/stat_affected = CONSCIOUS
var/sigil_name = "Sigil"
var/resist_string = "glows blinding white" //string for when a null rod blocks its effects, "glows [resist_string]"
var/list/component_refund = list()
/obj/effect/clockwork/sigil/attackby(obj/item/I, mob/living/user, params)
if(is_servant_of_ratvar(user))
if(istype(I, /obj/item/clockwork/slab))
user.visible_message("<span class='warning'>[user] starts to dispel [src]...</span>", "<span class='danger'>You start to dispel [src]...</span>")
if(do_after(user, 20, target = src))
user.visible_message("<span class='warning'>[user] dispels [src]!</span>", "<span class='danger'>You dispel [src]!</span>")
for(var/i in component_refund)
if(component_refund[i])
for(var/r in 1 to component_refund[i])
generate_cache_component(i, src)
qdel(src)
return 1
else if(I.force)
if(I.force)
if(is_servant_of_ratvar(user) && user.a_intent != INTENT_HARM)
return ..()
user.visible_message("<span class='warning'>[user] scatters [src] with [I]!</span>", "<span class='danger'>You scatter [src] with [I]!</span>")
qdel(src)
return 1
@@ -35,7 +25,9 @@
return //you can't tk stomp sigils, but you can hit them with something
/obj/effect/clockwork/sigil/attack_hand(mob/user)
if(iscarbon(user) && !user.stat && !is_servant_of_ratvar(user))
if(iscarbon(user) && !user.stat)
if(is_servant_of_ratvar(user) && user.a_intent != INTENT_HARM)
return ..()
user.visible_message("<span class='warning'>[user] stamps out [src]!</span>", "<span class='danger'>You stomp on [src], scattering it into thousands of particles.</span>")
qdel(src)
return 1
@@ -75,7 +67,6 @@
light_power = 1
light_color = "#FAE48C"
sigil_name = "Sigil of Transgression"
component_refund = list(HIEROPHANT_ANSIBLE = 1)
/obj/effect/clockwork/sigil/transgression/sigil_effects(mob/living/L)
var/target_flashed = L.flash_act()
@@ -85,10 +76,11 @@
if(iscultist(L))
to_chat(L, "<span class='heavy_brass'>\"Watch your step, wretch.\"</span>")
L.adjustBruteLoss(10)
L.Knockdown(140, FALSE)
L.Knockdown(80, FALSE)
L.visible_message("<span class='warning'>[src] appears around [L] in a burst of light!</span>", \
"<span class='userdanger'>[target_flashed ? "An unseen force":"The glowing sigil around you"] holds you in place!</span>")
L.Stun(100)
L.Stun(40)
L.apply_status_effect(STATUS_EFFECT_BELLIGERENT)
new /obj/effect/temp_visual/ratvar/sigil/transgression(get_turf(src))
qdel(src)
@@ -107,18 +99,23 @@
light_color = "#FAE48C"
stat_affected = UNCONSCIOUS
resist_string = "glows faintly yellow"
sigil_name = "Sigil of Submission"
component_refund = list(GEIS_CAPACITOR = 1)
var/convert_time = 80
var/delete_on_finish = TRUE
sigil_name = "Sigil of Submission"
var/glow_type = /obj/effect/temp_visual/ratvar/sigil/submission
/obj/effect/clockwork/sigil/submission/sigil_effects(mob/living/L)
if(istype(L.buckled, /obj/structure/destructible/clockwork/geis_binding))
if(is_servant_of_ratvar(L.pulledby))
L.pulledby.stop_pulling()
if(is_servant_of_ratvar(L.buckled.pulledby))
L.buckled.pulledby.stop_pulling()
var/turf/T = get_turf(src)
var/has_sigil = FALSE
var/has_servant = FALSE
if(locate(/obj/effect/clockwork/sigil/transgression) in T)
has_sigil = TRUE
for(var/mob/living/M in range(3, src))
if(is_servant_of_ratvar(M) && !M.stat)
has_servant = TRUE
if(!has_sigil && !has_servant)
visible_message("<span class='danger'>[src] strains into a gentle violet color, but quietly fades...</span>")
return
L.visible_message("<span class='warning'>[src] begins to glow a piercing magenta!</span>", "<span class='sevtug'>You feel something start to invade your mind...</span>")
var/oldcolor = color
animate(src, color = "#AF0AAF", time = convert_time, flags = ANIMATION_END_NOW)
@@ -127,10 +124,10 @@
glow = new glow_type(get_turf(src))
animate(glow, alpha = 255, time = convert_time)
var/I = 0
while(I < convert_time && !QDELETED(L) && get_turf(L) == get_turf(src))
while(I < convert_time && get_turf(L) == get_turf(src))
I++
sleep(1)
if(QDELETED(L) || get_turf(L) != get_turf(src))
if(get_turf(L) != get_turf(src))
if(glow)
qdel(glow)
animate(src, color = oldcolor, time = 20, flags = ANIMATION_END_NOW)
@@ -139,6 +136,9 @@
return
if(is_eligible_servant(L))
to_chat(L, "<span class='heavy_brass'>\"You belong to me now.\"</span>")
if(!GLOB.application_scripture_unlocked)
GLOB.application_scripture_unlocked = TRUE
hierophant_message("<span class='large_brass bold'>With the conversion of a new servant the Ark's power grows. Application scriptures are now available.</span>")
if(add_servant_of_ratvar(L))
L.log_message("<font color=#BE8700>Conversion was done with a [sigil_name].</font>", INDIVIDUAL_ATTACK_LOG)
L.Knockdown(50) //Completely defenseless for five seconds - mainly to give them time to read over the information they've just been presented with
@@ -160,29 +160,26 @@
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
//Sigil of Transmission: Stores power for clockwork machinery, serving as a battery.
//Sigil of Transmission: Serves as an access point for powered structures.
/obj/effect/clockwork/sigil/transmission
name = "suspicious sigil"
desc = "A glowing orange sigil. The air around it feels staticky."
clockwork_desc = "A sigil that serves as power generation and a battery for clockwork structures."
clockwork_desc = "A sigil that serves as power generation and a battery for clockwork structures, linked to all other sigils of its type."
icon_state = "sigiltransmission"
alpha = 50
color = "#EC8A2D"
light_color = "#EC8A2D"
resist_string = "glows faintly"
sigil_name = "Sigil of Transmission"
component_refund = list(HIEROPHANT_ANSIBLE = 1)
affects_servants = TRUE
var/power_charge = 0 //starts with no power
var/drain_range = 14
/obj/effect/clockwork/sigil/transmission/Initialize()
. = ..()
update_glow()
update_icon()
/obj/effect/clockwork/sigil/transmission/ex_act(severity)
if(severity == 3)
modify_charge(-500)
adjust_clockwork_power(500) //Light explosions charge the network!
visible_message("<span class='warning'>[src] flares a brilliant orange!</span>")
else
..()
@@ -193,70 +190,26 @@
var/structure_number = 0
for(var/obj/structure/destructible/clockwork/powered/P in range(SIGIL_ACCESS_RANGE, src))
structure_number++
to_chat(user, "<span class='[power_charge ? "brass":"alloy"]'>It is storing <b>[GLOB.ratvar_awakens ? "INFINITE</b>":"[DisplayPower(power_charge)]</b> of"] power, \
and <b>[structure_number]</b> Clockwork Structure[structure_number == 1 ? " is":"s are"] in range.</span>")
to_chat(user, "<span class='brass'>While active, it will gradually drain power from nearby electronics. It is currently [isprocessing ? "active":"disabled"].</span>")
to_chat(user, "<span class='[get_clockwork_power() ? "brass":"alloy"]'>It is storing <b>[DisplayPower(get_clockwork_power())]</b> of shared power, \
and <b>[structure_number]</b> clockwork structure[structure_number == 1 ? " is":"s are"] in range.</span>")
if(iscyborg(user))
to_chat(user, "<span class='brass'>You can recharge from the [sigil_name] by crossing it.</span>")
else if(!GLOB.ratvar_awakens)
to_chat(user, "<span class='brass'>Hitting the [sigil_name] with brass sheets will convert them to power at a rate of <b>1</b> brass sheet to <b>[DisplayPower(POWER_FLOOR)]</b> power.</span>")
if(!GLOB.ratvar_awakens)
to_chat(user, "<span class='brass'>You can recharge Replica Fabricators from the [sigil_name].</span>")
/obj/effect/clockwork/sigil/transmission/attackby(obj/item/I, mob/living/user, params)
if(is_servant_of_ratvar(user) && istype(I, /obj/item/stack/tile/brass) && !GLOB.ratvar_awakens)
var/obj/item/stack/tile/brass/B = I
user.visible_message("<span class='warning'>[user] places [B] on [src], causing it to disintegrate into glowing orange energy!</span>", \
"<span class='brass'>You charge the [sigil_name] with [B], providing it with <b>[DisplayPower(B.amount * POWER_FLOOR)]</b> of power.</span>")
modify_charge(-(B.amount * POWER_FLOOR))
playsound(src, 'sound/effects/light_flicker.ogg', (B.amount * POWER_FLOOR) * 0.01, 1)
qdel(B)
return TRUE
return ..()
/obj/effect/clockwork/sigil/transmission/attack_ai(mob/user)
if(is_servant_of_ratvar(user))
attack_hand(user)
/obj/effect/clockwork/sigil/transmission/attack_hand(mob/user)
if(is_servant_of_ratvar(user))
visible_message("<span class='notice'>[user] [isprocessing ? "de":""]activates [src].</span>", "<span class='brass'>You [isprocessing ? "de":""]activate the [sigil_name].</span>")
if(isprocessing)
STOP_PROCESSING(SSobj, src)
else
START_PROCESSING(SSobj, src)
else
return ..()
/obj/effect/clockwork/sigil/transmission/sigil_effects(mob/living/L)
if(is_servant_of_ratvar(L))
if(iscyborg(L))
charge_cyborg(L)
else if(power_charge)
else if(get_clockwork_power())
to_chat(L, "<span class='brass'>You feel a slight, static shock.</span>")
/obj/effect/clockwork/sigil/transmission/process()
var/power_drained = 0
for(var/t in spiral_range_turfs(drain_range, src))
var/turf/T = t
for(var/M in T)
var/atom/movable/A = M
power_drained += A.power_drain(TRUE)
CHECK_TICK
modify_charge(-Floor(power_drained, MIN_CLOCKCULT_POWER))
new /obj/effect/temp_visual/ratvar/sigil/transmission(loc, 1 + (power_drained * 0.0035))
/obj/effect/clockwork/sigil/transmission/proc/charge_cyborg(mob/living/silicon/robot/cyborg)
if(!cyborg_checks(cyborg))
return
to_chat(cyborg, "<span class='brass'>You start to charge from the [sigil_name]...</span>")
if(!do_after(cyborg, 50, target = src, extra_checks = CALLBACK(src, .proc/cyborg_checks, cyborg, TRUE)))
return
var/giving_power = min(Floor(cyborg.cell.maxcharge - cyborg.cell.charge, MIN_CLOCKCULT_POWER), power_charge) //give the borg either all our power or their missing power floored to MIN_CLOCKCULT_POWER
if(modify_charge(giving_power))
var/giving_power = min(Floor(cyborg.cell.maxcharge - cyborg.cell.charge, MIN_CLOCKCULT_POWER), get_clockwork_power()) //give the borg either all our power or their missing power floored to MIN_CLOCKCULT_POWER
if(adjust_clockwork_power(-giving_power))
cyborg.visible_message("<span class='warning'>[cyborg] glows a brilliant orange!</span>")
var/previous_color = cyborg.color
cyborg.color = list("#EC8A2D", "#EC8A2D", "#EC8A2D", rgb(0,0,0))
@@ -269,9 +222,9 @@
if(!silent)
to_chat(cyborg, "<span class='warning'>You have no cell!</span>")
return FALSE
if(!power_charge)
if(!get_clockwork_power())
if(!silent)
to_chat(cyborg, "<span class='warning'>The [sigil_name] has no stored power!</span>")
to_chat(cyborg, "<span class='warning'>There is no power available across sigils!</span>")
return FALSE
if(cyborg.cell.charge > cyborg.cell.maxcharge - MIN_CLOCKCULT_POWER)
if(!silent)
@@ -283,25 +236,15 @@
return FALSE
return TRUE
/obj/effect/clockwork/sigil/transmission/proc/modify_charge(amount)
if(GLOB.ratvar_awakens)
update_glow()
return TRUE
if(power_charge - amount < 0)
return FALSE
power_charge -= amount
update_glow()
return TRUE
/obj/effect/clockwork/sigil/transmission/proc/update_glow()
/obj/effect/clockwork/sigil/transmission/update_icon()
if(GLOB.ratvar_awakens)
alpha = 255
else
alpha = min(initial(alpha) + power_charge*0.02, 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))
set_light(max(alpha * 0.02, 1.4), max(alpha * 0.01, 0.1))
//Vitality Matrix: Drains health from non-servants to heal or even revive servants.
/obj/effect/clockwork/sigil/vitality
@@ -316,7 +259,6 @@
stat_affected = DEAD
resist_string = "glows shimmering yellow"
sigil_name = "Vitality Matrix"
component_refund = list(VANGUARD_COGWHEEL = 1)
var/revive_cost = 150
var/sigil_active = FALSE
var/animation_number = 3 //each cycle increments this by 1, at 4 it produces an animation and resets
@@ -0,0 +1,20 @@
//Marks the point at which "no man's land" begins on Reebe. Servants can't pass beyond this point in any way.
/obj/effect/clockwork/servant_blocker
name = "glowing arrow"
desc = "A faintly glowing image of an arrow on the ground. Convenient!"
icon_state = "servant_blocker"
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
density = TRUE
/obj/effect/clockwork/servant_blocker/Destroy(force)
if(!force)
return
. = ..()
/obj/effect/clockwork/servant_blocker/CanPass(atom/movable/M, turf/target)
var/list/target_contents = M.GetAllContents() + M
for(var/mob/living/L in target_contents)
if(is_servant_of_ratvar(L) && get_dir(M, src) != dir) //Unless we're on the side the arrow is pointing directly away from, no-go
to_chat(L, "<span class='danger'>The space beyond here can't be accessed by you or other servants.</span>")
return
return TRUE
@@ -1,93 +1,3 @@
//generates a component in the global component cache, either random based on lowest or a specific component
/proc/generate_cache_component(specific_component_id, atom/A)
if(!specific_component_id)
specific_component_id = get_weighted_component_id()
GLOB.clockwork_component_cache[specific_component_id]++
if(A)
var/component_animation_type = get_component_animation_type(specific_component_id)
new component_animation_type(get_turf(A))
update_slab_info()
return specific_component_id
//returns a chosen component id based on the lowest amount of that component in the global cache, the global cache plus the slab if there are caches, or the slab if there are no caches.
/proc/get_weighted_component_id(obj/item/clockwork/slab/storage_slab)
. = list()
if(storage_slab)
if(GLOB.clockwork_caches)
for(var/i in GLOB.clockwork_component_cache)
.[i] = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*(GLOB.clockwork_component_cache[i] + storage_slab.stored_components[i]), 1)
else
for(var/i in GLOB.clockwork_component_cache)
.[i] = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*storage_slab.stored_components[i], 1)
else
for(var/i in GLOB.clockwork_component_cache)
.[i] = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*GLOB.clockwork_component_cache[i], 1)
for(var/obj/structure/destructible/clockwork/massive/celestial_gateway/G in GLOB.all_clockwork_objects)
if(G.still_needs_components())
for(var/i in G.required_components)
if(!G.required_components[i])
. -= i
break
. = pickweight(.)
//returns a component name from a component id
/proc/get_component_name(id)
switch(id)
if(BELLIGERENT_EYE)
return "Belligerent Eye"
if(VANGUARD_COGWHEEL)
return "Vanguard Cogwheel"
if(GEIS_CAPACITOR)
return "Geis Capacitor"
if(REPLICANT_ALLOY)
return "Replicant Alloy"
if(HIEROPHANT_ANSIBLE)
return "Hierophant Ansible"
else
return null
//returns a component acronym from a component id
/proc/get_component_acronym(id)
switch(id)
if(BELLIGERENT_EYE)
return "BE"
if(VANGUARD_COGWHEEL)
return "VC"
if(GEIS_CAPACITOR)
return "GC"
if(REPLICANT_ALLOY)
return "RA"
if(HIEROPHANT_ANSIBLE)
return "HA"
else
return null
//returns a component icon from a component id
/proc/get_component_icon(id)
var/static/list/tgui_component_icons = list(
BELLIGERENT_EYE = icon2base64(icon('icons/obj/tgui_components.dmi', BELLIGERENT_EYE)),
VANGUARD_COGWHEEL = icon2base64(icon('icons/obj/tgui_components.dmi', VANGUARD_COGWHEEL)),
GEIS_CAPACITOR = icon2base64(icon('icons/obj/tgui_components.dmi', GEIS_CAPACITOR)),
REPLICANT_ALLOY = icon2base64(icon('icons/obj/tgui_components.dmi', REPLICANT_ALLOY)),
HIEROPHANT_ANSIBLE = icon2base64(icon('icons/obj/tgui_components.dmi', HIEROPHANT_ANSIBLE)))
return "<img style='width:14px; height:14px' src='data:image/png;base64,[tgui_component_icons[id]]'/>"
//returns a component id from a component name
/proc/get_component_id(name)
switch(name)
if("Belligerent Eye")
return BELLIGERENT_EYE
if("Vanguard Cogwheel")
return VANGUARD_COGWHEEL
if("Geis Capacitor")
return GEIS_CAPACITOR
if("Replicant Alloy")
return REPLICANT_ALLOY
if("Hierophant Ansible")
return HIEROPHANT_ANSIBLE
else
return null
//returns a component spanclass from a component id
/proc/get_component_span(id)
switch(id)
@@ -129,35 +39,3 @@
return "#DAAA18"
else
return "#BE8700"
//returns a type for a floating component animation from a component id
/proc/get_component_animation_type(id)
switch(id)
if(BELLIGERENT_EYE)
return /obj/effect/temp_visual/ratvar/component
if(VANGUARD_COGWHEEL)
return /obj/effect/temp_visual/ratvar/component/cogwheel
if(GEIS_CAPACITOR)
return /obj/effect/temp_visual/ratvar/component/capacitor
if(REPLICANT_ALLOY)
return /obj/effect/temp_visual/ratvar/component/alloy
if(HIEROPHANT_ANSIBLE)
return /obj/effect/temp_visual/ratvar/component/ansible
else
return null
//returns a type for a component from a component id
/proc/get_component_type(id)
switch(id)
if(BELLIGERENT_EYE)
return /obj/item/clockwork/component/belligerent_eye
if(VANGUARD_COGWHEEL)
return /obj/item/clockwork/component/vanguard_cogwheel
if(GEIS_CAPACITOR)
return /obj/item/clockwork/component/geis_capacitor
if(REPLICANT_ALLOY)
return /obj/item/clockwork/component/replicant_alloy
if(HIEROPHANT_ANSIBLE)
return /obj/item/clockwork/component/hierophant_ansible
else
return null
@@ -9,7 +9,7 @@
return FALSE
/atom/proc/consume_visual(obj/item/clockwork/replica_fabricator/fabricator, power_amount)
if(fabricator.can_use_power(power_amount))
if(get_clockwork_power(power_amount))
var/obj/effect/temp_visual/ratvar/beam/itemconsume/B = new /obj/effect/temp_visual/ratvar/beam/itemconsume(get_turf(src))
B.pixel_x = pixel_x
B.pixel_y = pixel_y
@@ -240,7 +240,7 @@
extra_checks = CALLBACK(fabricator, /obj/item/clockwork/replica_fabricator.proc/fabricator_repair_checks, repair_values, src, user, TRUE)))
break
obj_integrity = Clamp(obj_integrity + repair_values["healing_for_cycle"], 0, max_integrity)
fabricator.modify_stored_power(-repair_values["power_required"])
adjust_clockwork_power(-repair_values["power_required"])
playsound(src, 'sound/machines/click.ogg', 50, 1)
if(fabricator)
@@ -249,28 +249,6 @@
user.visible_message("<span class='notice'>[user]'s [fabricator.name] stops covering [src] with glowing orange energy.</span>", \
"<span class='alloy'>You finish repairing [src]. It is now at <b>[obj_integrity]/[max_integrity]</b> integrity.</span>")
//Hitting a sigil of transmission will try to charge from it.
/obj/effect/clockwork/sigil/transmission/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
. = TRUE
var/list/charge_values = list()
if(!fabricator.sigil_charge_checks(charge_values, src, user))
return
user.visible_message("<span class='notice'>[user]'s [fabricator.name] starts draining glowing orange energy from [src]...</span>", \
"<span class='alloy'>You start recharging your [fabricator.name]...</span>")
fabricator.recharging = src
while(fabricator && user && src)
if(!do_after(user, 10, target = src, extra_checks = CALLBACK(fabricator, /obj/item/clockwork/replica_fabricator.proc/sigil_charge_checks, charge_values, src, user, TRUE)))
break
modify_charge(charge_values["power_gain"])
fabricator.modify_stored_power(charge_values["power_gain"])
playsound(src, 'sound/effects/light_flicker.ogg', charge_values["power_gain"] * 0.1, 1)
if(fabricator)
fabricator.recharging = null
if(user)
user.visible_message("<span class='notice'>[user]'s [fabricator.name] stops draining glowing orange energy from [src].</span>", \
"<span class='alloy'>You finish recharging your [fabricator.name]. It now contains <b>[DisplayPower(fabricator.get_power())]/[DisplayPower(fabricator.get_max_power())]</b> power.</span>")
//Fabricator mob heal proc, to avoid as much copypaste as possible.
/mob/living/proc/fabricator_heal(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator)
var/list/repair_values = list()
@@ -284,7 +262,7 @@
extra_checks = CALLBACK(fabricator, /obj/item/clockwork/replica_fabricator.proc/fabricator_repair_checks, repair_values, src, user, TRUE)))
break
fabricator_heal_tick(repair_values["healing_for_cycle"])
fabricator.modify_stored_power(-repair_values["power_required"])
adjust_clockwork_power(-repair_values["power_required"])
playsound(src, 'sound/machines/click.ogg', 50, 1)
if(fabricator)
@@ -26,6 +26,7 @@
/datum/action/innate/hierophant
name = "Hierophant Network"
desc = "Allows you to communicate with other Servants."
icon_icon = 'icons/mob/actions/actions_clockcult.dmi'
button_icon_state = "hierophant"
background_icon_state = "bg_clock"
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
@@ -43,6 +44,7 @@
var/input = stripped_input(usr, "Please enter a message to send to other servants.", "Hierophant Network", "")
if(!input || !IsAvailable())
return
if(ishuman(owner))
clockwork_say(owner, "[text2ratvar("Servants, hear my words: [input]")]", TRUE)
log_talk(owner,"CLOCK:[key_name(owner)] : [input]",LOGSAY)
titled_hierophant_message(owner, input, span_for_name, span_for_message, title)
@@ -0,0 +1,25 @@
//Helper procs for clockwork power, used by structures and items and that kind of jazz.
/proc/get_clockwork_power(amount) //If no amount is provided, returns the clockwork power; otherwise, returns if there's enough power for that amount.
return amount ? GLOB.clockwork_power >= amount : GLOB.clockwork_power
/proc/adjust_clockwork_power(amount) //Adjusts the global clockwork power by this amount (min 0.)
if(GLOB.ratvar_approaches)
amount *= 0.75 //The herald's beacon reduces power costs by 25% across the board!
GLOB.clockwork_power = GLOB.ratvar_awakens ? INFINITY : max(0, GLOB.clockwork_power + amount)
for(var/obj/effect/clockwork/sigil/transmission/T in GLOB.all_clockwork_objects)
T.update_icon()
var/power_overwhelming = GLOB.clockwork_power
if(power_overwhelming >= SCRIPT_UNLOCK_THRESHOLD && !GLOB.script_scripture_unlocked)
GLOB.script_scripture_unlocked = TRUE
hierophant_message("<span class='large_brass bold'>The Ark swells as a key power threshold is reached. Script scriptures are now available.</span>")
if(power_overwhelming >= APPLICATION_UNLOCK_THRESHOLD && !GLOB.application_scripture_unlocked)
GLOB.application_scripture_unlocked = TRUE
hierophant_message("<span class='large_brass bold'>The Ark surges as a key power threshold is reached. Application scriptures are now available.</span>")
return TRUE
/proc/can_access_clockwork_power(atom/movable/access_point, amount) //Returns true if the access point has access to clockwork power (and optionally, a number of watts for it)
if(amount && !get_clockwork_power(amount)) //No point in trying if we don't have the power anyway
return
var/list/possible_conduits = view(5, access_point)
return locate(/obj/effect/clockwork/sigil/transmission) in possible_conduits || GLOB.ratvar_awakens
@@ -1,39 +1,23 @@
//returns a list of scriptures and if they're unlocked or not
/proc/scripture_unlock_check()
var/servants = 0
var/unconverted_ai_exists = get_unconverted_ais()
for(var/mob/living/M in GLOB.living_mob_list)
if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M)))
servants++
. = list(SCRIPTURE_DRIVER = TRUE, SCRIPTURE_SCRIPT = FALSE, SCRIPTURE_APPLICATION = FALSE, SCRIPTURE_JUDGEMENT = FALSE)
. = list(SCRIPTURE_DRIVER = TRUE, SCRIPTURE_SCRIPT = FALSE, SCRIPTURE_APPLICATION = FALSE)
//Drivers: always unlocked
.[SCRIPTURE_SCRIPT] = (SSticker.scripture_states[SCRIPTURE_SCRIPT] || \
(servants >= SCRIPT_SERVANT_REQ && GLOB.clockwork_caches >= SCRIPT_CACHE_REQ))
//Script: SCRIPT_SERVANT_REQ or more non-brain servants and SCRIPT_CACHE_REQ or more clockwork caches
.[SCRIPTURE_APPLICATION] = (SSticker.scripture_states[SCRIPTURE_APPLICATION] || \
(servants >= APPLICATION_SERVANT_REQ && GLOB.clockwork_caches >= APPLICATION_CACHE_REQ && GLOB.clockwork_construction_value >= APPLICATION_CV_REQ))
.[SCRIPTURE_SCRIPT] = GLOB.script_scripture_unlocked
//Script: Convert a new servant using a sigil of submission.
.[SCRIPTURE_APPLICATION] = GLOB.application_scripture_unlocked
//Application: APPLICATION_SERVANT_REQ or more non-brain servants, APPLICATION_CACHE_REQ or more clockwork caches, and at least APPLICATION_CV_REQ CV
.[SCRIPTURE_JUDGEMENT] = (SSticker.scripture_states[SCRIPTURE_JUDGEMENT] || \
(servants >= JUDGEMENT_SERVANT_REQ && GLOB.clockwork_caches >= JUDGEMENT_CACHE_REQ && GLOB.clockwork_construction_value >= JUDGEMENT_CV_REQ && !unconverted_ai_exists))
//Judgement: JUDGEMENT_SERVANT_REQ or more non-brain servants, JUDGEMENT_CACHE_REQ or more clockwork caches, at least JUDGEMENT_CV_REQ CV, and there are no living, non-servant ais
//reports to servants when scripture is locked or unlocked
/proc/scripture_unlock_alert(list/previous_states)
. = scripture_unlock_check()
for(var/i in .)
if(.[i] != previous_states[i])
hierophant_message("<span class='large_brass'><i>Hierophant Network:</i> <b>[i] Scripture has been [.[i] ? "un":""]locked.</b></span>") //maybe admins fucked with scripture states?
update_slab_info()
/proc/get_unconverted_ais()
. = 0
for(var/ai in GLOB.ai_list)
var/mob/living/silicon/ai/AI = ai
if(AI.deployed_shell && is_servant_of_ratvar(AI.deployed_shell))
continue
if(is_servant_of_ratvar(AI) || !isturf(AI.loc) || !(AI.z in GLOB.station_z_levels) || AI.stat == DEAD)
continue
.++
for(var/mob/M in GLOB.player_list)
if(is_servant_of_ratvar(M) || isobserver(M))
M.playsound_local(M, 'sound/magic/clockwork/scripture_tier_up.ogg', 50, FALSE, pressure_affected = FALSE)
/proc/update_slab_info(obj/item/clockwork/slab/set_slab)
generate_all_scripture()
@@ -21,70 +21,58 @@
remove_ranged_ability()
return TRUE
//For the Geis scripture; binds a target to convert.
/obj/effect/proc_holder/slab/geis
ranged_mousepointer = 'icons/effects/geis_target.dmi'
//For the Hateful Manacles scripture; applies replicant handcuffs to the target.
/obj/effect/proc_holder/slab/hateful_manacles
/obj/effect/proc_holder/slab/geis/InterceptClickOn(mob/living/caller, params, atom/target)
/obj/effect/proc_holder/slab/hateful_manacles/InterceptClickOn(mob/living/caller, params, atom/target)
if(..())
return TRUE
var/turf/T = ranged_ability_user.loc
if(!isturf(T))
return TRUE
var/target_is_binding = istype(target, /obj/structure/destructible/clockwork/geis_binding)
if(iscarbon(target) && target.Adjacent(ranged_ability_user))
var/mob/living/carbon/L = target
if(is_servant_of_ratvar(L))
to_chat(ranged_ability_user, "<span class='neovgre'>\"They're a servant.\"</span>")
return TRUE
else if(L.stat)
to_chat(ranged_ability_user, "<span class='neovgre'>\"There is use in shackling the dead, but for examples.\"</span>")
return TRUE
else if(L.handcuffed)
to_chat(ranged_ability_user, "<span class='neovgre'>\"They are already helpless, no?\"</span>")
return TRUE
if((target_is_binding || isliving(target)) && ranged_ability_user.Adjacent(target))
if(target_is_binding)
var/obj/structure/destructible/clockwork/geis_binding/GB = target
GB.repair_and_interrupt()
for(var/m in GB.buckled_mobs)
if(m)
add_logs(ranged_ability_user, m, "rebound with Geis")
successful = TRUE
playsound(loc, 'sound/weapons/handcuffs.ogg', 30, TRUE)
ranged_ability_user.visible_message("<span class='danger'>[ranged_ability_user] begins forming manacles around [L]'s wrists!</span>", \
"<span class='neovgre_small'>You begin shaping replicant alloy into manacles around [L]'s wrists...</span>")
to_chat(L, "<span class='userdanger'>[ranged_ability_user] begins forming manacles around your wrists!</span>")
if(do_mob(ranged_ability_user, L, 30))
if(!L.handcuffed)
L.handcuffed = new/obj/item/restraints/handcuffs/clockwork(L)
L.update_handcuffed()
to_chat(ranged_ability_user, "<span class='neovgre_small'>You shackle [L].</span>")
add_logs(ranged_ability_user, L, "handcuffed")
else
var/mob/living/L = target
if(L.null_rod_check())
to_chat(ranged_ability_user, "<span class='sevtug'>\"A void weapon? Really, you expect me to be able to do anything?\"</span>")
return TRUE
if(is_servant_of_ratvar(L))
if(L != ranged_ability_user)
to_chat(ranged_ability_user, "<span class='sevtug'>\"[L.p_they(TRUE)] already serve[L.p_s()] Ratvar. [text2ratvar("Perhaps [ranged_ability_user.p_theyre()] into bondage?")]\"</span>")
return TRUE
if(L.stat == DEAD)
to_chat(ranged_ability_user, "<span class='sevtug'>\"[L.p_theyre(TRUE)] dead, idiot.\"</span>")
return TRUE
to_chat(ranged_ability_user, "<span class='warning'>You fail to shackle [L].</span>")
if(istype(L.buckled, /obj/structure/destructible/clockwork/geis_binding)) //if they're already bound, just stun them
var/obj/structure/destructible/clockwork/geis_binding/GB = L.buckled
GB.repair_and_interrupt()
add_logs(ranged_ability_user, L, "rebound with Geis")
successful = TRUE
else
clockwork_say(ranged_ability_user, text2ratvar("Be bound, heathen!"))
add_logs(ranged_ability_user, L, "bound with Geis")
playsound(target, 'sound/magic/blink.ogg', 50, TRUE, -4, frequency = 0.5)
if(slab.speed_multiplier >= 0.5) //excuse my debug...
ranged_ability_user.notransform = TRUE
addtimer(CALLBACK(src, .proc/reset_user_notransform, ranged_ability_user), 4) //stop us moving for a little bit so we don't break the binding immediately
if(L.buckled)
L.buckled.unbuckle_mob(target, TRUE)
var/obj/structure/destructible/clockwork/geis_binding/binding = new(get_turf(target))
binding.setDir(target.dir)
binding.buckle_mob(target, TRUE)
ranged_ability_user.start_pulling(binding)
ranged_ability_user.apply_status_effect(STATUS_EFFECT_GEISTRACKER, binding)
successful = TRUE
successful = TRUE
remove_ranged_ability()
else
..()
return TRUE
/obj/effect/proc_holder/slab/geis/proc/reset_user_notransform(mob/living/user)
if(user)
user.notransform = FALSE
/obj/item/restraints/handcuffs/clockwork
name = "replicant manacles"
desc = "Cold, heavy manacles made out of some strange black metal."
origin_tech = "materials=2;magnets=5"
flags_1 = DROPDEL_1
/obj/item/restraints/handcuffs/clockwork/dropped(mob/user)
user.visible_message("<span class='danger'>[user]'s [name] come apart at the seams!</span>", \
"<span class='userdanger'>Your [name] break apart as they're removed!</span>")
. = ..()
//For the Sentinel's Compromise scripture; heals a target servant.
/obj/effect/proc_holder/slab/compromise
@@ -140,12 +128,83 @@
playsound(targetturf, 'sound/magic/staff_healing.ogg', 50, 1)
if(has_holy_water)
L.reagents.del_reagent("holywater")
L.reagents.remove_reagent("holywater", 1000)
remove_ranged_ability()
return TRUE
//For the Kindle scripture; stuns and mutes a target non-servant.
/obj/effect/proc_holder/slab/kindle
ranged_mousepointer = 'icons/effects/volt_target.dmi'
/obj/effect/proc_holder/slab/kindle/InterceptClickOn(mob/living/caller, params, atom/target)
if(..())
return TRUE
var/turf/T = ranged_ability_user.loc
if(!isturf(T))
return TRUE
if(target in view(7, get_turf(ranged_ability_user)))
successful = TRUE
var/turf/U = get_turf(target)
to_chat(ranged_ability_user, "<span class='brass'>You release the light of Ratvar!</span>")
clockwork_say(ranged_ability_user, text2ratvar("Purge all untruths and honor Engine!"))
add_logs(ranged_ability_user, U, "fired at with Kindle")
playsound(ranged_ability_user, 'sound/magic/blink.ogg', 50, TRUE, frequency = 0.5)
var/obj/item/projectile/kindle/A = new(T)
A.original = target
A.starting = T
A.current = T
A.yo = U.y - T.y
A.xo = U.x - T.x
A.fire()
remove_ranged_ability()
return TRUE
/obj/item/projectile/kindle
name = "kindled flame"
icon_state = "pulse0"
nodamage = TRUE
damage = 0 //We're just here for the stunning!
damage_type = BURN
flag = "bomb"
range = 3
log_override = TRUE
/obj/item/projectile/kindle/Destroy()
visible_message("<span class='warning'>[src] flickers out!</span>")
. = ..()
/obj/item/projectile/kindle/on_hit(atom/target, blocked = FALSE)
if(isliving(target))
var/mob/living/L = target
if(is_servant_of_ratvar(L) || L.stat || L.has_status_effect(STATUS_EFFECT_KINDLE))
return
var/obj/O = L.null_rod_check()
playsound(L, 'sound/magic/fireball.ogg', 50, TRUE, frequency = 1.25)
if(O)
L.visible_message("<span class='warning'>[L]'s eyes flare with dim light as they stumble!</span>", \
"<span class='userdanger'>Your [O] glows white-hot against you as it absorbs some sort of power!</span>")
L.adjustFireLoss(5)
L.Stun(40)
playsound(L, 'sound/weapons/sear.ogg', 50, TRUE)
else
L.visible_message("<span class='warning'>[L]'s eyes blaze with brilliant light!</span>", \
"<span class='userdanger'>Your vision suddenly screams with white-hot light!</span>")
L.Knockdown(15)
L.apply_status_effect(STATUS_EFFECT_KINDLE)
L.flash_act(1, 1)
if(iscultist(L))
L.adjustFireLoss(15)
..()
//For the cyborg Linked Vanguard scripture, grants you and a nearby ally Vanguard
/obj/effect/proc_holder/slab/vanguard
ranged_mousepointer = 'icons/effects/vanguard_target.dmi'
@@ -9,6 +9,20 @@
var/list/servant_of_ratvar_messages = list("ayy" = FALSE, "lmao" = TRUE) //Fluff, shown to servants of Ratvar on a low chance, if associated value is TRUE, will automatically apply ratvarian
var/message_span = "heavy_brass"
/obj/item/clockwork/component/examine(mob/user)
. = ..()
if(is_servant_of_ratvar(user) || isobserver(user))
to_chat(user, "<span class='[get_component_span(component_id)]'>You can activate this in your hand to break it down for power.</span>")
/obj/item/clockwork/component/attack_self(mob/living/user)
if(is_servant_of_ratvar(user))
user.visible_message("<span class='notice'>[user] crushes [src] in their hand!</span>", \
"<span class='alloy'>You crush [src], capturing its escaping energy for use as power.</span>")
playsound(user, 'sound/effects/pop_expl.ogg', 50, TRUE)
adjust_clockwork_power(POWER_WALL_TOTAL)
user.drop_item()
qdel(src)
/obj/item/clockwork/component/pickup(mob/living/user)
..()
if(iscultist(user) || (user.mind && user.mind.isholy))
@@ -22,11 +36,6 @@
var/pickedmessage = pick(servant_of_ratvar_messages)
to_chat(user, "<span class='[message_span]'>[servant_of_ratvar_messages[pickedmessage] ? "[text2ratvar(pickedmessage)]" : pickedmessage]</span>")
/obj/item/clockwork/component/examine(mob/user)
..()
if(is_servant_of_ratvar(user))
to_chat(user, "<span class='[message_span]'>You should put this in a slab or cache immediately.</span>")
/obj/item/clockwork/component/belligerent_eye
name = "belligerent eye"
desc = "A brass construct with a rotating red center. It's as though it's looking for something to hurt."
@@ -39,7 +48,7 @@
/obj/item/clockwork/component/belligerent_eye/blind_eye
name = "blind eye"
desc = "A heavy brass eye, its red iris fallen dark."
clockwork_desc = "A smashed ocular warden covered in dents. <b>Serviceable as a substitute for a belligerent eye.</b>"
clockwork_desc = "A smashed ocular warden covered in dents."
icon_state = "blind_eye"
cultist_message = "The eye flickers at you with intense hate before falling dark."
servant_of_ratvar_messages = list("The eye flickers before falling dark." = FALSE, "You feel watched." = FALSE, "\"...\"" = FALSE)
@@ -48,7 +57,7 @@
/obj/item/clockwork/component/belligerent_eye/lens_gem
name = "lens gem"
desc = "A tiny pinkish gem. It catches the light oddly, almost glowing."
clockwork_desc = "The gem from an interdiction lens. <b>Serviceable as a substitute for a belligerent eye.</b>"
clockwork_desc = "The gem from an interdiction lens."
icon_state = "lens_gem"
cultist_message = "The gem turns black and cold for a moment before its normal glow returns."
servant_of_ratvar_messages = list("\"Disgusting failure.\"" = TRUE, "You feel scrutinized." = FALSE, "\"Weaklings.\"" = TRUE, "\"Pathetic defenses.\"" = TRUE)
@@ -69,7 +78,7 @@
/obj/item/clockwork/component/vanguard_cogwheel/onyx_prism
name = "onyx prism"
desc = "An onyx prism with a small aperture. It's very heavy."
clockwork_desc = "A broken prism from a prolonging prism. <b>Serviceable as a substitute for a vanguard cogwheel.</b>"
clockwork_desc = "A broken prism from a prolonging prism."
icon_state = "onyx_prism"
cultist_message = "The prism grows painfully hot in your hands."
servant_of_ratvar_messages = list("The prism isn't getting any lighter." = FALSE, "\"So... you haven't failed yet. Have hope, child.\"" = TRUE, \
@@ -98,7 +107,7 @@
/obj/item/clockwork/component/geis_capacitor/antennae
name = "mania motor antennae"
desc = "A pair of dented and bent antennae. They constantly emit a static hiss."
clockwork_desc = "The antennae from a mania motor. <b>Serviceable as a substitute for a geis capacitor.</b>"
clockwork_desc = "The antennae from a mania motor."
icon_state = "mania_motor_antennae"
cultist_message = "Your head is filled with a burst of static."
servant_of_ratvar_messages = list("\"Who broke this.\"" = TRUE, "\"Did you break these off YOURSELF?\"" = TRUE, "\"Why did we give this to such simpletons, anyway?\"" = TRUE, \
@@ -117,16 +126,16 @@
/obj/item/clockwork/component/replicant_alloy/smashed_anima_fragment
name = "smashed anima fragment"
desc = "Shattered chunks of metal. Damaged beyond repair and completely unusable."
clockwork_desc = "The sad remains of an anima fragment. <b>Serviceable as a substitute for replicant alloy.</b>"
clockwork_desc = "The sad remains of an anima fragment."
icon_state = "smashed_anime_fragment"
cultist_message = "The shards vibrate in your hands for a moment."
servant_of_ratvar_messages = list("\"...still fight...\"" = FALSE, "\"...where am I...?\"" = FALSE, "\"...put me... slab...\"" = FALSE)
servant_of_ratvar_messages = list("\"...still fight...\"" = FALSE, "\"...where am I...?\"" = FALSE, "\"...bring me... back...\"" = FALSE)
w_class = WEIGHT_CLASS_NORMAL
/obj/item/clockwork/component/replicant_alloy/replication_plate
name = "replication plate"
desc = "A flat, heavy disc of metal with a triangular formation on its surface."
clockwork_desc = "The replication plate from a tinkerer's daemon. <b>Serviceable as a substitute for replicant alloy.</b>"
clockwork_desc = "The replication plate from a tinkerer's daemon."
icon_state = "replication_plate"
cultist_message = "The plate shudders in your hands, as though trying to get away."
servant_of_ratvar_messages = list("\"Put this in a slab and get back to work.\"" = FALSE, "\"Worse servants than you have held these.\"" = TRUE, \
@@ -146,7 +155,7 @@
/obj/item/clockwork/component/hierophant_ansible/obelisk
name = "obelisk prism"
desc = "A prism that occasionally glows brightly. It seems not-quite there."
clockwork_desc = "The prism from a clockwork obelisk. <b>Serviceable as a substitute for a hierophant ansible.</b>"
clockwork_desc = "The prism from a clockwork obelisk."
cultist_message = "The prism flickers wildly in your hands before resuming its normal glow."
servant_of_ratvar_messages = list("You hear the distinctive sound of the Hierophant Network for a moment." = FALSE, "\"Hieroph'ant Br'o'adcas't fail'ure.\"" = TRUE, \
"The obelisk flickers wildly, as if trying to open a gateway." = FALSE, "\"Spa'tial Ga'tewa'y fai'lure.\"" = TRUE)
@@ -182,6 +191,13 @@
desc = "A broken shard of some oddly malleable metal. It occasionally moves and seems to glow."
clockwork_desc = "A broken shard of replicant alloy."
/obj/item/clockwork/alloy_shards/clockgolem_remains
name = "clockwork golem scrap"
desc = "A pile of scrap metal. It seems damaged beyond repair."
clockwork_desc = "The sad remains of a clockwork golem. It's broken beyond repair."
icon_state = "clockgolem_dead"
sprite_shift = 0
/obj/item/clockwork/alloy_shards/large
w_class = WEIGHT_CLASS_TINY
randomsinglesprite = TRUE

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