Merge branch 'master' into upstream-merge-29647
This commit is contained in:
@@ -76,7 +76,7 @@
|
||||
#define ACCESS_CENT_STORAGE 106//Generic storage areas.
|
||||
#define ACCESS_CENT_TELEPORTER 107//Teleporter.
|
||||
#define ACCESS_CENT_CAPTAIN 109//Captain's office/ID comp/AI.
|
||||
#define ACCESS_CENT_BAR 110 // The non-existent Centcom Bar
|
||||
#define ACCESS_CENT_BAR 110 // The non-existent CentCom Bar
|
||||
|
||||
//The Syndicate
|
||||
#define ACCESS_SYNDICATE 150//General Syndicate Access
|
||||
@@ -93,4 +93,9 @@
|
||||
#define ACCESS_AWAY_GENERIC1 205//Away generic access
|
||||
#define ACCESS_AWAY_GENERIC2 206
|
||||
#define ACCESS_AWAY_GENERIC3 207
|
||||
#define ACCESS_AWAY_GENERIC4 208
|
||||
#define ACCESS_AWAY_GENERIC4 208
|
||||
|
||||
//Special, for anything that's basically internal
|
||||
#define ACCESS_BLOODCULT 250
|
||||
#define ACCESS_CLOCKCULT 251
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
#define ADMIN_SM(user) "(<a href='?_src_=holder;subtlemessage=\ref[user]'>SM</a>)"
|
||||
#define ADMIN_TP(user) "(<a href='?_src_=holder;traitor=\ref[user]'>TP</a>)"
|
||||
#define ADMIN_KICK(user) "(<a href='?_src_=holder;boot2=\ref[user]'>KICK</a>)"
|
||||
#define ADMIN_CENTCOM_REPLY(user) "(<a href='?_src_=holder;CentcommReply=\ref[user]'>RPLY</a>)"
|
||||
#define ADMIN_CENTCOM_REPLY(user) "(<a href='?_src_=holder;CentComReply=\ref[user]'>RPLY</a>)"
|
||||
#define ADMIN_SYNDICATE_REPLY(user) "(<a href='?_src_=holder;SyndicateReply=\ref[user]'>RPLY</a>)"
|
||||
#define ADMIN_SC(user) "(<a href='?_src_=holder;adminspawncookie=\ref[user]'>SC</a>)"
|
||||
#define ADMIN_SMITE(user) "(<a href='?_src_=holder;adminsmite=\ref[user]'>SMITE</a>)"
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
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_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
|
||||
|
||||
+11
-10
@@ -1,15 +1,16 @@
|
||||
//Investigate logging defines
|
||||
#define INVESTIGATE_ATMOS "atmos"
|
||||
#define INVESTIGATE_BOTANY "botany"
|
||||
#define INVESTIGATE_CARGO "cargo"
|
||||
#define INVESTIGATE_EXPERIMENTOR "experimentor"
|
||||
#define INVESTIGATE_GRAVITY "gravity"
|
||||
#define INVESTIGATE_RECORDS "records"
|
||||
#define INVESTIGATE_SINGULO "singulo"
|
||||
#define INVESTIGATE_SUPERMATTER "supermatter"
|
||||
#define INVESTIGATE_TELESCI "telesci"
|
||||
#define INVESTIGATE_WIRES "wires"
|
||||
#define INVESTIGATE_ATMOS "atmos"
|
||||
#define INVESTIGATE_BOTANY "botany"
|
||||
#define INVESTIGATE_CARGO "cargo"
|
||||
#define INVESTIGATE_EXPERIMENTOR "experimentor"
|
||||
#define INVESTIGATE_GRAVITY "gravity"
|
||||
#define INVESTIGATE_RECORDS "records"
|
||||
#define INVESTIGATE_SINGULO "singulo"
|
||||
#define INVESTIGATE_SUPERMATTER "supermatter"
|
||||
#define INVESTIGATE_TELESCI "telesci"
|
||||
#define INVESTIGATE_WIRES "wires"
|
||||
#define INVESTIGATE_PORTAL "portals"
|
||||
#define INVESTIGATE_HALLUCINATIONS "hallucinations"
|
||||
|
||||
//Individual logging defines
|
||||
#define INDIVIDUAL_ATTACK_LOG "Attack log"
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
diff a/code/__DEFINES/logging.dm b/code/__DEFINES/logging.dm (rejected hunks)
|
||||
@@ -9,6 +9,7 @@
|
||||
#define INVESTIGATE_SUPERMATTER "supermatter"
|
||||
#define INVESTIGATE_TELESCI "telesci"
|
||||
#define INVESTIGATE_WIRES "wires"
|
||||
+#define INVESTIGATE_HALLUCINATIONS "hallucinations"
|
||||
|
||||
//Individual logging defines
|
||||
#define INDIVIDUAL_ATTACK_LOG "Attack log"
|
||||
@@ -5,7 +5,7 @@ Names of z-level do not matter, but order does greatly, for instances such as ch
|
||||
|
||||
current as of 2016/6/2
|
||||
z1 = station
|
||||
z2 = centcomm
|
||||
z2 = centcom
|
||||
z5 = mining
|
||||
Everything else = randomized space
|
||||
Last space-z level = empty
|
||||
@@ -16,7 +16,7 @@ Last space-z level = empty
|
||||
#define UNAFFECTED 0
|
||||
|
||||
#define MAIN_STATION "Main Station"
|
||||
#define CENTCOMM "CentComm"
|
||||
#define CENTCOM "CentCom"
|
||||
#define EMPTY_AREA_1 "Empty Area 1"
|
||||
#define EMPTY_AREA_2 "Empty Area 2"
|
||||
#define MINING "Mining Asteroid"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//You can use these defines to get the typepath of the currently running proc/verb (yes procs + verbs are objects)
|
||||
/* eg:
|
||||
/mob/living/carbon/human/death()
|
||||
world << THIS_PROC_TYPE_STR //You can only output the string versions
|
||||
to_chat(world, THIS_PROC_TYPE_STR) //You can only output the string versions
|
||||
Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a string with () (eg: the _WITH_ARGS defines) to make it look nicer)
|
||||
*/
|
||||
#define THIS_PROC_TYPE .....
|
||||
@@ -46,8 +46,8 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
|
||||
//Human Overlays Indexes/////////
|
||||
//citadel code
|
||||
#define MUTATIONS_LAYER 30 //mutations. Tk headglows, cold resistance glow, etc
|
||||
#define BODY_BEHIND_LAYER 29 //certain mutantrace features (tail when looking south) that must appear behind the body parts
|
||||
#define GENITALS_BEHIND_LAYER 28
|
||||
#define GENITALS_BEHIND_LAYER 29 //Some genitalia needs to be behind everything, such as with taurs (Taurs use body_behind_layer
|
||||
#define BODY_BEHIND_LAYER 28 //certain mutantrace features (tail when looking south) that must appear behind the body parts
|
||||
#define BODYPARTS_LAYER 27 //Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag
|
||||
#define BODY_ADJ_LAYER 26 //certain mutantrace features (snout, body markings) that must appear above the body parts
|
||||
#define GENITALS_ADJ_LAYER 25
|
||||
@@ -350,6 +350,7 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
|
||||
|
||||
//debug printing macros
|
||||
#define debug_world(msg) if (GLOB.Debug2) to_chat(world, "DEBUG: [msg]")
|
||||
#define debug_usr(msg) if (GLOB.Debug2&&usr) to_chat(usr, "DEBUG: [msg]")
|
||||
#define debug_admins(msg) if (GLOB.Debug2) to_chat(GLOB.admins, "DEBUG: [msg]")
|
||||
#define debug_world_log(msg) if (GLOB.Debug2) log_world("DEBUG: [msg]")
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
#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_PR_TEST_JSON "..\\..\\prtestjob.json"
|
||||
@@ -17,7 +20,7 @@
|
||||
#define SERVICE_CMD_NAME_CHECK "namecheck"
|
||||
#define SERVICE_CMD_ADMIN_WHO "adminwho"
|
||||
|
||||
//#define SERVICE_CMD_PARAM_KEY //defined in __compile_options.dm
|
||||
#define SERVICE_CMD_PARAM_KEY "serviceCommsKey"
|
||||
#define SERVICE_CMD_PARAM_COMMAND "command"
|
||||
#define SERVICE_CMD_PARAM_MESSAGE "message"
|
||||
#define SERVICE_CMD_PARAM_TARGET "target"
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#define SHUTTLE_ALREADY_DOCKED "we_are_already_docked"
|
||||
#define SHUTTLE_SOMEONE_ELSE_DOCKED "someone_else_docked"
|
||||
|
||||
//Launching Shuttles to Centcomm
|
||||
//Launching Shuttles to CentCom
|
||||
#define NOLAUNCH -1
|
||||
#define UNLAUNCHED 0
|
||||
#define ENDGAME_LAUNCHED 1
|
||||
|
||||
@@ -91,16 +91,23 @@
|
||||
//returns a new list with only atoms that are in typecache L
|
||||
/proc/typecache_filter_list(list/atoms, list/typecache)
|
||||
. = list()
|
||||
for (var/thing in atoms)
|
||||
for(var/thing in atoms)
|
||||
var/atom/A = thing
|
||||
if (typecache[A.type])
|
||||
. += A
|
||||
|
||||
/proc/typecache_filter_list_reverse(list/atoms, list/typecache)
|
||||
. = list()
|
||||
for (var/thing in atoms)
|
||||
for(var/thing in atoms)
|
||||
var/atom/A = thing
|
||||
if (!typecache[A.type])
|
||||
if(!typecache[A.type])
|
||||
. += A
|
||||
|
||||
/proc/typecache_filter_multi_list_exclusion(list/atoms, list/typecache_include, list/typecache_exclude)
|
||||
. = list()
|
||||
for(var/thing in atoms)
|
||||
var/atom/A = thing
|
||||
if(typecache_include[A.type] && !typecache_exclude[A.type])
|
||||
. += A
|
||||
|
||||
//Like typesof() or subtypesof(), but returns a typecache instead of a list
|
||||
@@ -177,7 +184,11 @@
|
||||
result = first ^ second
|
||||
return result
|
||||
|
||||
//Pretends to pick an element based on its weight but really just seems to pick a random element.
|
||||
//Picks a random element from a list based on a weighting system:
|
||||
//1. Adds up the total of weights for each element
|
||||
//2. Gets a number between 1 and that total
|
||||
//3. For each element in the list, subtracts its weighting from that number
|
||||
//4. If that makes the number 0 or less, return that element.
|
||||
/proc/pickweight(list/L)
|
||||
var/total = 0
|
||||
var/item
|
||||
@@ -309,7 +320,7 @@
|
||||
return r
|
||||
|
||||
// Returns the key based on the index
|
||||
#define KEYBYINDEX(L, index) (((index <= L:len) && (index > 0)) ? L[index] : null)
|
||||
#define KEYBYINDEX(L, index) (((index <= length(L)) && (index > 0)) ? L[index] : null)
|
||||
|
||||
/proc/count_by_type(list/L, type)
|
||||
var/i = 0
|
||||
@@ -457,7 +468,7 @@
|
||||
. |= key_list[key]
|
||||
|
||||
//Picks from the list, with some safeties, and returns the "default" arg if it fails
|
||||
#define DEFAULTPICK(L, default) ((islist(L) && L:len) ? pick(L) : default)
|
||||
#define DEFAULTPICK(L, default) ((islist(L) && length(L)) ? pick(L) : default)
|
||||
#define LAZYINITLIST(L) if (!L) L = list()
|
||||
#define UNSETEMPTY(L) if (L && !L.len) L = null
|
||||
#define LAZYREMOVE(L, I) if(L) { L -= I; if(!L.len) { L = null; } }
|
||||
|
||||
+25
-18
@@ -1,3 +1,10 @@
|
||||
//wrapper macros for easier grepping
|
||||
#define DIRECT_OUTPUT(A, B) A << B
|
||||
#define SEND_IMAGE(target, image) DIRECT_OUTPUT(target, image)
|
||||
#define SEND_SOUND(target, sound) DIRECT_OUTPUT(target, sound)
|
||||
#define SEND_TEXT(target, text) DIRECT_OUTPUT(target, text)
|
||||
#define WRITE_FILE(file, text) DIRECT_OUTPUT(file, text)
|
||||
|
||||
//print a warning message to world.log
|
||||
#define WARNING(MSG) warning("[MSG] in [__FILE__] at line [__LINE__] src: [src] usr: [usr].")
|
||||
/proc/warning(msg)
|
||||
@@ -20,13 +27,13 @@
|
||||
/proc/log_admin(text)
|
||||
GLOB.admin_log.Add(text)
|
||||
if (config.log_admin)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]ADMIN: [text]"
|
||||
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)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]ADMINPRIVATE: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]ADMINPRIVATE: [text]")
|
||||
|
||||
/proc/log_adminsay(text)
|
||||
if (config.log_adminchat)
|
||||
@@ -38,65 +45,65 @@
|
||||
|
||||
/proc/log_game(text)
|
||||
if (config.log_game)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]GAME: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]GAME: [text]")
|
||||
|
||||
/proc/log_vote(text)
|
||||
if (config.log_vote)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]VOTE: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]VOTE: [text]")
|
||||
|
||||
/proc/log_access(text)
|
||||
if (config.log_access)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]ACCESS: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]ACCESS: [text]")
|
||||
|
||||
/proc/log_say(text)
|
||||
if (config.log_say)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]SAY: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]SAY: [text]")
|
||||
|
||||
/proc/log_prayer(text)
|
||||
if (config.log_prayer)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]PRAY: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]PRAY: [text]")
|
||||
|
||||
/proc/log_law(text)
|
||||
if (config.log_law)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]LAW: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]LAW: [text]")
|
||||
|
||||
/proc/log_ooc(text)
|
||||
if (config.log_ooc)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]OOC: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]OOC: [text]")
|
||||
|
||||
/proc/log_whisper(text)
|
||||
if (config.log_whisper)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]WHISPER: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]WHISPER: [text]")
|
||||
|
||||
/proc/log_emote(text)
|
||||
if (config.log_emote)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]EMOTE: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]EMOTE: [text]")
|
||||
|
||||
/proc/log_attack(text)
|
||||
if (config.log_attack)
|
||||
GLOB.world_attack_log << "\[[time_stamp()]]ATTACK: [text]"
|
||||
WRITE_FILE(GLOB.world_attack_log, "\[[time_stamp()]]ATTACK: [text]")
|
||||
|
||||
/proc/log_pda(text)
|
||||
if (config.log_pda)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]PDA: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]PDA: [text]")
|
||||
|
||||
/proc/log_comment(text)
|
||||
if (config.log_pda)
|
||||
//reusing the PDA option because I really don't think news comments are worth a config option
|
||||
GLOB.world_game_log << "\[[time_stamp()]]COMMENT: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]COMMENT: [text]")
|
||||
|
||||
/proc/log_chat(text)
|
||||
if (config.log_pda)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]CHAT: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]CHAT: [text]")
|
||||
|
||||
/proc/log_sql(text)
|
||||
if(config.sql_enabled)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]SQL: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]SQL: [text]")
|
||||
|
||||
//This replaces world.log so it displays both in DD and the file
|
||||
/proc/log_world(text)
|
||||
GLOB.world_runtime_log << text
|
||||
world.log << text
|
||||
WRITE_FILE(GLOB.world_runtime_log, text)
|
||||
SEND_TEXT(world.log, text)
|
||||
|
||||
// Helper procs for building detailed log lines
|
||||
|
||||
|
||||
@@ -418,7 +418,7 @@
|
||||
/proc/showCandidatePollWindow(mob/M, poll_time, Question, list/candidates, ignore_category, time_passed, flashwindow = TRUE)
|
||||
set waitfor = 0
|
||||
|
||||
M << 'sound/misc/notice2.ogg' //Alerting them to their consideration
|
||||
SEND_SOUND(M, 'sound/misc/notice2.ogg') //Alerting them to their consideration
|
||||
if(flashwindow)
|
||||
window_flash(M.client)
|
||||
switch(ignore_category ? askuser(M,Question,"Please answer in [poll_time/10] seconds!","Yes","No","Never for this round", StealFocus=0, Timeout=poll_time) : askuser(M,Question,"Please answer in [poll_time/10] seconds!","Yes","No", StealFocus=0, Timeout=poll_time))
|
||||
@@ -426,7 +426,7 @@
|
||||
to_chat(M, "<span class='notice'>Choice registered: Yes.</span>")
|
||||
if(time_passed + poll_time <= world.time)
|
||||
to_chat(M, "<span class='danger'>Sorry, you answered too late to be considered!</span>")
|
||||
M << 'sound/machines/buzz-sigh.ogg'
|
||||
SEND_SOUND(M, 'sound/machines/buzz-sigh.ogg')
|
||||
candidates -= M
|
||||
else
|
||||
candidates += M
|
||||
|
||||
@@ -48,6 +48,11 @@
|
||||
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.
|
||||
|
||||
+138
-33
@@ -167,7 +167,7 @@ mob
|
||||
|
||||
Output_Icon()
|
||||
set name = "2. Output Icon"
|
||||
to_chat(src, "Icon is: [bicon(getFlatIcon(src))]")
|
||||
to_chat(src, "Icon is: [icon2base64html(getFlatIcon(src))]")
|
||||
|
||||
Label_Icon()
|
||||
set name = "3. Label Icon"
|
||||
@@ -712,7 +712,8 @@ The _flatIcons list is a cache for generated icon files.
|
||||
if(!current)
|
||||
curIndex++ //Try the next layer
|
||||
continue
|
||||
currentLayer = current:layer
|
||||
var/image/I = current
|
||||
currentLayer = I.layer
|
||||
if(currentLayer<0) // Special case for FLY_LAYER
|
||||
if(currentLayer <= -1000) return flat
|
||||
if(pSet == 0) // Underlay
|
||||
@@ -747,22 +748,22 @@ The _flatIcons list is a cache for generated icon files.
|
||||
// Dimensions of overlay being added
|
||||
var/{addX1;addX2;addY1;addY2}
|
||||
|
||||
for(var/I in layers)
|
||||
|
||||
if(I:alpha == 0)
|
||||
for(var/V in layers)
|
||||
var/image/I = V
|
||||
if(I.alpha == 0)
|
||||
continue
|
||||
|
||||
if(I == copy) // 'I' is an /image based on the object being flattened.
|
||||
curblend = BLEND_OVERLAY
|
||||
add = icon(I:icon, I:icon_state, I:dir)
|
||||
add = icon(I.icon, I.icon_state, I.dir)
|
||||
else // 'I' is an appearance object.
|
||||
add = getFlatIcon(new/image(I), curdir, curicon, curstate, curblend)
|
||||
|
||||
// Find the new dimensions of the flat icon to fit the added overlay
|
||||
addX1 = min(flatX1, I:pixel_x+1)
|
||||
addX2 = max(flatX2, I:pixel_x+add.Width())
|
||||
addY1 = min(flatY1, I:pixel_y+1)
|
||||
addY2 = max(flatY2, I:pixel_y+add.Height())
|
||||
addX1 = min(flatX1, I.pixel_x+1)
|
||||
addX2 = max(flatX2, I.pixel_x+add.Width())
|
||||
addY1 = min(flatY1, I.pixel_y+1)
|
||||
addY2 = max(flatY2, I.pixel_y+add.Height())
|
||||
|
||||
if(addX1!=flatX1 || addX2!=flatX2 || addY1!=flatY1 || addY2!=flatY2)
|
||||
// Resize the flattened icon so the new icon fits
|
||||
@@ -771,7 +772,7 @@ The _flatIcons list is a cache for generated icon files.
|
||||
flatY1=addY1;flatY2=addY2
|
||||
|
||||
// Blend the overlay into the flattened icon
|
||||
flat.Blend(add, blendMode2iconMode(curblend), I:pixel_x + 2 - flatX1, I:pixel_y + 2 - flatY1)
|
||||
flat.Blend(add, blendMode2iconMode(curblend), I.pixel_x + 2 - flatX1, I.pixel_y + 2 - flatY1)
|
||||
|
||||
if(A.color)
|
||||
flat.Blend(A.color, ICON_MULTIPLY)
|
||||
@@ -782,10 +783,11 @@ The _flatIcons list is a cache for generated icon files.
|
||||
|
||||
/proc/getIconMask(atom/A)//By yours truly. Creates a dynamic mask for a mob/whatever. /N
|
||||
var/icon/alpha_mask = new(A.icon,A.icon_state)//So we want the default icon and icon state of A.
|
||||
for(var/I in A.overlays)//For every image in overlays. var/image/I will not work, don't try it.
|
||||
if(I:layer>A.layer)
|
||||
for(var/V in A.overlays)//For every image in overlays. var/image/I will not work, don't try it.
|
||||
var/image/I = V
|
||||
if(I.layer>A.layer)
|
||||
continue//If layer is greater than what we need, skip it.
|
||||
var/icon/image_overlay = new(I:icon,I:icon_state)//Blend only works with icon objects.
|
||||
var/icon/image_overlay = new(I.icon,I.icon_state)//Blend only works with icon objects.
|
||||
//Also, icons cannot directly set icon_state. Slower than changing variables but whatever.
|
||||
alpha_mask.Blend(image_overlay,ICON_OR)//OR so they are lumped together in a nice overlay.
|
||||
return alpha_mask//And now return the mask.
|
||||
@@ -968,32 +970,135 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
|
||||
/image/proc/setDir(newdir)
|
||||
dir = newdir
|
||||
|
||||
/atom/proc/freeze_icon_index()
|
||||
return "\ref[initial(icon)]-[initial(icon_state)]"
|
||||
#define FROZEN_RED_COLOR "#2E5E69"
|
||||
#define FROZEN_GREEN_COLOR "#60A2A8"
|
||||
#define FROZEN_BLUE_COLOR "#A1AFB1"
|
||||
|
||||
/obj/proc/make_frozen_visual()
|
||||
// Used to make the frozen item visuals for Freon.
|
||||
var/static/list/freeze_item_icons = list()
|
||||
if(resistance_flags & FREEZE_PROOF)
|
||||
return
|
||||
if(!HAS_SECONDARY_FLAG(src, FROZEN) && (initial(icon) && initial(icon_state)))
|
||||
var/index = freeze_icon_index()
|
||||
var/icon/IC
|
||||
var/icon/P = freeze_item_icons[index]
|
||||
if(!P)
|
||||
P = new /icon
|
||||
for(var/iconstate in icon_states(icon))
|
||||
var/icon/O = new('icons/effects/freeze.dmi', "ice_cube")
|
||||
IC = new(icon, iconstate)
|
||||
O.Blend(IC, ICON_ADD)
|
||||
P.Insert(O, iconstate)
|
||||
freeze_item_icons[index] = P
|
||||
icon = P
|
||||
if(!HAS_SECONDARY_FLAG(src, FROZEN))
|
||||
name = "frozen [name]"
|
||||
add_atom_colour(list(FROZEN_RED_COLOR, FROZEN_GREEN_COLOR, FROZEN_BLUE_COLOR, rgb(0,0,0)), TEMPORARY_COLOUR_PRIORITY)
|
||||
alpha -= 25
|
||||
SET_SECONDARY_FLAG(src, FROZEN)
|
||||
|
||||
//Assumes already frozed
|
||||
/obj/proc/make_unfrozen()
|
||||
icon = initial(icon)
|
||||
name = replacetext(name, "frozen ", "")
|
||||
CLEAR_SECONDARY_FLAG(src, FROZEN)
|
||||
if(HAS_SECONDARY_FLAG(src, FROZEN))
|
||||
name = replacetext(name, "frozen ", "")
|
||||
remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, list(FROZEN_RED_COLOR, FROZEN_GREEN_COLOR, FROZEN_BLUE_COLOR, rgb(0,0,0)))
|
||||
alpha += 25
|
||||
CLEAR_SECONDARY_FLAG(src, FROZEN)
|
||||
|
||||
#undef FROZEN_RED_COLOR
|
||||
#undef FROZEN_GREEN_COLOR
|
||||
#undef FROZEN_BLUE_COLOR
|
||||
|
||||
|
||||
//Converts an icon to base64. Operates by putting the icon in the iconCache savefile,
|
||||
// exporting it as text, and then parsing the base64 from that.
|
||||
// (This relies on byond automatically storing icons in savefiles as base64)
|
||||
/proc/icon2base64(icon/icon, iconKey = "misc")
|
||||
if (!isicon(icon))
|
||||
return FALSE
|
||||
WRITE_FILE(GLOB.iconCache[iconKey], icon)
|
||||
var/iconData = GLOB.iconCache.ExportText(iconKey)
|
||||
var/list/partial = splittext(iconData, "{")
|
||||
return replacetext(copytext(partial[2], 3, -5), "\n", "")
|
||||
|
||||
/proc/icon2html(thing, target, icon_state, dir, frame = 1, moving = FALSE)
|
||||
if (!thing)
|
||||
return
|
||||
|
||||
var/key
|
||||
var/icon/I = thing
|
||||
if (!target)
|
||||
return
|
||||
if (target == world)
|
||||
target = GLOB.clients
|
||||
|
||||
var/list/targets
|
||||
if (!islist(target))
|
||||
targets = list(target)
|
||||
else
|
||||
targets = target
|
||||
if (!targets.len)
|
||||
return
|
||||
if (!isicon(I))
|
||||
if (isfile(thing)) //special snowflake
|
||||
var/name = sanitize_filename("[generate_asset_name(thing)].png")
|
||||
register_asset(name, thing)
|
||||
for (var/thing2 in targets)
|
||||
send_asset(thing2, key, FALSE)
|
||||
return "<img class='icon icon-misc' src=\"[url_encode(name)]\">"
|
||||
var/atom/A = thing
|
||||
if (isnull(dir))
|
||||
dir = A.dir
|
||||
if (isnull(icon_state))
|
||||
icon_state = A.icon_state
|
||||
I = A.icon
|
||||
if (ishuman(thing)) // Shitty workaround for a BYOND issue.
|
||||
var/icon/temp = I
|
||||
I = icon()
|
||||
I.Insert(temp, dir = SOUTH)
|
||||
dir = SOUTH
|
||||
else
|
||||
if (isnull(dir))
|
||||
dir = SOUTH
|
||||
if (isnull(icon_state))
|
||||
icon_state = ""
|
||||
|
||||
I = icon(I, icon_state, dir, frame, moving)
|
||||
|
||||
key = "[generate_asset_name(I)].png"
|
||||
register_asset(key, I)
|
||||
for (var/thing2 in targets)
|
||||
send_asset(thing2, key, FALSE)
|
||||
|
||||
return "<img class='icon icon-[icon_state]' src=\"[url_encode(key)]\">"
|
||||
|
||||
/proc/icon2base64html(thing)
|
||||
if (!thing)
|
||||
return
|
||||
var/static/list/bicon_cache = list()
|
||||
if (isicon(thing))
|
||||
var/icon/I = thing
|
||||
var/icon_base64 = icon2base64(I)
|
||||
|
||||
if (I.Height() > world.icon_size || I.Width() > world.icon_size)
|
||||
var/icon_md5 = md5(icon_base64)
|
||||
icon_base64 = bicon_cache[icon_md5]
|
||||
if (!icon_base64) // Doesn't exist yet, make it.
|
||||
bicon_cache[icon_md5] = icon_base64 = icon2base64(I)
|
||||
|
||||
|
||||
return "<img class='icon icon-misc' src='data:image/png;base64,[icon_base64]'>"
|
||||
|
||||
// Either an atom or somebody fucked up and is gonna get a runtime, which I'm fine with.
|
||||
var/atom/A = thing
|
||||
var/key = "[istype(A.icon, /icon) ? "\ref[A.icon]" : A.icon]:[A.icon_state]"
|
||||
|
||||
|
||||
if (!bicon_cache[key]) // Doesn't exist, make it.
|
||||
var/icon/I = icon(A.icon, A.icon_state, SOUTH, 1)
|
||||
if (ishuman(thing)) // Shitty workaround for a BYOND issue.
|
||||
var/icon/temp = I
|
||||
I = icon()
|
||||
I.Insert(temp, dir = SOUTH)
|
||||
|
||||
bicon_cache[key] = icon2base64(I, key)
|
||||
|
||||
return "<img class='icon icon-[A.icon_state]' src='data:image/png;base64,[bicon_cache[key]]'>"
|
||||
|
||||
//Costlier version of icon2html() that uses getFlatIcon() to account for overlays, underlays, etc. Use with extreme moderation, ESPECIALLY on mobs.
|
||||
/proc/costly_icon2html(thing, target)
|
||||
if (!thing)
|
||||
return
|
||||
|
||||
if (isicon(thing))
|
||||
return icon2html(thing, target)
|
||||
|
||||
var/icon/I = getFlatIcon(thing)
|
||||
return icon2html(I, target)
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
//wrapper macro for sending images that makes grepping easy
|
||||
#define SEND_IMAGE(target, image) target << image
|
||||
|
||||
/proc/random_blood_type()
|
||||
return pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+")
|
||||
|
||||
@@ -116,6 +113,7 @@
|
||||
"xenohead" = "None",
|
||||
"xenotail" = "None",
|
||||
"exhibitionist" = FALSE,
|
||||
"genitals_use_skintone" = FALSE,
|
||||
"has_cock" = FALSE,
|
||||
"cock_shape" = pick(GLOB.cock_shapes_list),
|
||||
"cock_length" = 6,
|
||||
@@ -158,8 +156,9 @@
|
||||
"womb_cum_rate" = CUM_RATE,
|
||||
"womb_cum_mult" = CUM_RATE_MULT,
|
||||
"womb_efficiency" = CUM_EFFICIENCY,
|
||||
"womb_fluid" = "femcum"))
|
||||
|
||||
"womb_fluid" = "femcum",
|
||||
"flavor_text" = ""))
|
||||
|
||||
/proc/random_hair_style(gender)
|
||||
switch(gender)
|
||||
if(MALE)
|
||||
|
||||
@@ -24,11 +24,12 @@
|
||||
announcement += "<br><span class='alert'>[html_encode(text)]</span><br>"
|
||||
announcement += "<br>"
|
||||
|
||||
var/s = sound(sound)
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!isnewplayer(M) && M.can_hear())
|
||||
to_chat(M, announcement)
|
||||
if(M.client.prefs.toggles & SOUND_ANNOUNCEMENTS)
|
||||
M << sound(sound)
|
||||
SEND_SOUND(M, s)
|
||||
|
||||
/proc/print_command_report(text = "", title = null, announce=TRUE)
|
||||
if(!title)
|
||||
@@ -55,6 +56,6 @@
|
||||
to_chat(M, "<b><font size = 3><font color = red>[title]</font color><BR>[message]</font size></b><BR>")
|
||||
if(M.client.prefs.toggles & SOUND_ANNOUNCEMENTS)
|
||||
if(alert)
|
||||
M << sound('sound/misc/notice1.ogg')
|
||||
SEND_SOUND(M, sound('sound/misc/notice1.ogg'))
|
||||
else
|
||||
M << sound('sound/misc/notice2.ogg')
|
||||
SEND_SOUND(M, sound('sound/misc/notice2.ogg'))
|
||||
|
||||
@@ -45,6 +45,9 @@
|
||||
index = findtext(t, char, index+1)
|
||||
return t
|
||||
|
||||
/proc/sanitize_filename(t)
|
||||
return sanitize_simple(t, list("\n"="", "\t"="", "/"="", "\\"="", "?"="", "%"="", "*"="", ":"="", "|"="", "\""="", "<"="", ">"=""))
|
||||
|
||||
//Runs byond's sanitization proc along-side sanitize_simple
|
||||
/proc/sanitize(t,list/repl_chars = null)
|
||||
return html_encode(sanitize_simple(t,repl_chars))
|
||||
@@ -553,14 +556,14 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
|
||||
|
||||
var/list/tosend = list()
|
||||
tosend["data"] = finalized
|
||||
log << json_encode(tosend)
|
||||
WRITE_FILE(log, json_encode(tosend))
|
||||
|
||||
//Used for applying byonds text macros to strings that are loaded at runtime
|
||||
/proc/apply_text_macros(string)
|
||||
var/next_backslash = findtext(string, "\\")
|
||||
if(!next_backslash)
|
||||
return string
|
||||
|
||||
|
||||
var/leng = length(string)
|
||||
|
||||
var/next_space = findtext(string, " ", next_backslash + 1)
|
||||
|
||||
@@ -537,3 +537,18 @@
|
||||
if(!istype(the_matrix) || the_matrix.len != 20)
|
||||
return "#ffffffff"
|
||||
return rgb(the_matrix[1]*255, the_matrix[6]*255, the_matrix[11]*255, the_matrix[16]*255)
|
||||
|
||||
/proc/type2parent(child)
|
||||
var/string_type = "[child]"
|
||||
var/last_slash = findlasttext(string_type, "/")
|
||||
if(last_slash == 1)
|
||||
switch(child)
|
||||
if(/datum)
|
||||
return null
|
||||
if(/obj || /mob)
|
||||
return /atom/movable
|
||||
if(/area || /turf)
|
||||
return /atom
|
||||
else
|
||||
return /datum
|
||||
return text2path(copytext(string_type, 1, last_slash))
|
||||
@@ -289,7 +289,7 @@ Turf and target are separate in case you want to teleport some distance from a t
|
||||
var/list/pois = list()
|
||||
for(var/mob/M in mobs)
|
||||
if(skip_mindless && (!M.mind && !M.ckey))
|
||||
if(!isbot(M) && !istype(M, /mob/camera/))
|
||||
if(!isbot(M) && !istype(M, /mob/camera) && !ismegafauna(M))
|
||||
continue
|
||||
if(M.client && M.client.holder && M.client.holder.fakekey) //stealthmins
|
||||
continue
|
||||
@@ -491,17 +491,26 @@ 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()
|
||||
/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
|
||||
|
||||
while(processing_list.len)
|
||||
var/atom/A = processing_list[1]
|
||||
processing_list -= 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)
|
||||
processing_list |= (A.contents - assembled)
|
||||
|
||||
assembled |= A
|
||||
assembled |= A
|
||||
|
||||
return assembled
|
||||
|
||||
@@ -836,11 +845,11 @@ GLOBAL_LIST_INIT(WALLITEMS_INVERSE, typecacheof(list(
|
||||
|
||||
/obj/proc/atmosanalyzer_scan(datum/gas_mixture/air_contents, mob/user, obj/target = src)
|
||||
var/obj/icon = target
|
||||
user.visible_message("[user] has used the analyzer on [bicon(icon)] [target].", "<span class='notice'>You use the analyzer on [bicon(icon)] [target].</span>")
|
||||
user.visible_message("[user] has used the analyzer on [icon2html(icon, viewers(src))] [target].", "<span class='notice'>You use the analyzer on [icon2html(icon, user)] [target].</span>")
|
||||
var/pressure = air_contents.return_pressure()
|
||||
var/total_moles = air_contents.total_moles()
|
||||
|
||||
to_chat(user, "<span class='notice'>Results of analysis of [bicon(icon)] [target].</span>")
|
||||
to_chat(user, "<span class='notice'>Results of analysis of [icon2html(icon, user)] [target].</span>")
|
||||
if(total_moles>0)
|
||||
to_chat(user, "<span class='notice'>Pressure: [round(pressure,0.1)] kPa</span>")
|
||||
|
||||
|
||||
@@ -69,8 +69,6 @@
|
||||
#error You need version 511 or higher
|
||||
#endif
|
||||
|
||||
#define SERVICE_CMD_PARAM_KEY "serviceCommsKey"
|
||||
|
||||
//Update this whenever the db schema changes
|
||||
//make sure you add an update to the schema_version stable in the db changelog
|
||||
#define DB_MAJOR_VERSION 3
|
||||
|
||||
@@ -205,7 +205,7 @@ or something covering your eyes."
|
||||
/obj/screen/alert/embeddedobject
|
||||
name = "Embedded Object"
|
||||
desc = "Something got lodged into your flesh and is causing major bleeding. It might fall out with time, but surgery is the safest way. \
|
||||
If you're feeling frisky, click yourself in help intent to pull the object out."
|
||||
If you're feeling frisky, examine yourself and click the underlined item to pull the object out."
|
||||
icon_state = "embeddedobject"
|
||||
|
||||
/obj/screen/alert/embeddedobject/Click()
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
return
|
||||
new /obj/effect/temp_visual/telekinesis(loc)
|
||||
user.UnarmedAttack(src,0) // attack_hand, attack_paw, etc
|
||||
add_hiddenprint(user)
|
||||
return
|
||||
|
||||
/obj/attack_tk(mob/user)
|
||||
@@ -34,6 +35,7 @@
|
||||
O.tk_user = user
|
||||
if(O.focus_object(src))
|
||||
user.put_in_active_hand(O)
|
||||
add_hiddenprint(user)
|
||||
|
||||
/mob/attack_tk(mob/user)
|
||||
return
|
||||
|
||||
@@ -53,6 +53,7 @@ GLOBAL_LIST_EMPTY(xeno_dorsal_list)
|
||||
|
||||
//Genitals and Arousal Lists
|
||||
GLOBAL_LIST_EMPTY(cock_shapes_list)//global_lists.dm for the list initializations //Now also _DATASTRUCTURES globals.dm
|
||||
GLOBAL_LIST_EMPTY(cock_shapes_icons) //Associated list for names->icon_states for cockshapes.
|
||||
GLOBAL_LIST_EMPTY(breasts_size_list)
|
||||
GLOBAL_LIST_EMPTY(breasts_shapes_list)
|
||||
GLOBAL_LIST_EMPTY(vagina_shapes_list)
|
||||
|
||||
+129
-31
@@ -6,7 +6,7 @@
|
||||
var/arousal_rate = 1 //The base rate that arousal will increase in this mob.
|
||||
var/arousal_loss_rate = 1 //How easily arousal can be relieved for this mob.
|
||||
var/canbearoused = FALSE //Mob-level disabler for arousal. Starts off and can be enabled as features are added for different mob types.
|
||||
var/mb_cd_length = 50 //5 second cooldown for masturbating because fuck spam
|
||||
var/mb_cd_length = 100 //5 second cooldown for masturbating because fuck spam.
|
||||
var/mb_cd_timer = 0 //The timer itself
|
||||
|
||||
/mob/living/carbon/human
|
||||
@@ -150,14 +150,14 @@
|
||||
return 0
|
||||
var/mob/living/M = usr
|
||||
if(M.canbearoused)
|
||||
M.mob_masturbate()
|
||||
M.mob_climax()
|
||||
return 1
|
||||
else
|
||||
M << "<span class='warning'>Arousal is disabled. Feature is unavailable.</span>"
|
||||
to_chat(M, "<span class='warning'>Arousal is disabled. Feature is unavailable.</span>")
|
||||
|
||||
|
||||
|
||||
/mob/living/proc/mob_masturbate()//This is just so I can test this shit without being forced to add actual content to get rid of arousal. Will be a very basic proc for a while.
|
||||
/mob/living/proc/mob_climax()//This is just so I can test this shit without being forced to add actual content to get rid of arousal. Will be a very basic proc for a while.
|
||||
set name = "Masturbate"
|
||||
set category = "IC"
|
||||
if(canbearoused && !restrained() && !stat)
|
||||
@@ -179,45 +179,93 @@
|
||||
PoolOrNew(/obj/effect/decal/cleanable/femcum, loc)
|
||||
*/
|
||||
else
|
||||
src << "<span class='notice'>You aren't aroused enough for that.</span>"
|
||||
to_chat(src, "<span class='notice'>You aren't aroused enough for that.</span>")
|
||||
|
||||
/mob/living/carbon/human/mob_masturbate()
|
||||
/mob/living/carbon/human/mob_climax(forced_climax=FALSE) //Forced is instead of the other proc, makes you cum if you have the tools for it, ignoring restraints
|
||||
if(mb_cd_timer > world.time)
|
||||
src << "<span class='warning'>You need to wait [round((mb_cd_timer - world.time)/(20))] seconds before you can do that again!</span>"
|
||||
if(!forced_climax) //Don't spam the message to the victim if forced to come too fast
|
||||
to_chat(src, "<span class='warning'>You need to wait [round((mb_cd_timer - world.time)/(20))] seconds before you can do that again!</span>")
|
||||
return
|
||||
mb_cd_timer = (world.time + mb_cd_length)
|
||||
var/list/genitals_list = list()
|
||||
var/obj/item/organ/genital/SG = null//originally selected_genital
|
||||
var/list/containers_list = list()
|
||||
var/obj/item/weapon/reagent_containers/SC = null
|
||||
var/datum/reagents/fluid_source = null
|
||||
var/into_container = 0
|
||||
var/arms = get_num_arms()
|
||||
var/free_hands = arms
|
||||
var/free_hands = get_num_arms() //arms was only used to know if we had ANY at all
|
||||
var/total_cum = 0
|
||||
var/finished = 0
|
||||
var/mb_time = 30
|
||||
mb_cd_timer = (world.time + mb_cd_length)
|
||||
if(canbearoused && has_dna())
|
||||
if(restrained())
|
||||
src << "<span class='warning'>You can't do that while restrained!</span>"
|
||||
if(stat==2)
|
||||
to_chat(src, "<span class='warning'>You can't do that while dead!</span>")
|
||||
return
|
||||
if(stat)
|
||||
src << "<span class='warning'>You must be conscious to do that!</span>"
|
||||
if(forced_climax) //Something forced us to cum, this is not a masturbation thing and does not progress to the other checks
|
||||
for(var/obj/item/organ/genital/G in internal_organs)
|
||||
if(G.can_masturbate_with) //All capable genitals will orgasm with this
|
||||
var/unable_to_come = FALSE
|
||||
switch(G.type)
|
||||
if(/obj/item/organ/genital/penis)
|
||||
var/obj/item/organ/genital/penis/P = G
|
||||
if(!P.linked_balls)
|
||||
unable_to_come = TRUE
|
||||
else
|
||||
fluid_source = P.linked_balls.reagents
|
||||
|
||||
|
||||
if(/obj/item/organ/genital/vagina)
|
||||
var/obj/item/organ/genital/vagina/V = G
|
||||
if(!V.linked_womb)
|
||||
unable_to_come = TRUE
|
||||
else
|
||||
fluid_source = V.linked_womb.reagents
|
||||
else //Weird, undefined genitalia behaviour
|
||||
unable_to_come = TRUE
|
||||
|
||||
if(unable_to_come)
|
||||
src.visible_message("<span class='danger'>[src] shudders, their [G.name] unable to cum.</span>", \
|
||||
"<span class='userdanger'>Your [G.name] cannot cum, giving no relief.</span>", \
|
||||
"<span class='userdanger'>Your [G.name] cannot cum, giving no relief.</span>")
|
||||
else
|
||||
if(fluid_source)
|
||||
total_cum = fluid_source.total_volume
|
||||
src.visible_message("<span class='danger'>[src] looks like they're about to cum.</span>", \
|
||||
"<span class='green'>You feel yourself about to orgasm.</span>", \
|
||||
"<span class='green'>You feel yourself about to orgasm.</span>")
|
||||
if(do_after(src, mb_time, target = src))
|
||||
if(total_cum > 5)
|
||||
fluid_source.reaction(src.loc, TOUCH, 1, 0)
|
||||
fluid_source.clear_reagents()
|
||||
fluid_source = null //cleanup so this can be used for the next genitalia
|
||||
|
||||
src.visible_message("<span class='danger'>[src] orgasms, cumming[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""]!</span>", \
|
||||
"<span class='green'>You're forced to cum[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""] with your [G].</span>", \
|
||||
"<span class='green'>Your [G] have been forced to climax.</span>")
|
||||
finished = 1
|
||||
if(finished)
|
||||
setArousalLoss(min_arousal)
|
||||
return //Do not proceed to masturbating if all genitals have been forced to orgasm.
|
||||
if(stat==1) //Sleeping people can be forced chemically or with electrical stimulants, for example.
|
||||
to_chat(src, "<span class='warning'>You must be conscious to do that!</span>")
|
||||
return
|
||||
if(restrained())
|
||||
to_chat(src, "<span class='warning'>You can't do that while restrained!</span>")
|
||||
return
|
||||
if(getArousalLoss() < 33)//flat number instead of percentage
|
||||
src << "<span class='warning'>You aren't aroused enough for that!</span>"
|
||||
to_chat(src, "<span class='warning'>You aren't aroused enough for that!</span>")
|
||||
return
|
||||
if(!is_groin_exposed())
|
||||
src << "<span class='warning'>You need to undress, first!</span>"
|
||||
to_chat(src, "<span class='warning'>You need to undress, first!</span>")
|
||||
return
|
||||
if(!arms)
|
||||
src << "<span class='warning'>You need at least one arm.</span>"
|
||||
if(!free_hands)
|
||||
to_chat(src, "<span class='warning'>You need at least one free arm.</span>")
|
||||
return
|
||||
for(var/helditem in held_items)//how many hands are free
|
||||
if(isobj(helditem))
|
||||
free_hands--
|
||||
if(free_hands <= 0)
|
||||
src << "<span class='warning'>You need at least one free hand.</span>"
|
||||
to_chat(src, "<span class='warning'>You need at least one free hand.</span>")
|
||||
return
|
||||
for(var/obj/item/organ/genital/G in internal_organs)
|
||||
if(G.can_masturbate_with)//filter out what you can't masturbate with
|
||||
@@ -240,12 +288,12 @@
|
||||
if(/obj/item/organ/genital/penis)
|
||||
var/obj/item/organ/genital/penis/P = SG
|
||||
if(!P.linked_balls)
|
||||
src << "<span class='warning'>Grow a pair!</span>"
|
||||
to_chat(src, "<span class='warning'>You need a pair of testicles to do this.</span>")
|
||||
return
|
||||
fluid_source = P.linked_balls.reagents
|
||||
total_cum = fluid_source.total_volume
|
||||
if(into_container)//into a glass or beaker or whatever
|
||||
src.visible_message("<span class='danger'>[src] starts [pick("jerking off","stroking")] their [SG] over [SC].</span>", \
|
||||
src.visible_message("<span class='danger'>[src] starts [pick("jerking off","stroking")] their [SG.name] over [SC].</span>", \
|
||||
"<span class='userdanger'>You start jerking off over [SC.name].</span>", \
|
||||
"<span class='userdanger'>You start masturbating.</span>")
|
||||
if(do_after(src, mb_time, target = src) && in_range(src, SC))
|
||||
@@ -254,16 +302,71 @@
|
||||
"<span class='green'>You cum into [SC].</span>", \
|
||||
"<span class='green'>You have relieved yourself.</span>")
|
||||
finished = 1
|
||||
|
||||
else //Not in a container
|
||||
if(src.pulling)
|
||||
if(iscarbon(src.pulling))
|
||||
var/mob/living/carbon/C = src.pulling
|
||||
if(!C.is_groin_exposed())
|
||||
to_chat(src, "<span class='warning'>You must undress someone to climax inside them.</span>")
|
||||
return
|
||||
if(isliving(src.pulling)) //Gotta be alive to fuck it, don't wanna have to code fucking objects that ain't containers...
|
||||
var/mob/living/partner = src.pulling
|
||||
src.visible_message("[src] is about to climax inside [partner]!", \
|
||||
"You're about to climax inside [partner]!", \
|
||||
"<span class='danger'>You're preparing to climax inside someone!</span>")
|
||||
switch(grab_state)
|
||||
if(GRAB_PASSIVE)
|
||||
if(do_after(src, mb_time, target = src) && in_range(src, partner))
|
||||
var/spillage = 0.5 //Leaks a bit on passive grab
|
||||
var/did_spill = FALSE
|
||||
fluid_source.trans_to(partner, total_cum*(1-spillage))
|
||||
total_cum = total_cum*spillage
|
||||
if(total_cum > 5)
|
||||
fluid_source.reaction(partner.loc, TOUCH, 1, 0)
|
||||
did_spill = TRUE
|
||||
fluid_source.clear_reagents()
|
||||
|
||||
src.visible_message("<span class='danger'>[src] ejaculates inside [partner][did_spill ? ", overflowing and spilling":""]!</span>", \
|
||||
"<span class='green'>You ejaculate inside [partner][did_spill ? ", spilling out of them":""].</span>", \
|
||||
"<span class='green'>You have climaxed inside someone[did_spill ? ", spilling out of them":""].</span>")
|
||||
finished = 1
|
||||
else //Aggressive or higher
|
||||
if(do_after(src, mb_time, target = src) && in_range(src, partner))
|
||||
var/spillage = 0.0 //Leakproofing seals
|
||||
fluid_source.trans_to(partner, total_cum*(1-spillage))
|
||||
total_cum = total_cum*spillage
|
||||
if(total_cum > 5)
|
||||
fluid_source.reaction(partner.loc, TOUCH, 1, 0)
|
||||
fluid_source.clear_reagents()
|
||||
|
||||
src.visible_message("<span class='danger'>[src] ejaculates inside [partner], spilling nothing!</span>", \
|
||||
"<span class='green'>You ejaculate inside [partner], spilling nothing.</span>", \
|
||||
"<span class='green'>You have climaxed inside someone, spilling nothing.</span>")
|
||||
finished = 1
|
||||
//Don't care, not coding you fucking a unanchored girder
|
||||
else //No pulling, or pulling non-living things
|
||||
src.visible_message("<span class='danger'>[src] starts [pick("jerking off","stroking")] their [SG].</span>", \
|
||||
"<span class='green'>You start masturbating.</span>", \
|
||||
"<span class='green'>You start masturbating.</span>")
|
||||
if(do_after(src, mb_time, target = src))
|
||||
if(total_cum > 5)
|
||||
fluid_source.reaction(src.loc, TOUCH, 1, 0)
|
||||
fluid_source.clear_reagents()
|
||||
|
||||
src.visible_message("<span class='danger'>[src] orgasms, cumming[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""]!</span>", \
|
||||
"<span class='green'>You cum[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""].</span>", \
|
||||
"<span class='green'>You have relieved yourself.</span>")
|
||||
finished = 1
|
||||
|
||||
if(/obj/item/organ/genital/vagina)
|
||||
var/obj/item/organ/genital/vagina/V = SG
|
||||
if(!V.linked_womb)
|
||||
src << "<span class='warning'>No womb!</span>"
|
||||
to_chat(src, "<span class='warning'>You need a womb to do this.</span>")
|
||||
return
|
||||
fluid_source = V.linked_womb.reagents
|
||||
total_cum = fluid_source.total_volume
|
||||
if(into_container)//into a glass or beaker or whatever
|
||||
src.visible_message("<span class='danger'>[src] starts fingering their vagina over [SC].</span>", \
|
||||
src.visible_message("<span class='danger'>[src] starts fingering their [SG.name] over [SC].</span>", \
|
||||
"<span class='userdanger'>You start fingering over [SC.name].</span>", \
|
||||
"<span class='userdanger'>You start masturbating.</span>")
|
||||
if(do_after(src, mb_time, target = src) && in_range(src, SC))
|
||||
@@ -272,7 +375,7 @@
|
||||
"<span class='green'>You cum into [SC].</span>", \
|
||||
"<span class='green'>You have relieved yourself.</span>")
|
||||
finished = 1
|
||||
|
||||
|
||||
else//not into a container
|
||||
src.visible_message("<span class='danger'>[src] starts fingering their vagina.</span>", \
|
||||
"<span class='userdanger'>You start fingering your vagina.</span>", \
|
||||
@@ -297,10 +400,5 @@
|
||||
setArousalLoss(min_arousal)
|
||||
|
||||
else
|
||||
src << "<span class='warning'>You have no genitals!</span>"
|
||||
to_chat(src, "<span class='warning'>You have no genitals!</span>")
|
||||
return
|
||||
|
||||
/mob/living/carbon/proc/force_orgasm(intensity)
|
||||
if(canbearoused && has_dna() && (has_penis() || has_vagina()))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
M.emote(pick("moan","blush"))
|
||||
if(prob(5))
|
||||
var/aroused_message = pick("You feel frisky.", "You're having trouble suppressing your urges.", "You feel in the mood.")
|
||||
M << "<span class='love'>[aroused_message]</span>"
|
||||
to_chat(M, "<span class='love'>[aroused_message]</span>")
|
||||
..()
|
||||
|
||||
/datum/reagent/aphrodisiacplus
|
||||
@@ -128,15 +128,13 @@
|
||||
else
|
||||
M.emote(pick("moan","blush"))
|
||||
if(prob(5))
|
||||
var/aroused_message
|
||||
if(M.getArousalLoss() > 90)
|
||||
var/aroused_message = pick("You need to fuck someone!", "You're bursting with sexual tension!", "You can't get sex off your mind!")
|
||||
M << "<span class='love'>[aroused_message]</span>"
|
||||
aroused_message = pick("You need to fuck someone!", "You're bursting with sexual tension!", "You can't get sex off your mind!")
|
||||
else
|
||||
var/aroused_message = pick("You feel a bit hot.", "You feel strong sexual urges.", "You feel in the mood.", "You're ready to go down on someone.")
|
||||
M << "<span class='love'>[aroused_message]</span>"
|
||||
// if(iscarbon(M) && has_dna(M))
|
||||
// M.force_ejaculation()
|
||||
..()
|
||||
aroused_message = pick("You feel a bit hot.", "You feel strong sexual urges.", "You feel in the mood.", "You're ready to go down on someone.")
|
||||
to_chat(M, "<span class='love'>[aroused_message]</span>")
|
||||
|
||||
/datum/reagent/aphrodisiacplus/addiction_act_stage2(mob/living/M)
|
||||
if(prob(30))
|
||||
M.adjustBrainLoss(2)
|
||||
@@ -152,11 +150,17 @@
|
||||
..()
|
||||
|
||||
/datum/reagent/aphrodisiacplus/overdose_process(mob/living/M)
|
||||
if(prob(66))
|
||||
if(prob(33))
|
||||
if(M.getArousalLoss() >= 100 && ishuman(M) && M.has_dna())
|
||||
var/mob/living/carbon/human/H = M
|
||||
to_chat(H, "<span class='love'>Your libido is going haywire!</span>")
|
||||
H.mob_climax(forced_climax=TRUE)
|
||||
if(M.min_arousal < 50)
|
||||
M.min_arousal += 1
|
||||
if(M.max_arousal < 200)
|
||||
M.max_arousal += 1
|
||||
to_chat(M, "<span class='love'>You're having a hard time thinkin about things other than sex!</span>")
|
||||
if(M.min_arousal < M.max_arousal)
|
||||
M.min_arousal += 1
|
||||
to_chat(M, "<span class='love'>You feel your libido permanently increasing.</span>")
|
||||
M.adjustArousalLoss(2)
|
||||
..()
|
||||
|
||||
@@ -193,8 +197,10 @@
|
||||
if(prob(33))
|
||||
if(M.min_arousal > 0)
|
||||
M.min_arousal -= 1
|
||||
if(M.max_arousal > 75)
|
||||
to_chat(M, "<span class='notice'>You feel your libido returning to more normal levels.</span>")
|
||||
if(M.min_arousal > 50)
|
||||
M.min_arousal -= 1
|
||||
to_chat(M, "<span class='notice'>You feel like your overactive libido is calming down.</span>")
|
||||
M.adjustArousalLoss(-2)
|
||||
..()
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 704 B |
@@ -1,5 +1,5 @@
|
||||
/obj/item/organ/genital/breasts
|
||||
name = "breasts"
|
||||
name = "Breasts"
|
||||
desc = "Female milk producing organs."
|
||||
icon_state = "breasts"
|
||||
icon = 'code/citadel/icons/breasts.dmi'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/obj/item/organ/genital/eggsack
|
||||
name = "egg sack"
|
||||
name = "Egg sack"
|
||||
desc = "An egg producing reproductive organ."
|
||||
icon_state = "egg_sack"
|
||||
icon = 'code/citadel/icons/ovipositor.dmi'
|
||||
|
||||
@@ -243,8 +243,10 @@
|
||||
G.aroused_state = FALSE
|
||||
icon_string = "[G.slot]_[S.icon_state]_[size]_[G.aroused_state]_[layertext]"
|
||||
I = image("icon" = S.icon, "icon_state" = icon_string, "layer" =- layer)
|
||||
|
||||
if(S.center)
|
||||
I = center_image(I,S.dimension_x,S.dimension_y)
|
||||
|
||||
if(use_skintones && H.dna.features["genitals_use_skintone"])
|
||||
I.color = "#[skintone2hex(H.skin_tone)]"
|
||||
else
|
||||
|
||||
@@ -31,6 +31,33 @@
|
||||
icon_state = "tapered"
|
||||
name = "Tapered"
|
||||
|
||||
////////////////////////
|
||||
// Taur cocks go here //
|
||||
////////////////////////
|
||||
/datum/sprite_accessory/penis/taur_flared
|
||||
icon = 'code/citadel/icons/taur_penis_onmob.dmi' //Needed larger width
|
||||
icon_state = "flared"
|
||||
name = "Taur, Flared"
|
||||
center = TRUE //Center the image 'cause 2-tile wide.
|
||||
dimension_x = 64
|
||||
|
||||
/datum/sprite_accessory/penis/taur_knotted
|
||||
icon = 'code/citadel/icons/taur_penis_onmob.dmi' //Needed larger width
|
||||
icon_state = "knotted"
|
||||
name = "Taur, Knotted"
|
||||
center = TRUE //Center the image 'cause 2-tile wide.
|
||||
dimension_x = 64
|
||||
|
||||
/datum/sprite_accessory/penis/taur_tapered
|
||||
icon = 'code/citadel/icons/taur_penis_onmob.dmi' //Needed larger width
|
||||
icon_state = "tapered"
|
||||
name = "Taur, Tapered"
|
||||
center = TRUE //Center the image 'cause 2-tile wide.
|
||||
dimension_x = 64
|
||||
|
||||
|
||||
|
||||
|
||||
//Vaginas
|
||||
/datum/sprite_accessory/vagina
|
||||
icon = 'code/citadel/icons/vagina_onmob.dmi'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/obj/item/organ/genital/ovipositor
|
||||
name = "ovipositor"
|
||||
name = "Ovipositor"
|
||||
desc = "An egg laying reproductive organ."
|
||||
icon_state = "ovi_knotted_2"
|
||||
icon = 'code/citadel/icons/ovipositor.dmi'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/obj/item/organ/genital/penis
|
||||
name = "penis"
|
||||
name = "Penis"
|
||||
desc = "A male reproductive organ."
|
||||
icon_state = "penis"
|
||||
icon = 'code/citadel/icons/penis.dmi'
|
||||
@@ -35,7 +35,7 @@
|
||||
cached_length = length
|
||||
|
||||
/obj/item/organ/genital/penis/update_appearance()
|
||||
var/string = "penis_[lowertext(shape)]_[size]"
|
||||
var/string = "penis_[GLOB.cock_shapes_icons[shape]]_[size]"
|
||||
icon_state = sanitize_text(string)
|
||||
var/lowershape = lowertext(shape)
|
||||
if(lowershape in knotted_types)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/obj/item/organ/genital/testicles
|
||||
name = "testicles"
|
||||
name = "Testicles"
|
||||
desc = "A male reproductive organ."
|
||||
icon_state = "testicles"
|
||||
icon = 'code/citadel/icons/penis.dmi'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/obj/item/organ/genital/vagina
|
||||
name = "vagina"
|
||||
name = "Vagina"
|
||||
desc = "A female reproductive organ."
|
||||
icon = 'code/citadel/icons/vagina.dmi'
|
||||
icon_state = "vagina"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/obj/item/organ/genital/womb
|
||||
name = "womb"
|
||||
name = "Womb"
|
||||
desc = "A female reproductive organ."
|
||||
icon = 'code/citadel/icons/vagina.dmi'
|
||||
icon_state = "womb"
|
||||
@@ -10,7 +10,7 @@
|
||||
fluid_id = "femcum"
|
||||
producing = TRUE
|
||||
var/obj/item/organ/genital/vagina/linked_vag
|
||||
|
||||
|
||||
/obj/item/organ/genital/womb/Initialize()
|
||||
. = ..()
|
||||
reagents.add_reagent(fluid_id, fluid_max_volume)
|
||||
|
||||
@@ -275,7 +275,7 @@
|
||||
|
||||
if(M.config_tag)
|
||||
if(!(M.config_tag in modes)) // ensure each mode is added only once
|
||||
GLOB.config_error_log << "Adding game mode [M.name] ([M.config_tag]) to configuration."
|
||||
WRITE_FILE(GLOB.config_error_log, "Adding game mode [M.name] ([M.config_tag]) to configuration.")
|
||||
modes += M.config_tag
|
||||
mode_names[M.config_tag] = M.name
|
||||
probabilities[M.config_tag] = M.probability
|
||||
@@ -548,7 +548,7 @@
|
||||
if("irc_announce_new_game")
|
||||
irc_announce_new_game = TRUE
|
||||
else
|
||||
GLOB.config_error_log << "Unknown setting in configuration: '[name]'"
|
||||
WRITE_FILE(GLOB.config_error_log, "Unknown setting in configuration: '[name]'")
|
||||
|
||||
else if(type == "game_options")
|
||||
switch(name)
|
||||
@@ -611,13 +611,13 @@
|
||||
if(mode_name in modes)
|
||||
continuous[mode_name] = 1
|
||||
else
|
||||
GLOB.config_error_log << "Unknown continuous configuration definition: [mode_name]."
|
||||
WRITE_FILE(GLOB.config_error_log, "Unknown continuous configuration definition: [mode_name].")
|
||||
if("midround_antag")
|
||||
var/mode_name = lowertext(value)
|
||||
if(mode_name in modes)
|
||||
midround_antag[mode_name] = 1
|
||||
else
|
||||
GLOB.config_error_log << "Unknown midround antagonist configuration definition: [mode_name]."
|
||||
WRITE_FILE(GLOB.config_error_log, "Unknown midround antagonist configuration definition: [mode_name].")
|
||||
if("midround_antag_time_check")
|
||||
midround_antag_time_check = text2num(value)
|
||||
if("midround_antag_life_check")
|
||||
@@ -633,9 +633,9 @@
|
||||
if(mode_name in modes)
|
||||
min_pop[mode_name] = text2num(mode_value)
|
||||
else
|
||||
GLOB.config_error_log << "Unknown minimum population configuration definition: [mode_name]."
|
||||
WRITE_FILE(GLOB.config_error_log, "Unknown minimum population configuration definition: [mode_name].")
|
||||
else
|
||||
GLOB.config_error_log << "Incorrect minimum population configuration definition: [mode_name] [mode_value]."
|
||||
WRITE_FILE(GLOB.config_error_log, "Incorrect minimum population configuration definition: [mode_name] [mode_value].")
|
||||
if("max_pop")
|
||||
var/pop_pos = findtext(value, " ")
|
||||
var/mode_name = null
|
||||
@@ -647,9 +647,9 @@
|
||||
if(mode_name in modes)
|
||||
max_pop[mode_name] = text2num(mode_value)
|
||||
else
|
||||
GLOB.config_error_log << "Unknown maximum population configuration definition: [mode_name]."
|
||||
WRITE_FILE(GLOB.config_error_log, "Unknown maximum population configuration definition: [mode_name].")
|
||||
else
|
||||
GLOB.config_error_log << "Incorrect maximum population configuration definition: [mode_name] [mode_value]."
|
||||
WRITE_FILE(GLOB.config_error_log, "Incorrect maximum population configuration definition: [mode_name] [mode_value].")
|
||||
if("shuttle_refuel_delay")
|
||||
shuttle_refuel_delay = text2num(value)
|
||||
if("show_game_type_odds")
|
||||
@@ -677,9 +677,9 @@
|
||||
if(prob_name in modes)
|
||||
probabilities[prob_name] = text2num(prob_value)
|
||||
else
|
||||
GLOB.config_error_log << "Unknown game mode probability configuration definition: [prob_name]."
|
||||
WRITE_FILE(GLOB.config_error_log, "Unknown game mode probability configuration definition: [prob_name].")
|
||||
else
|
||||
GLOB.config_error_log << "Incorrect probability configuration definition: [prob_name] [prob_value]."
|
||||
WRITE_FILE(GLOB.config_error_log, "Incorrect probability configuration definition: [prob_name] [prob_value].")
|
||||
|
||||
if("protect_roles_from_antagonist")
|
||||
protect_roles_from_antagonist = 1
|
||||
@@ -726,7 +726,7 @@
|
||||
// Value is in the form "LAWID,NUMBER"
|
||||
var/list/L = splittext(value, ",")
|
||||
if(L.len != 2)
|
||||
GLOB.config_error_log << "Invalid LAW_WEIGHT: " + t
|
||||
WRITE_FILE(GLOB.config_error_log, "Invalid LAW_WEIGHT: " + t)
|
||||
continue
|
||||
var/lawid = L[1]
|
||||
var/weight = text2num(L[2])
|
||||
@@ -781,7 +781,7 @@
|
||||
if("mice_roundstart")
|
||||
mice_roundstart = text2num(value)
|
||||
else
|
||||
GLOB.config_error_log << "Unknown setting in configuration: '[name]'"
|
||||
WRITE_FILE(GLOB.config_error_log, "Unknown setting in configuration: '[name]'")
|
||||
else if(type == "policies")
|
||||
policies[name] = value
|
||||
|
||||
@@ -839,7 +839,7 @@
|
||||
if ("disabled")
|
||||
currentmap = null
|
||||
else
|
||||
GLOB.config_error_log << "Unknown command in map vote config: '[command]'"
|
||||
WRITE_FILE(GLOB.config_error_log, "Unknown command in map vote config: '[command]'")
|
||||
|
||||
|
||||
/datum/configuration/proc/loadsql(filename)
|
||||
@@ -883,7 +883,7 @@
|
||||
if("feedback_tableprefix")
|
||||
global.sqlfdbktableprefix = value
|
||||
else
|
||||
GLOB.config_error_log << "Unknown setting in configuration: '[name]'"
|
||||
WRITE_FILE(GLOB.config_error_log, "Unknown setting in configuration: '[name]'")
|
||||
|
||||
/datum/configuration/proc/pick_mode(mode_name)
|
||||
// I wish I didn't have to instance the game modes in order to look up
|
||||
|
||||
@@ -3,12 +3,15 @@ SUBSYSTEM_DEF(assets)
|
||||
init_order = INIT_ORDER_ASSETS
|
||||
flags = SS_NO_FIRE
|
||||
var/list/cache = list()
|
||||
var/list/preload = list()
|
||||
|
||||
/datum/controller/subsystem/assets/Initialize(timeofday)
|
||||
for(var/type in typesof(/datum/asset) - list(/datum/asset, /datum/asset/simple))
|
||||
var/datum/asset/A = new type()
|
||||
A.register()
|
||||
|
||||
preload = cache.Copy() //don't preload assets generated during the round
|
||||
|
||||
for(var/client/C in GLOB.clients)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/getFilesSlow, C, cache, FALSE), 10)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/getFilesSlow, C, preload, FALSE), 10)
|
||||
..()
|
||||
|
||||
@@ -250,7 +250,7 @@ SUBSYSTEM_DEF(blackbox)
|
||||
return 0
|
||||
return value
|
||||
|
||||
/datum/feedback_variable/proc/get_variable()
|
||||
/datum/feedback_variable/proc/get_variable()
|
||||
return variable
|
||||
|
||||
/datum/feedback_variable/proc/set_details(text)
|
||||
@@ -260,12 +260,12 @@ SUBSYSTEM_DEF(blackbox)
|
||||
/datum/feedback_variable/proc/add_details(text)
|
||||
if (istext(text))
|
||||
if (!details)
|
||||
details = text
|
||||
details = "\"[text]\""
|
||||
else
|
||||
details += " [text]"
|
||||
details += " | \"[text]\""
|
||||
|
||||
/datum/feedback_variable/proc/get_details()
|
||||
/datum/feedback_variable/proc/get_details()
|
||||
return details
|
||||
|
||||
/datum/feedback_variable/proc/get_parsed()
|
||||
return list(variable,value,details)
|
||||
return list(variable,value,details)
|
||||
@@ -283,13 +283,12 @@ SUBSYSTEM_DEF(garbage)
|
||||
|
||||
/client/verb/purge_all_destroyed_objects()
|
||||
set category = "Debug"
|
||||
if(SSgarbage)
|
||||
while(SSgarbage.queue.len)
|
||||
var/datum/o = locate(SSgarbage.queue[1])
|
||||
if(istype(o) && o.gc_destroyed)
|
||||
del(o)
|
||||
SSgarbage.totaldels++
|
||||
SSgarbage.queue.Cut(1, 2)
|
||||
while(SSgarbage.queue.len)
|
||||
var/datum/o = locate(SSgarbage.queue[1])
|
||||
if(istype(o) && o.gc_destroyed)
|
||||
del(o)
|
||||
SSgarbage.totaldels++
|
||||
SSgarbage.queue.Cut(1, 2)
|
||||
|
||||
/datum/verb/qdel_then_find_references()
|
||||
set category = "Debug"
|
||||
|
||||
@@ -217,10 +217,9 @@ SUBSYSTEM_DEF(job)
|
||||
Debug("Running DO")
|
||||
|
||||
//Holder for Triumvirate is stored in the SSticker, this just processes it
|
||||
if(SSticker)
|
||||
if(SSticker.triai)
|
||||
for(var/datum/job/ai/A in occupations)
|
||||
if(SSticker.triai)
|
||||
A.spawn_positions = 3
|
||||
A.spawn_positions = 3
|
||||
|
||||
//Get the players who are ready
|
||||
for(var/mob/dead/new_player/player in GLOB.player_list)
|
||||
|
||||
@@ -149,7 +149,6 @@ SUBSYSTEM_DEF(pai)
|
||||
continue
|
||||
if(!(ROLE_PAI in G.client.prefs.be_special))
|
||||
continue
|
||||
//G << 'sound/misc/server-ready.ogg' //Alerting them to their consideration
|
||||
to_chat(G, "<span class='ghostalert'>[user] is requesting a pAI personality! Use the pAI button to submit yourself as one.</span>")
|
||||
addtimer(CALLBACK(src, .proc/spam_again), spam_delay)
|
||||
var/list/available = list()
|
||||
|
||||
@@ -49,7 +49,7 @@ SUBSYSTEM_DEF(persistence)
|
||||
satchel_string = pick_n_take(expanded_old_satchels)
|
||||
|
||||
old_secret_satchels = jointext(expanded_old_satchels,"#")
|
||||
secret_satchels[SSmapping.config.map_name] << old_secret_satchels
|
||||
WRITE_FILE(secret_satchels[SSmapping.config.map_name], old_secret_satchels)
|
||||
|
||||
var/list/chosen_satchel = splittext(satchel_string,"|")
|
||||
if(!chosen_satchel || isemptylist(chosen_satchel) || chosen_satchel.len != 3) //Malformed
|
||||
@@ -171,7 +171,7 @@ SUBSYSTEM_DEF(persistence)
|
||||
if(isemptylist(savable_obj))
|
||||
continue
|
||||
old_secret_satchels += "[F.x]|[F.y]|[pick(savable_obj)]#"
|
||||
secret_satchels[SSmapping.config.map_name] << old_secret_satchels
|
||||
WRITE_FILE(secret_satchels[SSmapping.config.map_name], old_secret_satchels)
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectChiselMessages()
|
||||
var/savefile/chisel_messages_sav = new /savefile("data/npc_saves/ChiselMessages.sav")
|
||||
@@ -181,14 +181,14 @@ SUBSYSTEM_DEF(persistence)
|
||||
|
||||
log_world("Saved [saved_messages.len] engraved messages on map [SSmapping.config.map_name]")
|
||||
|
||||
chisel_messages_sav[SSmapping.config.map_name] << json_encode(saved_messages)
|
||||
WRITE_FILE(chisel_messages_sav[SSmapping.config.map_name], json_encode(saved_messages))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SaveChiselMessage(obj/structure/chisel_message/M)
|
||||
saved_messages += list(M.pack()) // dm eats one list
|
||||
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectTrophies()
|
||||
trophy_sav << json_encode(saved_trophies)
|
||||
WRITE_FILE(trophy_sav, json_encode(saved_trophies))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SaveTrophy(obj/structure/displaycase/trophy/T)
|
||||
if(!T.added_roundstart && T.showpiece)
|
||||
|
||||
@@ -40,9 +40,15 @@ 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
|
||||
for(var/thing in GLOB.clients)
|
||||
if(!thing)
|
||||
continue
|
||||
var/client/C = thing
|
||||
if(C && config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite
|
||||
C << link("byond://[config.server]")
|
||||
var/datum/chatOutput/co = C.chatOutput
|
||||
if(co)
|
||||
co.ehjax_send(data = "roundrestart")
|
||||
if(server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite
|
||||
C << link("byond://[server]")
|
||||
|
||||
#undef PING_BUFFER_TIME
|
||||
|
||||
@@ -34,8 +34,8 @@ SUBSYSTEM_DEF(shuttle)
|
||||
var/obj/docking_port/mobile/supply/supply
|
||||
var/ordernum = 1 //order number given to next order
|
||||
var/points = 5000 //number of trade-points we have
|
||||
var/centcom_message = "" //Remarks from Centcom on how well you checked the last order.
|
||||
var/list/discoveredPlants = list() //Typepaths for unusual plants we've already sent CentComm, associated with their potencies
|
||||
var/centcom_message = "" //Remarks from CentCom on how well you checked the last order.
|
||||
var/list/discoveredPlants = list() //Typepaths for unusual plants we've already sent CentCom, associated with their potencies
|
||||
|
||||
var/list/supply_packs = list()
|
||||
var/list/shoppinglist = list()
|
||||
@@ -101,8 +101,6 @@ SUBSYSTEM_DEF(shuttle)
|
||||
T.color = "#00ffff"
|
||||
#endif
|
||||
|
||||
//world.log << "[transit_turfs.len] transit turfs registered"
|
||||
|
||||
/datum/controller/subsystem/shuttle/fire()
|
||||
for(var/thing in mobile)
|
||||
if(!thing)
|
||||
@@ -185,7 +183,7 @@ SUBSYSTEM_DEF(shuttle)
|
||||
|
||||
switch(emergency.mode)
|
||||
if(SHUTTLE_RECALL)
|
||||
to_chat(user, "The emergency shuttle may not be called while returning to Centcom.")
|
||||
to_chat(user, "The emergency shuttle may not be called while returning to CentCom.")
|
||||
return
|
||||
if(SHUTTLE_CALL)
|
||||
to_chat(user, "The emergency shuttle is already on its way.")
|
||||
@@ -200,7 +198,7 @@ SUBSYSTEM_DEF(shuttle)
|
||||
to_chat(user, "The emergency shuttle is moving away to a safe distance.")
|
||||
return
|
||||
if(SHUTTLE_STRANDED)
|
||||
to_chat(user, "The emergency shuttle has been disabled by Centcom.")
|
||||
to_chat(user, "The emergency shuttle has been disabled by CentCom.")
|
||||
return
|
||||
|
||||
call_reason = trim(html_encode(call_reason))
|
||||
|
||||
@@ -225,7 +225,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
round_start_time = world.time
|
||||
|
||||
to_chat(world, "<FONT color='blue'><B>Welcome to [station_name()], enjoy your stay!</B></FONT>")
|
||||
world << sound('sound/ai/welcome.ogg')
|
||||
SEND_SOUND(world, sound('sound/ai/welcome.ogg'))
|
||||
|
||||
current_state = GAME_STATE_PLAYING
|
||||
Master.SetRunLevel(RUNLEVEL_GAME)
|
||||
@@ -300,7 +300,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
if("nuclear emergency") //Nuke wasn't on station when it blew up
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
|
||||
station_explosion_detonation(bomb)
|
||||
flick("station_intact_fade_red",cinematic)
|
||||
cinematic.icon_state = "summary_nukefail"
|
||||
@@ -308,12 +308,12 @@ SUBSYSTEM_DEF(ticker)
|
||||
cinematic.icon_state = null
|
||||
flick("intro_cult",cinematic)
|
||||
sleep(25)
|
||||
world << sound('sound/magic/enter_blood.ogg')
|
||||
SEND_SOUND(world, sound('sound/magic/enter_blood.ogg'))
|
||||
sleep(28)
|
||||
world << sound('sound/machines/terminal_off.ogg')
|
||||
SEND_SOUND(world, sound('sound/machines/terminal_off.ogg'))
|
||||
sleep(20)
|
||||
flick("station_corrupted",cinematic)
|
||||
world << sound('sound/effects/ghost.ogg')
|
||||
SEND_SOUND(world, sound('sound/effects/ghost.ogg'))
|
||||
actually_blew_up = FALSE
|
||||
if("gang war") //Gang Domination (just show the override screen)
|
||||
cinematic.icon_state = "intro_malf_still"
|
||||
@@ -323,19 +323,19 @@ SUBSYSTEM_DEF(ticker)
|
||||
if("fake") //The round isn't over, we're just freaking people out for fun
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
world << sound('sound/items/bikehorn.ogg')
|
||||
SEND_SOUND(world, sound('sound/items/bikehorn.ogg'))
|
||||
flick("summary_selfdes",cinematic)
|
||||
actually_blew_up = FALSE
|
||||
else
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
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)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
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
|
||||
@@ -346,42 +346,42 @@ SUBSYSTEM_DEF(ticker)
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
flick("station_explode_fade_red",cinematic)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
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)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
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)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
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)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
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)
|
||||
world << sound('sound/ambience/signal.ogg')
|
||||
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)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
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.
|
||||
@@ -479,7 +479,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
var/list/area/shuttle_areas
|
||||
if(SSshuttle && SSshuttle.emergency)
|
||||
shuttle_areas = SSshuttle.emergency.shuttle_areas
|
||||
if(!Player.onCentcom() && !Player.onSyndieBase())
|
||||
if(!Player.onCentCom() && !Player.onSyndieBase())
|
||||
to_chat(Player, "<font color='blue'><b>You managed to survive, but were marooned on [station_name()]...</b></FONT>")
|
||||
else
|
||||
num_escapees++
|
||||
@@ -636,7 +636,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
if(living_player_count() < config.hard_popcap)
|
||||
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>")
|
||||
next_in_line << sound('sound/misc/notice1.ogg')
|
||||
SEND_SOUND(next_in_line, sound('sound/misc/notice1.ogg'))
|
||||
next_in_line.LateChoices()
|
||||
return
|
||||
queued_players -= next_in_line //Client disconnected, remove he
|
||||
@@ -804,7 +804,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
/datum/controller/subsystem/ticker/proc/save_mode(the_mode)
|
||||
var/F = file("data/mode.txt")
|
||||
fdel(F)
|
||||
F << the_mode
|
||||
WRITE_FILE(F, the_mode)
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/SetRoundEndSound(the_sound)
|
||||
set waitfor = FALSE
|
||||
@@ -858,4 +858,4 @@ SUBSYSTEM_DEF(ticker)
|
||||
'sound/roundend/disappointed.ogg'\
|
||||
)
|
||||
|
||||
world << sound(round_end_sound)
|
||||
SEND_SOUND(world, sound(round_end_sound))
|
||||
|
||||
@@ -53,7 +53,7 @@ SUBSYSTEM_DEF(title)
|
||||
/datum/controller/subsystem/title/Shutdown()
|
||||
if(file_path)
|
||||
var/F = file("data/previous_title.dat")
|
||||
F << file_path
|
||||
WRITE_FILE(F, file_path)
|
||||
|
||||
for(var/thing in GLOB.clients)
|
||||
if(!thing)
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
|
||||
/datum/action/item_action/toggle_firemode
|
||||
name = "Toggle Firemode"
|
||||
|
||||
|
||||
/datum/action/item_action/rcl
|
||||
name = "Change Cable Color"
|
||||
button_icon_state = "rcl_rainbow"
|
||||
@@ -417,6 +417,7 @@
|
||||
button_icon_state = "smoke"
|
||||
|
||||
/datum/action/item_action/ninjaboost
|
||||
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_CONSCIOUS
|
||||
name = "Adrenaline Boost"
|
||||
desc = "Inject a secret chemical that will counteract all movement-impairing effect."
|
||||
button_icon_state = "repulse"
|
||||
@@ -489,7 +490,8 @@
|
||||
var/obj/effect/proc_holder/spell/S = target
|
||||
S.action = src
|
||||
name = S.name
|
||||
icon_icon = S.action_icon
|
||||
desc = S.desc
|
||||
button_icon = S.action_icon
|
||||
button_icon_state = S.action_icon_state
|
||||
background_icon_state = S.action_background_icon_state
|
||||
button.name = name
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
/datum/antagonist/traitor/human
|
||||
should_specialise = FALSE
|
||||
var/should_equip = TRUE
|
||||
|
||||
/datum/antagonist/traitor/human/custom
|
||||
silent = TRUE
|
||||
should_give_codewords = FALSE
|
||||
@@ -31,6 +32,7 @@
|
||||
|
||||
/datum/antagonist/traitor/AI
|
||||
should_specialise = FALSE
|
||||
|
||||
/datum/antagonist/traitor/AI/custom
|
||||
silent = TRUE
|
||||
should_give_codewords = FALSE
|
||||
@@ -38,9 +40,8 @@
|
||||
|
||||
|
||||
/datum/antagonist/traitor/on_body_transfer(mob/living/old_body, mob/living/new_body)
|
||||
if(issilicon(new_body) && issilicon(old_body))
|
||||
..()
|
||||
else
|
||||
// human <-> silicon only
|
||||
if(old_body && issilicon(new_body) ^ issilicon(old_body))
|
||||
silent = TRUE
|
||||
owner.add_antag_datum(base_datum_custom)
|
||||
for(var/datum/antagonist/traitor/new_datum in owner.antag_datums)
|
||||
@@ -49,13 +50,14 @@
|
||||
transfer_important_variables(new_datum)
|
||||
break
|
||||
on_removal()
|
||||
|
||||
|
||||
else
|
||||
..()
|
||||
|
||||
/datum/antagonist/traitor/human/custom //used to give custom objectives
|
||||
silent = TRUE
|
||||
give_objectives = FALSE
|
||||
should_give_codewords = FALSE
|
||||
|
||||
/datum/antagonist/traitor/AI/custom //used to give custom objectives
|
||||
silent = TRUE
|
||||
give_objectives = FALSE
|
||||
@@ -83,7 +85,8 @@
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
if(traitor_mob&&istype(traitor_mob))
|
||||
if(!silent) to_chat(traitor_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
|
||||
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)
|
||||
|
||||
/datum/antagonist/traitor/remove_innate_effects()
|
||||
|
||||
@@ -280,7 +280,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
|
||||
if(!D)
|
||||
return
|
||||
to_chat(world, "<font size=5><span class='danger'><b>\"SLOTH, WRATH, GLUTTONY, ACEDIA, ENVY, GREED, PRIDE! FIRES OF HELL AWAKEN!!\"</font></span>")
|
||||
world << 'sound/hallucinations/veryfar_noise.ogg'
|
||||
SEND_SOUND(world, sound('sound/hallucinations/veryfar_noise.ogg'))
|
||||
give_appropriate_spells()
|
||||
D.convert_to_archdevil()
|
||||
if(istype(D.loc, /obj/effect/dummy/slaughter/))
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
|
||||
|
||||
/datum/antagonist/ninja/greet()
|
||||
owner.current << sound('sound/effects/ninja_greeting.ogg')
|
||||
SEND_SOUND(owner.current, sound('sound/effects/ninja_greeting.ogg'))
|
||||
to_chat(owner.current, "I am an elite mercenary assassin of the mighty Spider Clan. A <font color='red'><B>SPACE NINJA</B></font>!")
|
||||
to_chat(owner.current, "Surprise is my weapon. Shadows are my armor. Without them, I am nothing. (//initialize your suit by right clicking on it, to use abilities like stealth)!")
|
||||
to_chat(owner.current, "Officially, [helping_station?"Nanotrasen":"The Syndicate"] are my employer.")
|
||||
|
||||
@@ -100,3 +100,57 @@
|
||||
if (object == GLOBAL_PROC)
|
||||
return call(delegate)(arglist(calling_arguments))
|
||||
return call(object, delegate)(arglist(calling_arguments))
|
||||
|
||||
|
||||
/datum/callback_select
|
||||
var/list/finished
|
||||
var/pendingcount
|
||||
var/total
|
||||
|
||||
/datum/callback_select/New(count, savereturns)
|
||||
total = count
|
||||
if (savereturns)
|
||||
finished = new(count)
|
||||
|
||||
|
||||
/datum/callback_select/proc/invoke_callback(index, datum/callback/callback, list/callback_args, savereturn = TRUE)
|
||||
set waitfor = FALSE
|
||||
if (!callback || !istype(callback))
|
||||
//This check only exists because the alternative is callback_select would block forever if given invalid data
|
||||
CRASH("invalid callback passed to invoke_callback")
|
||||
if (!length(callback_args))
|
||||
callback_args = list()
|
||||
pendingcount++
|
||||
var/rtn = callback.Invoke(arglist(callback_args))
|
||||
pendingcount--
|
||||
if (savereturn)
|
||||
finished[index] = rtn
|
||||
|
||||
|
||||
|
||||
|
||||
//runs a list of callbacks asynchronously, returning once all of them return.
|
||||
//callbacks can be repeated.
|
||||
//callbacks-args is a optional list of argument lists, in the same order as the callbacks,
|
||||
// the inner lists will be sent to the callbacks when invoked() as additional args.
|
||||
//can optionly save and return a list of return values, in the same order as the original list of callbacks
|
||||
//resolution is the number of byond ticks between checks.
|
||||
/proc/callback_select(list/callbacks, list/callback_args, savereturns = TRUE, resolution = 1)
|
||||
if (!callbacks)
|
||||
return
|
||||
var/count = length(callbacks)
|
||||
if (!count)
|
||||
return
|
||||
if (!callback_args)
|
||||
callback_args = list()
|
||||
|
||||
callback_args.len = count
|
||||
|
||||
var/datum/callback_select/CS = new(count, savereturns)
|
||||
for (var/i in 1 to count)
|
||||
CS.invoke_callback(i, callbacks[i], callback_args[i], savereturns)
|
||||
|
||||
while(CS.pendingcount)
|
||||
sleep(resolution*world.tick_lag)
|
||||
return CS.finished
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
diff a/code/datums/callback.dm b/code/datums/callback.dm (rejected hunks)
|
||||
@@ -100,60 +100,3 @@
|
||||
if (object == GLOBAL_PROC)
|
||||
return call(delegate)(arglist(calling_arguments))
|
||||
return call(object, delegate)(arglist(calling_arguments))
|
||||
-
|
||||
-
|
||||
-/datum/callback_select
|
||||
- var/list/finished
|
||||
- var/pendingcount
|
||||
- var/total
|
||||
-
|
||||
-/datum/callback_select/New(count, savereturns)
|
||||
- total = count
|
||||
- if (savereturns)
|
||||
- finished = new(count)
|
||||
-
|
||||
-
|
||||
-/datum/callback_select/proc/invoke_callback(index, datum/callback/callback, list/callback_args, savereturn = TRUE)
|
||||
- set waitfor = FALSE
|
||||
- if (!callback || !istype(callback))
|
||||
- //This check only exists because the alternative is callback_select would block forever if given invalid data
|
||||
- CRASH("invalid callback passed to invoke_callback")
|
||||
- if (!length(callback_args))
|
||||
- callback_args = list()
|
||||
- pendingcount++
|
||||
- debug_usr("calling callback")
|
||||
- var/rtn = callback.Invoke(arglist(callback_args))
|
||||
- debug_usr("callback returned")
|
||||
- pendingcount--
|
||||
- if (savereturn)
|
||||
- finished[index] = rtn
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-//runs a list of callbacks asynchronously, returning once all of them return.
|
||||
-//callbacks can be repeated.
|
||||
-//callbacks-args is a optional list of argument lists, in the same order as the callbacks,
|
||||
-// the inner lists will be sent to the callbacks when invoked() as additional args.
|
||||
-//can optionly save and return a list of return values, in the same order as the original list of callbacks
|
||||
-//resolution is the number of byond ticks between checks.
|
||||
-/proc/callback_select(list/callbacks, list/callback_args, savereturns = TRUE, resolution = 1)
|
||||
- if (!callbacks)
|
||||
- return
|
||||
- var/count = length(callbacks)
|
||||
- if (!count)
|
||||
- return
|
||||
- if (!callback_args)
|
||||
- callback_args = list()
|
||||
-
|
||||
- callback_args.len = count
|
||||
-
|
||||
- var/datum/callback_select/CS = new(count, savereturns)
|
||||
- for (var/i in 1 to count)
|
||||
- CS.invoke_callback(i, callbacks[i], callback_args[i], savereturns)
|
||||
- debug_usr("starting callbacks: [CS.pendingcount]")
|
||||
- while(CS.pendingcount)
|
||||
- debug_usr("callbacks: [CS.pendingcount]")
|
||||
- sleep(resolution*world.tick_lag)
|
||||
- return CS.finished
|
||||
-
|
||||
@@ -18,7 +18,38 @@
|
||||
qdel(src)
|
||||
return
|
||||
P.SendSignal(COMSIG_COMPONENT_ADDED, src)
|
||||
LAZYADD(P.datum_components, src)
|
||||
|
||||
//lazy init the parent's dc list
|
||||
var/list/dc = P.datum_components
|
||||
if(!dc)
|
||||
P.datum_components = dc = list()
|
||||
|
||||
//set up the typecache
|
||||
var/our_type = type
|
||||
for(var/I in _GetInverseTypeListExceptRoot(our_type))
|
||||
var/test = dc[I]
|
||||
if(test) //already another component of this type here
|
||||
var/list/components_of_type
|
||||
if(!islist(test))
|
||||
components_of_type = list(test)
|
||||
dc[I] = components_of_type
|
||||
else
|
||||
components_of_type = test
|
||||
if(I == our_type) //exact match, take priority
|
||||
var/inserted = FALSE
|
||||
for(var/J in 1 to components_of_type.len)
|
||||
var/datum/component/C = components_of_type[J]
|
||||
if(C.type != our_type) //but not over other exact matches
|
||||
components_of_type.Insert(J, I)
|
||||
inserted = TRUE
|
||||
break
|
||||
if(!inserted)
|
||||
components_of_type += src
|
||||
else //indirect match, back of the line with ya
|
||||
components_of_type += src
|
||||
else //only component of this type, no list
|
||||
dc[I] = src
|
||||
|
||||
parent = P
|
||||
|
||||
/datum/component/Destroy()
|
||||
@@ -33,7 +64,20 @@
|
||||
/datum/component/proc/_RemoveNoSignal()
|
||||
var/datum/P = parent
|
||||
if(P)
|
||||
LAZYREMOVE(P.datum_components, src)
|
||||
var/list/dc = P.datum_components
|
||||
var/our_type = type
|
||||
for(var/I in _GetInverseTypeListExceptRoot(our_type))
|
||||
var/list/components_of_type = dc[I]
|
||||
if(islist(components_of_type)) //
|
||||
var/list/subtracted = components_of_type - src
|
||||
if(subtracted.len == 1) //only 1 guy left
|
||||
dc[I] = subtracted[1] //make him special
|
||||
else
|
||||
dc[I] = subtracted
|
||||
else //just us
|
||||
dc -= I
|
||||
if(!dc.len)
|
||||
P.datum_components = null
|
||||
parent = null
|
||||
|
||||
/datum/component/proc/RegisterSignal(sig_type, proc_on_self, override = FALSE)
|
||||
@@ -66,6 +110,13 @@
|
||||
/datum/component/proc/OnTransfer(datum/new_parent)
|
||||
return
|
||||
|
||||
/datum/component/proc/_GetInverseTypeListExceptRoot(our_type_cached)
|
||||
var/datum/component/current_type = our_type_cached
|
||||
. = list()
|
||||
while (current_type != /datum/component)
|
||||
. += current_type
|
||||
current_type = type2parent(current_type)
|
||||
|
||||
/datum/proc/SendSignal(sigtype, ...)
|
||||
var/list/comps = datum_components
|
||||
. = FALSE
|
||||
@@ -81,21 +132,32 @@
|
||||
return
|
||||
|
||||
/datum/proc/GetComponent(c_type)
|
||||
for(var/I in datum_components)
|
||||
if(istype(I, c_type))
|
||||
return I
|
||||
var/list/dc = datum_components
|
||||
if(!dc)
|
||||
return null
|
||||
. = dc[c_type]
|
||||
if(islist(.))
|
||||
return .[1]
|
||||
|
||||
/datum/proc/GetExactComponent(c_type)
|
||||
for(var/I in datum_components)
|
||||
var/datum/component/C = I
|
||||
var/list/dc = datum_components
|
||||
if(!dc)
|
||||
return null
|
||||
var/datum/component/C = dc[c_type]
|
||||
if(C)
|
||||
if(islist(C))
|
||||
C = C[1]
|
||||
if(C.type == c_type)
|
||||
return I
|
||||
return C
|
||||
return null
|
||||
|
||||
/datum/proc/GetComponents(c_type)
|
||||
. = list()
|
||||
for(var/I in datum_components)
|
||||
if(istype(I, c_type))
|
||||
. += I
|
||||
var/list/dc = datum_components
|
||||
if(!dc)
|
||||
return null
|
||||
. = dc[c_type]
|
||||
if(!islist(.))
|
||||
return list(.)
|
||||
|
||||
/datum/proc/AddComponent(new_type, ...)
|
||||
var/nt = new_type
|
||||
|
||||
@@ -1,63 +1 @@
|
||||
diff a/code/datums/components/component.dm b/code/datums/components/component.dm (rejected hunks)
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
//set up the typecache
|
||||
var/our_type = type
|
||||
- for(var/I in _GetInverseTypeListExceptRoot(our_type))
|
||||
+ for(var/I in _GetInverseTypeList(our_type))
|
||||
var/test = dc[I]
|
||||
if(test) //already another component of this type here
|
||||
var/list/components_of_type
|
||||
@@ -66,7 +66,7 @@
|
||||
if(P)
|
||||
var/list/dc = P.datum_components
|
||||
var/our_type = type
|
||||
- for(var/I in _GetInverseTypeListExceptRoot(our_type))
|
||||
+ for(var/I in _GetInverseTypeList(our_type))
|
||||
var/list/components_of_type = dc[I]
|
||||
if(islist(components_of_type)) //
|
||||
var/list/subtracted = components_of_type - src
|
||||
@@ -110,25 +110,33 @@
|
||||
/datum/component/proc/OnTransfer(datum/new_parent)
|
||||
return
|
||||
|
||||
-/datum/component/proc/_GetInverseTypeListExceptRoot(our_type_cached)
|
||||
- var/datum/component/current_type = our_type_cached
|
||||
- . = list()
|
||||
+/datum/component/proc/_GetInverseTypeList(current_type)
|
||||
+ . = list(current_type)
|
||||
while (current_type != /datum/component)
|
||||
- . += current_type
|
||||
current_type = type2parent(current_type)
|
||||
+ . += current_type
|
||||
|
||||
/datum/var/list/datum_components //special typecache of /datum/component
|
||||
|
||||
/datum/proc/SendSignal(sigtype, ...)
|
||||
var/list/comps = datum_components
|
||||
. = FALSE
|
||||
- for(var/I in comps)
|
||||
- var/datum/component/C = I
|
||||
- if(!C.enabled)
|
||||
- continue
|
||||
- if(C.ReceiveSignal(arglist(args)))
|
||||
+ if(!comps)
|
||||
+ return
|
||||
+ var/target = comps[/datum/component]
|
||||
+ if(!islist(target))
|
||||
+ var/datum/component/C = target
|
||||
+ if(C.enabled && C.ReceiveSignal(arglist(args)))
|
||||
ComponentActivated(C)
|
||||
- . = TRUE
|
||||
+ return TRUE
|
||||
+ else
|
||||
+ for(var/I in target)
|
||||
+ var/datum/component/C = I
|
||||
+ if(!C.enabled)
|
||||
+ continue
|
||||
+ if(C.ReceiveSignal(arglist(args)))
|
||||
+ ComponentActivated(C)
|
||||
+ . = TRUE
|
||||
|
||||
/datum/proc/ComponentActivated(datum/component/C)
|
||||
return
|
||||
-
|
||||
@@ -929,6 +929,26 @@
|
||||
manipulate_organs(C)
|
||||
href_list["datumrefresh"] = href_list["editorgans"]
|
||||
|
||||
else if(href_list["hallucinate"])
|
||||
if(!check_rights(0))
|
||||
return
|
||||
|
||||
var/mob/living/carbon/C = locate(href_list["hallucinate"]) in GLOB.mob_list
|
||||
if(!istype(C))
|
||||
to_chat(usr, "This can only be done to instances of type /mob/living/carbon")
|
||||
return
|
||||
|
||||
var/list/hallucinations = subtypesof(/datum/hallucination)
|
||||
var/result = input(usr, "Choose the hallucination to apply","Send Hallucination") as null|anything in hallucinations
|
||||
if(!usr)
|
||||
return
|
||||
if(QDELETED(C))
|
||||
to_chat(usr, "Mob doesn't exist anymore")
|
||||
return
|
||||
|
||||
if(result)
|
||||
new result(C, TRUE)
|
||||
|
||||
else if(href_list["makehuman"])
|
||||
if(!check_rights(R_SPAWN))
|
||||
return
|
||||
|
||||
@@ -59,4 +59,4 @@ Bonus
|
||||
else
|
||||
if(prob(base_message_chance))
|
||||
to_chat(M, "<span class='userdanger'>[pick("Oh, your head...", "Your head pounds.", "They're everywhere! Run!", "Something in the shadows...")]</span>")
|
||||
M.hallucination += (15 * power)
|
||||
M.hallucination += (45 * power)
|
||||
|
||||
@@ -29,6 +29,10 @@
|
||||
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
|
||||
@@ -228,6 +232,7 @@
|
||||
|
||||
if(newfeatures)
|
||||
dna.features = newfeatures
|
||||
flavor_text = dna.features["flavor_text"] //Update the flavor_text to use new dna text
|
||||
|
||||
if(mrace)
|
||||
set_species(mrace, icon_update=0)
|
||||
@@ -247,6 +252,8 @@
|
||||
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()
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
var/minetype = "lavaland"
|
||||
|
||||
var/list/transition_config = list(CENTCOMM = SELFLOOPING,
|
||||
var/list/transition_config = list(CENTCOM = SELFLOOPING,
|
||||
MAIN_STATION = CROSSLINKED,
|
||||
EMPTY_AREA_1 = CROSSLINKED,
|
||||
EMPTY_AREA_2 = CROSSLINKED,
|
||||
@@ -115,8 +115,8 @@
|
||||
return UNAFFECTED
|
||||
if("MAIN_STATION")
|
||||
return MAIN_STATION
|
||||
if("CENTCOMM")
|
||||
return CENTCOMM
|
||||
if("CENTCOM")
|
||||
return CENTCOM
|
||||
if("MINING")
|
||||
return MINING
|
||||
if("EMPTY_AREA_1")
|
||||
|
||||
+20
-11
@@ -120,6 +120,10 @@
|
||||
transfer_martial_arts(new_character)
|
||||
if(active || force_key_move)
|
||||
new_character.key = key //now transfer the key to link the client to our new body
|
||||
if(isliving(new_character)) //New humans and such are by default enabled arousal. Let's always use the new mind's prefs.
|
||||
var/mob/living/L = new_character
|
||||
L.canbearoused = L.client.prefs.arousable //Technically this should make taking over a character mean the body gain the new minds setting...
|
||||
L.update_arousal_hud() //Removes the old icon
|
||||
|
||||
/datum/mind/proc/store_memory(new_text)
|
||||
memory += "[new_text]<BR>"
|
||||
@@ -396,7 +400,15 @@
|
||||
if (assigned_role in GLOB.command_positions)
|
||||
text += "<b>HEAD</b>|loyal|employee|headrev|rev"
|
||||
else if (src in SSticker.mode.head_revolutionaries)
|
||||
text += "head|loyal|<a href='?src=\ref[src];revolution=clear'>employee</a>|<b>HEADREV</b>|<a href='?src=\ref[src];revolution=rev'>rev</a>"
|
||||
var/last_healthy_headrev = TRUE
|
||||
for(var/I in SSticker.mode.head_revolutionaries)
|
||||
if(I == src)
|
||||
continue
|
||||
var/mob/M = I
|
||||
if(M.z == ZLEVEL_STATION && !M.stat)
|
||||
last_healthy_headrev = FALSE
|
||||
break
|
||||
text += "head|loyal|<a href='?src=\ref[src];revolution=clear'>employee</a>|<b>[last_healthy_headrev ? "<font color='red'>LAST </font> " : ""]HEADREV</b>|<a href='?src=\ref[src];revolution=rev'>rev</a>"
|
||||
text += "<br>Flash: <a href='?src=\ref[src];revolution=flash'>give</a>"
|
||||
|
||||
var/list/L = current.get_contents()
|
||||
@@ -801,11 +813,11 @@
|
||||
possible_targets += possible_target.current
|
||||
|
||||
var/mob/def_target = null
|
||||
var/objective_list[] = list(/datum/objective/assassinate, /datum/objective/protect, /datum/objective/debrain, /datum/objective/maroon)
|
||||
if (objective&&(objective.type in objective_list) && objective:target)
|
||||
def_target = objective:target.current
|
||||
var/list/objective_list = typecacheof(list(/datum/objective/assassinate, /datum/objective/protect, /datum/objective/debrain, /datum/objective/maroon))
|
||||
if (is_type_in_typecache(objective, objective_list) && objective.target)
|
||||
def_target = objective.target.current
|
||||
|
||||
var/new_target = input("Select target:", "Objective target", def_target) as null|anything in possible_targets
|
||||
var/mob/new_target = input("Select target:", "Objective target", def_target) as null|anything in possible_targets
|
||||
if (!new_target)
|
||||
return
|
||||
|
||||
@@ -813,12 +825,12 @@
|
||||
if (new_target == "Free objective")
|
||||
new_objective = new objective_path
|
||||
new_objective.owner = src
|
||||
new_objective:target = null
|
||||
new_objective.target = null
|
||||
new_objective.explanation_text = "Free objective"
|
||||
else
|
||||
new_objective = new objective_path
|
||||
new_objective.owner = src
|
||||
new_objective:target = new_target:mind
|
||||
new_objective.target = new_target.mind
|
||||
//Will display as special role if the target is set as MODE. Ninjas/commandos/nuke ops.
|
||||
new_objective.update_explanation_text()
|
||||
|
||||
@@ -1690,10 +1702,7 @@
|
||||
|
||||
else
|
||||
mind = new /datum/mind(key)
|
||||
if(SSticker)
|
||||
SSticker.minds += mind
|
||||
else
|
||||
stack_trace("mind_initialize(): No SSticker ready")
|
||||
SSticker.minds += mind
|
||||
if(!mind.name)
|
||||
mind.name = real_name
|
||||
mind.current = src
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
id = "derelict4"
|
||||
suffix = "derelict4.dmm"
|
||||
name = "Derelict 4"
|
||||
description = "Centcom ferries have never crashed, will never crash, there is no current investigation into a crashed ferry, and we will not let Internal Affairs trample over high security \
|
||||
description = "CentCom ferries have never crashed, will never crash, there is no current investigation into a crashed ferry, and we will not let Internal Affairs trample over high security \
|
||||
information in the name of this baseless witchhunt."
|
||||
|
||||
/datum/map_template/ruin/space/derelict5
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
/datum/map_template/shuttle/emergency/cramped
|
||||
suffix = "cramped"
|
||||
name = "Secure Transport Vessel 5 (STV5)"
|
||||
description = "Well, looks like Centcomm only had this ship in the area, they probably weren't expecting you to need evac for a while. \
|
||||
description = "Well, looks like CentCom only had this ship in the area, they probably weren't expecting you to need evac for a while. \
|
||||
Probably best if you don't rifle around in whatever equipment they were transporting. I hope you're friendly with your coworkers, because there is very little space in this thing.\n\
|
||||
\n\
|
||||
Contains contraband armory guns, maintenance loot, and abandoned crates!"
|
||||
@@ -181,7 +181,7 @@
|
||||
suffix = "supermatter"
|
||||
name = "Hyperfractal Gigashuttle"
|
||||
description = "\"I dunno, this seems kinda needlessly complicated.\"\n\
|
||||
\"This shuttle has very a very high safety record, according to Centcom Officer Cadet Yins.\"\n\
|
||||
\"This shuttle has very a very high safety record, according to CentCom Officer Cadet Yins.\"\n\
|
||||
\"Are you sure?\"\n\
|
||||
\"Yes, it has a safety record of N-A-N, which is apparently larger than 100%.\""
|
||||
admin_notes = "Supermatter that spawns on shuttle is special anchored 'hugbox' supermatter that cannot take damage and does not take in or emit gas. \
|
||||
@@ -215,7 +215,7 @@
|
||||
/datum/map_template/shuttle/ferry/base
|
||||
suffix = "base"
|
||||
name = "transport ferry"
|
||||
description = "Standard issue Box/Metastation Centcom ferry."
|
||||
description = "Standard issue Box/Metastation CentCom ferry."
|
||||
|
||||
/datum/map_template/shuttle/ferry/meat
|
||||
suffix = "meat"
|
||||
@@ -267,7 +267,7 @@
|
||||
|
||||
/datum/map_template/shuttle/emergency/raven
|
||||
suffix = "raven"
|
||||
name = "Centcomm Raven Battlecruiser"
|
||||
description = "The Centcomm Raven Battlecruiser is currently docked at the Centcomm ship bay awaiting a mission, this Battlecruiser has been reassigned as an emergency escape shuttle for currently unknown reasons. The Centcomm Raven Battlecruiser should comfortably fit a medium to large crew size crew and is complete with all required facitlities including a top of the range Centcomm Medical Bay."
|
||||
name = "CentCom Raven Battlecruiser"
|
||||
description = "The CentCom Raven Battlecruiser is currently docked at the CentCom ship bay awaiting a mission, this Battlecruiser has been reassigned as an emergency escape shuttle for currently unknown reasons. The CentCom Raven Battlecruiser should comfortably fit a medium to large crew size crew and is complete with all required facitlities including a top of the range CentCom Medical Bay."
|
||||
admin_notes = "The long way home"
|
||||
credit_cost = 12500
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
icon_state = "shadow_mend"
|
||||
|
||||
/datum/status_effect/void_price/tick()
|
||||
owner << sound('sound/magic/summon_karp.ogg', volume = 25)
|
||||
SEND_SOUND(owner, sound('sound/magic/summon_karp.ogg', volume = 25))
|
||||
owner.adjustBruteLoss(3)
|
||||
|
||||
|
||||
@@ -247,7 +247,7 @@
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
if(isliving(B.current))
|
||||
var/mob/living/M = B.current
|
||||
M << 'sound/hallucinations/veryfar_noise.ogg'
|
||||
SEND_SOUND(M, sound('sound/hallucinations/veryfar_noise.ogg'))
|
||||
to_chat(M, "<span class='cultlarge'>The Cult's Master, [owner], has fallen in \the [A]!</span>")
|
||||
|
||||
/datum/status_effect/cult_master/tick()
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
if(telegraph_message)
|
||||
to_chat(M, telegraph_message)
|
||||
if(telegraph_sound)
|
||||
M << sound(telegraph_sound)
|
||||
SEND_SOUND(M, sound(telegraph_sound))
|
||||
addtimer(CALLBACK(src, .proc/start), telegraph_duration)
|
||||
|
||||
/datum/weather/proc/start()
|
||||
@@ -83,7 +83,7 @@
|
||||
if(weather_message)
|
||||
to_chat(M, weather_message)
|
||||
if(weather_sound)
|
||||
M << sound(weather_sound)
|
||||
SEND_SOUND(M, sound(weather_sound))
|
||||
START_PROCESSING(SSweather, src)
|
||||
addtimer(CALLBACK(src, .proc/wind_down), weather_duration)
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
if(end_message)
|
||||
to_chat(M, end_message)
|
||||
if(end_sound)
|
||||
M << sound(end_sound)
|
||||
SEND_SOUND(M, sound(end_sound))
|
||||
STOP_PROCESSING(SSweather, src)
|
||||
addtimer(CALLBACK(src, .proc/end), end_duration)
|
||||
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
var/mob/living/simple_animal/bot/mulebot/M = holder
|
||||
switch(wire)
|
||||
if(WIRE_POWER1, WIRE_POWER2)
|
||||
holder.visible_message("<span class='notice'>[bicon(M)] The charge light flickers.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] The charge light flickers.</span>")
|
||||
if(WIRE_AVOIDANCE)
|
||||
holder.visible_message("<span class='notice'>[bicon(M)] The external warning lights flash briefly.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] The external warning lights flash briefly.</span>")
|
||||
if(WIRE_LOADCHECK)
|
||||
holder.visible_message("<span class='notice'>[bicon(M)] The load platform clunks.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] The load platform clunks.</span>")
|
||||
if(WIRE_MOTOR1, WIRE_MOTOR2)
|
||||
holder.visible_message("<span class='notice'>[bicon(M)] The drive motor whines briefly.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] The drive motor whines briefly.</span>")
|
||||
else
|
||||
holder.visible_message("<span class='notice'>[bicon(M)] You hear a radio crackle.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] You hear a radio crackle.</span>")
|
||||
@@ -25,7 +25,7 @@
|
||||
if(WIRE_INTERFACE)
|
||||
C.interface_control = !C.interface_control
|
||||
if(WIRE_LIMIT)
|
||||
C.visible_message("[bicon(C)]<b>[C]</b> makes a large whirring noise.")
|
||||
C.visible_message("[icon2html(C, viewers(holder))]<b>[C]</b> makes a large whirring noise.")
|
||||
|
||||
/datum/wires/particle_accelerator/control_box/on_cut(wire, mend)
|
||||
var/obj/machinery/particle_accelerator/control_box/C = holder
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
var/list/status = list()
|
||||
status += "The law sync module is [R.lawupdate ? "on" : "off"]."
|
||||
status += "The intelligence link display shows [R.connected_ai ? R.connected_ai.name : "NULL"]."
|
||||
status += "The camera light is [!isnull(R.camera) && R.camera.status ? "on" : "off"]."
|
||||
status += "The camera light is [!isnull(R.builtInCamera) && R.builtInCamera.status ? "on" : "off"]."
|
||||
status += "The lockdown indicator is [R.lockcharge ? "on" : "off"]."
|
||||
status += "The reset module hardware light is [R.has_module() ? "on" : "off"]."
|
||||
return status
|
||||
@@ -45,9 +45,9 @@
|
||||
else
|
||||
R.notify_ai(TRUE)
|
||||
if(WIRE_CAMERA) // Pulse to disable the camera.
|
||||
if(!isnull(R.camera) && !R.scrambledcodes)
|
||||
R.camera.toggle_cam(usr, 0)
|
||||
R.visible_message("[R]'s camera lense focuses loudly.", "Your camera lense focuses loudly.")
|
||||
if(!QDELETED(R.builtInCamera) && !R.scrambledcodes)
|
||||
R.builtInCamera.toggle_cam(usr, 0)
|
||||
R.visible_message("[R]'s camera lens focuses loudly.", "Your camera lens focuses loudly.")
|
||||
if(WIRE_LAWSYNC) // Forces a law update if possible.
|
||||
if(R.lawupdate)
|
||||
R.visible_message("[R] gently chimes.", "LawSync protocol engaged.")
|
||||
@@ -75,10 +75,10 @@
|
||||
else if(!R.deployed) //AI shells must always have the same laws as the AI
|
||||
R.lawupdate = FALSE
|
||||
if (WIRE_CAMERA) // Disable the camera.
|
||||
if(!isnull(R.camera) && !R.scrambledcodes)
|
||||
R.camera.status = mend
|
||||
R.camera.toggle_cam(usr, 0)
|
||||
R.visible_message("[R]'s camera lense focuses loudly.", "Your camera lense focuses loudly.")
|
||||
if(!QDELETED(R.builtInCamera) && !R.scrambledcodes)
|
||||
R.builtInCamera.status = mend
|
||||
R.builtInCamera.toggle_cam(usr, 0)
|
||||
R.visible_message("[R]'s camera lens focuses loudly.", "Your camera lens focuses loudly.")
|
||||
if(WIRE_LOCKDOWN) // Simple lockdown.
|
||||
R.SetLockdown(!mend)
|
||||
if(WIRE_RESET_MODULE)
|
||||
|
||||
@@ -19,21 +19,21 @@
|
||||
switch(wire)
|
||||
if(WIRE_BOOM)
|
||||
if(B.active)
|
||||
holder.visible_message("<span class='danger'>[bicon(B)] An alarm sounds! It's go-</span>")
|
||||
holder.visible_message("<span class='danger'>[icon2html(B, viewers(holder))] An alarm sounds! It's go-</span>")
|
||||
B.explode_now = TRUE
|
||||
tell_admins(B)
|
||||
if(WIRE_UNBOLT)
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] The bolts spin in place for a moment.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] The bolts spin in place for a moment.</span>")
|
||||
if(WIRE_DELAY)
|
||||
if(B.delayedbig)
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] The bomb has already been delayed.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] The bomb has already been delayed.</span>")
|
||||
else
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] The bomb chirps.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] The bomb chirps.</span>")
|
||||
playsound(B, 'sound/machines/chime.ogg', 30, 1)
|
||||
B.detonation_timer += 300
|
||||
B.delayedbig = TRUE
|
||||
if(WIRE_PROCEED)
|
||||
holder.visible_message("<span class='danger'>[bicon(B)] The bomb buzzes ominously!</span>")
|
||||
holder.visible_message("<span class='danger'>[icon2html(B, viewers(holder))] The bomb buzzes ominously!</span>")
|
||||
playsound(B, 'sound/machines/buzz-sigh.ogg', 30, 1)
|
||||
var/seconds = B.seconds_remaining()
|
||||
if(seconds >= 61) // Long fuse bombs can suddenly become more dangerous if you tinker with them.
|
||||
@@ -44,13 +44,13 @@
|
||||
B.detonation_timer = world.time + 100
|
||||
if(WIRE_ACTIVATE)
|
||||
if(!B.active && !B.defused)
|
||||
holder.visible_message("<span class='danger'>[bicon(B)] You hear the bomb start ticking!</span>")
|
||||
holder.visible_message("<span class='danger'>[icon2html(B, viewers(holder))] You hear the bomb start ticking!</span>")
|
||||
B.activate()
|
||||
B.update_icon()
|
||||
else if(B.delayedlittle)
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] Nothing happens.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] Nothing happens.</span>")
|
||||
else
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] The bomb seems to hesitate for a moment.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] The bomb seems to hesitate for a moment.</span>")
|
||||
B.detonation_timer += 100
|
||||
B.delayedlittle = TRUE
|
||||
|
||||
@@ -62,24 +62,24 @@
|
||||
B.defused = FALSE // Cutting and mending all the wires of an inactive bomb will thus cure any sabotage.
|
||||
else
|
||||
if(B.active)
|
||||
holder.visible_message("<span class='danger'>[bicon(B)] An alarm sounds! It's go-</span>")
|
||||
holder.visible_message("<span class='danger'>[icon2html(B, viewers(holder))] An alarm sounds! It's go-</span>")
|
||||
B.explode_now = TRUE
|
||||
tell_admins(B)
|
||||
else
|
||||
B.defused = TRUE
|
||||
if(WIRE_UNBOLT)
|
||||
if(!mend && B.anchored)
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] The bolts lift out of the ground!</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] The bolts lift out of the ground!</span>")
|
||||
playsound(B, 'sound/effects/stealthoff.ogg', 30, 1)
|
||||
B.anchored = FALSE
|
||||
if(WIRE_PROCEED)
|
||||
if(!mend && B.active)
|
||||
holder.visible_message("<span class='danger'>[bicon(B)] An alarm sounds! It's go-</span>")
|
||||
holder.visible_message("<span class='danger'>[icon2html(B, viewers(holder))] An alarm sounds! It's go-</span>")
|
||||
B.explode_now = TRUE
|
||||
tell_admins(B)
|
||||
if(WIRE_ACTIVATE)
|
||||
if(!mend && B.active)
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] The timer stops! The bomb has been defused!</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] The timer stops! The bomb has been defused!</span>")
|
||||
B.active = FALSE
|
||||
B.defused = TRUE
|
||||
B.update_icon()
|
||||
|
||||
+11
-4
@@ -41,7 +41,7 @@
|
||||
var/static_environ
|
||||
|
||||
var/has_gravity = FALSE
|
||||
var/noteleport = FALSE //Are you forbidden from teleporting to the area? (centcomm, mobs, wizard, hand teleporter)
|
||||
var/noteleport = FALSE //Are you forbidden from teleporting to the area? (centcom, mobs, wizard, hand teleporter)
|
||||
var/hidden = FALSE //Hides area from player Teleport function.
|
||||
var/safe = FALSE //Is the area teleport-safe: no space / radiation / aggresive mobs / other dangers
|
||||
|
||||
@@ -338,7 +338,14 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
else
|
||||
icon_state = "blue-red"
|
||||
else
|
||||
icon_state = null
|
||||
var/weather_icon
|
||||
for(var/V in SSweather.existing_weather)
|
||||
var/datum/weather/W = V
|
||||
if(src in W.impacted_areas)
|
||||
W.update_areas()
|
||||
weather_icon = TRUE
|
||||
if(!weather_icon)
|
||||
icon_state = null
|
||||
|
||||
/area/space/updateicon()
|
||||
icon_state = null
|
||||
@@ -432,7 +439,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
// Ambience goes down here -- make sure to list each area separately for ease of adding things in later, thanks! Note: areas adjacent to each other should have the same sounds to prevent cutoff when possible.- LastyScratch
|
||||
if(L.client && !L.client.ambience_playing && L.client.prefs.toggles & SOUND_SHIP_AMBIENCE)
|
||||
L.client.ambience_playing = 1
|
||||
L << sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = CHANNEL_BUZZ)
|
||||
SEND_SOUND(L, sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = CHANNEL_BUZZ))
|
||||
|
||||
if(!(L.client && (L.client.prefs.toggles & SOUND_AMBIENCE)))
|
||||
return //General ambience check is below the ship ambience so one can play without the other
|
||||
@@ -441,7 +448,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
var/sound = pick(ambientsounds)
|
||||
|
||||
if(!L.client.played)
|
||||
L << sound(sound, repeat = 0, wait = 0, volume = 25, channel = CHANNEL_AMBIENCE)
|
||||
SEND_SOUND(L, sound(sound, repeat = 0, wait = 0, volume = 25, channel = CHANNEL_AMBIENCE))
|
||||
L.client.played = 1
|
||||
sleep(600) //ewww - this is very very bad
|
||||
if(L.&& L.client)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
diff a/code/game/area/areas.dm b/code/game/area/areas.dm (rejected hunks)
|
||||
@@ -432,7 +432,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
// Ambience goes down here -- make sure to list each area seperately for ease of adding things in later, thanks! Note: areas adjacent to each other should have the same sounds to prevent cutoff when possible.- LastyScratch
|
||||
if(L.client && !L.client.ambience_playing && L.client.prefs.toggles & SOUND_SHIP_AMBIENCE)
|
||||
L.client.ambience_playing = 1
|
||||
- L << sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = CHANNEL_BUZZ)
|
||||
+ SEND_SOUND(L, sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = CHANNEL_BUZZ))
|
||||
|
||||
if(!(L.client && (L.client.prefs.toggles & SOUND_AMBIENCE)))
|
||||
return //General ambience check is below the ship ambience so one can play without the other
|
||||
@@ -2,7 +2,7 @@
|
||||
// CENTCOM
|
||||
|
||||
/area/centcom
|
||||
name = "Centcom"
|
||||
name = "CentCom"
|
||||
icon_state = "centcom"
|
||||
dynamic_lighting = DYNAMIC_LIGHTING_FORCED
|
||||
requires_power = FALSE
|
||||
@@ -12,16 +12,16 @@
|
||||
flags = NONE
|
||||
|
||||
/area/centcom/control
|
||||
name = "Centcom Docks"
|
||||
name = "CentCom Docks"
|
||||
|
||||
/area/centcom/evac
|
||||
name = "Centcom Recovery Ship"
|
||||
name = "CentCom Recovery Ship"
|
||||
|
||||
/area/centcom/supply
|
||||
name = "Centcom Supply Shuttle Dock"
|
||||
name = "CentCom Supply Shuttle Dock"
|
||||
|
||||
/area/centcom/ferry
|
||||
name = "Centcom Transport Shuttle Dock"
|
||||
name = "CentCom Transport Shuttle Dock"
|
||||
|
||||
/area/centcom/prison
|
||||
name = "Admin Prison"
|
||||
|
||||
+3
-3
@@ -105,7 +105,7 @@
|
||||
/atom/proc/CanPass(atom/movable/mover, turf/target)
|
||||
return !density
|
||||
|
||||
/atom/proc/onCentcom()
|
||||
/atom/proc/onCentCom()
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T)
|
||||
return FALSE
|
||||
@@ -126,7 +126,7 @@
|
||||
if(istype(T.loc, /area/centcom))
|
||||
return TRUE
|
||||
|
||||
//Check for centcomm shuttles
|
||||
//Check for centcom shuttles
|
||||
for(var/A in SSshuttle.mobile)
|
||||
var/obj/docking_port/mobile/M = A
|
||||
if(M.launch_status == ENDGAME_LAUNCHED)
|
||||
@@ -270,7 +270,7 @@
|
||||
f_name = "a "
|
||||
f_name += "<span class='danger'>blood-stained</span> [name]!"
|
||||
|
||||
to_chat(user, "[bicon(src)] That's [f_name]")
|
||||
to_chat(user, "[icon2html(src, user)] That's [f_name]")
|
||||
|
||||
if(desc)
|
||||
to_chat(user, desc)
|
||||
|
||||
@@ -530,7 +530,7 @@
|
||||
/* Stationloving
|
||||
*
|
||||
* A stationloving atom will always teleport back to the station
|
||||
* if it ever leaves the station z-levels or Centcom. It will also,
|
||||
* if it ever leaves the station z-levels or CentCom. It will also,
|
||||
* when Destroy() is called, will teleport to a random turf on the
|
||||
* station.
|
||||
*
|
||||
|
||||
@@ -130,7 +130,7 @@ GLOBAL_LIST_INIT(radiochannels, list(
|
||||
"Medical" = 1355,
|
||||
"Engineering" = 1357,
|
||||
"Security" = 1359,
|
||||
"Centcom" = 1337,
|
||||
"CentCom" = 1337,
|
||||
"Syndicate" = 1213,
|
||||
"Supply" = 1347,
|
||||
"Service" = 1349,
|
||||
@@ -146,7 +146,7 @@ GLOBAL_LIST_INIT(reverseradiochannels, list(
|
||||
"1355" = "Medical",
|
||||
"1357" = "Engineering",
|
||||
"1359" = "Security",
|
||||
"1337" = "Centcom",
|
||||
"1337" = "CentCom",
|
||||
"1213" = "Syndicate",
|
||||
"1347" = "Supply",
|
||||
"1349" = "Service",
|
||||
@@ -292,7 +292,7 @@ GLOBAL_VAR_INIT(RADIO_MAGNETS, "9")
|
||||
|
||||
/datum/signal/proc/debug_print()
|
||||
if (source)
|
||||
. = "signal = {source = '[source]' ([source:x],[source:y],[source:z])\n"
|
||||
. = "signal = {source = '[source]' [COORD(source)]\n"
|
||||
else
|
||||
. = "signal = {source = '[source]' ()\n"
|
||||
for (var/i in data)
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
SSticker.mode.apprentices += M.mind
|
||||
M.mind.special_role = "apprentice"
|
||||
SSticker.mode.update_wiz_icons_added(M.mind)
|
||||
M << sound('sound/effects/magic.ogg')
|
||||
SEND_SOUND(M, sound('sound/effects/magic.ogg'))
|
||||
var/newname = copytext(sanitize(input(M, "You are [wizard_name]'s apprentice. Would you like to change your name to something else?", "Name change", randomname) as null|text),1,MAX_NAME_LEN)
|
||||
if (!newname)
|
||||
newname = randomname
|
||||
|
||||
@@ -97,7 +97,8 @@ GLOBAL_LIST_EMPTY(blobs_legit) //used for win-score calculations, contains only
|
||||
|
||||
send_intercept(1)
|
||||
message_sent = TRUE
|
||||
addtimer(CALLBACK(src, .proc/SendSecondIntercept), 24000)
|
||||
|
||||
sleep(24000) //40 minutes, plus burst_delay*3(minimum of 6 minutes, maximum of 8)
|
||||
/datum/game_mode/blob/proc/SendSecondIntercept()
|
||||
if(!replacementmode)
|
||||
send_intercept(2) //if the blob has been alive this long, it's time to bomb it
|
||||
send_intercept(2) //if the blob has been alive this long, it's time to bomb it
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
if(blob_core)
|
||||
stat(null, "Core Health: [blob_core.obj_integrity]")
|
||||
stat(null, "Power Stored: [blob_points]/[max_blob_points]")
|
||||
if(SSticker && istype(SSticker.mode, /datum/game_mode/blob))
|
||||
if(istype(SSticker.mode, /datum/game_mode/blob))
|
||||
var/datum/game_mode/blob/B = SSticker.mode
|
||||
stat(null, "Blobs to Win: [GLOB.blobs_legit.len]/[B.blobwincount]")
|
||||
else
|
||||
|
||||
@@ -171,11 +171,11 @@
|
||||
if(candidates.len) //if we got at least one candidate, they're a blobbernaut now.
|
||||
var/client/C = pick(candidates)
|
||||
blobber.key = C.key
|
||||
blobber << 'sound/effects/blobattack.ogg'
|
||||
blobber << 'sound/effects/attackblob.ogg'
|
||||
SEND_SOUND(blobber, sound('sound/effects/blobattack.ogg'))
|
||||
SEND_SOUND(blobber, sound('sound/effects/attackblob.ogg'))
|
||||
to_chat(blobber, "<b>You are a blobbernaut!</b>")
|
||||
to_chat(blobber, "You are powerful, hard to kill, and slowly regenerate near nodes and cores, but will slowly die if not near the blob or if the factory that made you is killed.")
|
||||
to_chat(blobber, "You can communicate with other blobbernauts and GLOB.overminds via <b>:b</b>")
|
||||
to_chat(blobber, "You can communicate with other blobbernauts and overminds via <b>:b</b>")
|
||||
to_chat(blobber, "Your overmind's blob reagent is: <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font>!")
|
||||
to_chat(blobber, "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.shortdesc ? "[blob_reagent_datum.shortdesc]" : "[blob_reagent_datum.description]"]")
|
||||
if(blobber)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
diff a/code/game/gamemodes/blob/powers.dm b/code/game/gamemodes/blob/powers.dm (rejected hunks)
|
||||
@@ -175,7 +175,7 @@
|
||||
SEND_SOUND(blobber, sound('sound/effects/attackblob.ogg'))
|
||||
to_chat(blobber, "<b>You are a blobbernaut!</b>")
|
||||
to_chat(blobber, "You are powerful, hard to kill, and slowly regenerate near nodes and cores, but will slowly die if not near the blob or if the factory that made you is killed.")
|
||||
- to_chat(blobber, "You can communicate with other blobbernauts and GLOB.overminds via <b>:b</b>")
|
||||
+ to_chat(blobber, "You can communicate with other blobbernauts and overminds via <b>:b</b>")
|
||||
to_chat(blobber, "Your overmind's blob reagent is: <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font>!")
|
||||
to_chat(blobber, "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.shortdesc ? "[blob_reagent_datum.shortdesc]" : "[blob_reagent_datum.description]"]")
|
||||
if(blobber)
|
||||
@@ -24,6 +24,7 @@
|
||||
M.changeNext_move(CLICK_CD_MELEE)
|
||||
var/a = pick("gently stroke", "nuzzle", "affectionatly pet", "cuddle")
|
||||
M.visible_message("<span class='notice'>[M] [a]s [src]!</span>", "<span class='notice'>You [a] [src]!</span>")
|
||||
to_chat(overmind, "<span class='notice'>[M] [a]s you!</span>")
|
||||
playsound(src, 'sound/effects/blobattack.ogg', 50, 1) //SQUISH SQUISH
|
||||
|
||||
|
||||
@@ -235,7 +236,7 @@
|
||||
if(istype(I, /obj/item/device/analyzer))
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
to_chat(user, "<b>The analyzer beeps once, then reports:</b><br>")
|
||||
user << 'sound/machines/ping.ogg'
|
||||
SEND_SOUND(user, sound('sound/machines/ping.ogg'))
|
||||
chemeffectreport(user)
|
||||
typereport(user)
|
||||
else
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
C.confused += 25
|
||||
C.Jitter(50)
|
||||
else
|
||||
C << sound('sound/effects/screech.ogg')
|
||||
SEND_SOUND(C, sound('sound/effects/screech.ogg'))
|
||||
|
||||
if(issilicon(M))
|
||||
M << sound('sound/weapons/flash.ogg')
|
||||
SEND_SOUND(M, sound('sound/weapons/flash.ogg'))
|
||||
M.Knockdown(rand(100,200))
|
||||
|
||||
for(var/obj/machinery/light/L in range(4, user))
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/sigil/attack_tk(mob/user)
|
||||
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))
|
||||
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>")
|
||||
@@ -81,7 +84,7 @@
|
||||
/obj/effect/clockwork/sigil/submission
|
||||
name = "ominous sigil"
|
||||
desc = "A luminous golden sigil. Something about it really bothers you."
|
||||
clockwork_desc = "A sigil that will enslave the first person to cross it, provided they remain on it for seven seconds."
|
||||
clockwork_desc = "A sigil that will enslave any non-Servant that remains on it for 8 seconds. Cannot penetrate mindshield implants."
|
||||
icon_state = "sigilsubmission"
|
||||
layer = LOW_SIGIL_LAYER
|
||||
alpha = 125
|
||||
@@ -91,17 +94,15 @@
|
||||
light_color = "#FAE48C"
|
||||
stat_affected = UNCONSCIOUS
|
||||
resist_string = "glows faintly yellow"
|
||||
var/convert_time = 70
|
||||
var/convert_time = 80
|
||||
var/delete_on_finish = TRUE
|
||||
sigil_name = "Sigil of Submission"
|
||||
var/glow_type
|
||||
|
||||
/obj/effect/clockwork/sigil/submission/proc/post_channel(mob/living/L)
|
||||
var/glow_type = /obj/effect/temp_visual/ratvar/sigil/submission
|
||||
|
||||
/obj/effect/clockwork/sigil/submission/sigil_effects(mob/living/L)
|
||||
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)
|
||||
animate(src, color = "#AF0AAF", time = convert_time, flags = ANIMATION_END_NOW)
|
||||
var/obj/effect/temp_visual/ratvar/sigil/glow
|
||||
if(glow_type)
|
||||
glow = new glow_type(get_turf(src))
|
||||
@@ -113,16 +114,15 @@
|
||||
if(get_turf(L) != get_turf(src))
|
||||
if(glow)
|
||||
qdel(glow)
|
||||
animate(src, color = oldcolor, time = 20)
|
||||
animate(src, color = oldcolor, time = 20, flags = ANIMATION_END_NOW)
|
||||
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 20)
|
||||
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
|
||||
return
|
||||
post_channel(L)
|
||||
if(is_eligible_servant(L))
|
||||
to_chat(L, "<span class='heavy_brass'>\"You belong to me now.\"</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(60) //Completely defenseless for about five seconds - mainly to give them time to read over the information they've just been presented with
|
||||
L.Knockdown(50) //Completely defenseless for five seconds - mainly to give them time to read over the information they've just been presented with
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
C.silent += 5
|
||||
@@ -136,39 +136,9 @@
|
||||
to_chat(M, "<span class='heavy_brass'>[message] you!</span>")
|
||||
else
|
||||
to_chat(M, "<span class='heavy_brass'>[message] [L.real_name]!</span>")
|
||||
if(delete_on_finish)
|
||||
qdel(src)
|
||||
else
|
||||
animate(src, color = oldcolor, time = 20)
|
||||
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 20)
|
||||
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
|
||||
|
||||
|
||||
//Sigil of Accession: After a short time, converts any non-servant standing on it though implants. Knocks down and silences them for five seconds afterwards.
|
||||
/obj/effect/clockwork/sigil/submission/accession
|
||||
name = "terrifying sigil"
|
||||
desc = "A luminous brassy sigil. Something about it makes you want to flee."
|
||||
clockwork_desc = "A sigil that will enslave any person who crosses it, provided they remain on it for seven seconds. \n\
|
||||
It can convert a mindshielded target once before disppearing, but can convert any number of non-implanted targets."
|
||||
icon_state = "sigiltransgression"
|
||||
alpha = 200
|
||||
color = "#A97F1B"
|
||||
light_range = 3 //bright light
|
||||
light_power = 1
|
||||
light_color = "#A97F1B"
|
||||
delete_on_finish = FALSE
|
||||
sigil_name = "Sigil of Accession"
|
||||
glow_type = /obj/effect/temp_visual/ratvar/sigil/accession
|
||||
resist_string = "glows bright orange"
|
||||
|
||||
/obj/effect/clockwork/sigil/submission/accession/post_channel(mob/living/L)
|
||||
if(L.isloyal())
|
||||
L.log_message("<font color=#BE8700>Had their mindshield implant broken by a [sigil_name].</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
delete_on_finish = TRUE
|
||||
L.visible_message("<span class='warning'>[L] visibly trembles!</span>", \
|
||||
"<span class='sevtug'>[text2ratvar("You will be mine and his. This puny trinket will not stop me.")]</span>")
|
||||
for(var/obj/item/weapon/implant/mindshield/M in L.implants)
|
||||
qdel(M)
|
||||
animate(src, color = oldcolor, time = 20, flags = ANIMATION_END_NOW)
|
||||
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 20)
|
||||
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
|
||||
|
||||
|
||||
//Sigil of Transmission: Stores power for clockwork machinery, serving as a battery.
|
||||
@@ -326,8 +296,7 @@
|
||||
stat_affected = DEAD
|
||||
resist_string = "glows shimmering yellow"
|
||||
sigil_name = "Vitality Matrix"
|
||||
var/static/vitality = 0
|
||||
var/base_revive_cost = 20
|
||||
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
|
||||
var/static/list/damage_heal_order = list(CLONE, TOX, BURN, BRUTE, OXY) //we heal damage in this order
|
||||
@@ -335,11 +304,11 @@
|
||||
/obj/effect/clockwork/sigil/vitality/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
to_chat(user, "<span class='[vitality ? "inathneq_small":"alloy"]'>It has access to <b>[GLOB.ratvar_awakens ? "INFINITE":"[vitality]"]</b> units of vitality.</span>")
|
||||
to_chat(user, "<span class='[GLOB.clockwork_vitality ? "inathneq_small":"alloy"]'>It has access to <b>[GLOB.ratvar_awakens ? "INFINITE":GLOB.clockwork_vitality]</b> units of vitality.</span>")
|
||||
if(GLOB.ratvar_awakens)
|
||||
to_chat(user, "<span class='inathneq_small'>It can revive Servants at no cost!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='inathneq_small'>It can revive Servants at a cost of <b>[base_revive_cost]</b> vitality plus vitality equal to the non-oxygen damage they have, in addition to being destroyed in the process.</span>")
|
||||
to_chat(user, "<span class='inathneq_small'>It can revive Servants at a cost of <b>[revive_cost]</b> vitality.</span>")
|
||||
|
||||
/obj/effect/clockwork/sigil/vitality/sigil_effects(mob/living/L)
|
||||
if((is_servant_of_ratvar(L) && L.suiciding) || sigil_active)
|
||||
@@ -348,7 +317,7 @@
|
||||
animate(src, alpha = 255, time = 10, flags = ANIMATION_END_NOW) //we may have a previous animation going. finish it first, then do this one without delay.
|
||||
sleep(10)
|
||||
//as long as they're still on the sigil and are either not a servant or they're a servant AND it has remaining vitality
|
||||
while(L && (!is_servant_of_ratvar(L) || (is_servant_of_ratvar(L) && (GLOB.ratvar_awakens || vitality))) && get_turf(L) == get_turf(src))
|
||||
while(L && (!is_servant_of_ratvar(L) || (is_servant_of_ratvar(L) && (GLOB.ratvar_awakens || GLOB.clockwork_vitality))) && get_turf(L) == get_turf(src))
|
||||
sigil_active = TRUE
|
||||
if(animation_number >= 4)
|
||||
new /obj/effect/temp_visual/ratvar/sigil/vitality(get_turf(src))
|
||||
@@ -373,40 +342,37 @@
|
||||
else
|
||||
vitality_drained = L.adjustToxLoss(1.5)
|
||||
if(vitality_drained)
|
||||
vitality += vitality_drained
|
||||
GLOB.clockwork_vitality += vitality_drained
|
||||
else
|
||||
break
|
||||
else
|
||||
if(L.stat == DEAD)
|
||||
var/revival_cost = base_revive_cost + L.getCloneLoss() + L.getToxLoss() + L.getFireLoss() + L.getBruteLoss() //ignores oxygen damage
|
||||
var/revival_cost = revive_cost
|
||||
if(GLOB.ratvar_awakens)
|
||||
revival_cost = 0
|
||||
var/mob/dead/observer/ghost = L.get_ghost(TRUE)
|
||||
if(vitality >= revival_cost && (ghost || (L.mind && L.mind.active)))
|
||||
if(GLOB.clockwork_vitality >= revival_cost && (ghost || (L.mind && L.mind.active)))
|
||||
if(ghost)
|
||||
ghost.reenter_corpse()
|
||||
L.revive(1, 1)
|
||||
var/obj/effect/temp_visual/ratvar/sigil/vitality/V = new /obj/effect/temp_visual/ratvar/sigil/vitality(get_turf(src))
|
||||
animate(V, alpha = 0, transform = matrix()*2, time = 8)
|
||||
playsound(L, 'sound/magic/staff_healing.ogg', 50, 1)
|
||||
L.visible_message("<span class='warning'>[L] suddenly gets back up, [GLOB.ratvar_awakens ? "[L.p_their()] body dripping blue ichor":"even as [src] scatters into blue sparks around [L.p_them()]"]!</span>", \
|
||||
"<span class='inathneq'>\"[text2ratvar("You will be okay, child.")]\"</span>")
|
||||
vitality -= revival_cost
|
||||
if(!GLOB.ratvar_awakens)
|
||||
qdel(src)
|
||||
L.visible_message("<span class='warning'>[L] suddenly gets back up, [L.p_their()] body dripping blue ichor!</span>", "<span class='inathneq'>\"[text2ratvar("You will be okay, child.")]\"</span>")
|
||||
GLOB.clockwork_vitality -= revival_cost
|
||||
break
|
||||
var/vitality_for_cycle = 3
|
||||
if(!GLOB.ratvar_awakens)
|
||||
if(L.stat == CONSCIOUS)
|
||||
vitality_for_cycle = 2
|
||||
vitality_for_cycle = min(vitality, vitality_for_cycle)
|
||||
vitality_for_cycle = min(GLOB.clockwork_vitality, vitality_for_cycle)
|
||||
var/vitality_used = L.heal_ordered_damage(vitality_for_cycle, damage_heal_order)
|
||||
|
||||
if(!vitality_used)
|
||||
break
|
||||
|
||||
if(!GLOB.ratvar_awakens)
|
||||
vitality -= vitality_used
|
||||
GLOB.clockwork_vitality -= vitality_used
|
||||
|
||||
sleep(2)
|
||||
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
//horrifying power drain proc made for clockcult's power drain in lieu of six istypes or six for(x in view) loops
|
||||
/atom/movable/proc/power_drain(clockcult_user)
|
||||
var/obj/item/weapon/stock_parts/cell/cell = get_cell()
|
||||
if(cell)
|
||||
return cell.power_drain(clockcult_user)
|
||||
return 0
|
||||
|
||||
/obj/item/weapon/melee/baton/power_drain(clockcult_user) //balance memes
|
||||
return 0
|
||||
|
||||
/obj/item/weapon/gun/power_drain(clockcult_user) //balance memes
|
||||
return 0
|
||||
|
||||
/obj/machinery/power/apc/power_drain(clockcult_user)
|
||||
|
||||
@@ -24,11 +24,15 @@
|
||||
//For the Geis scripture; binds a target to convert.
|
||||
/obj/effect/proc_holder/slab/geis
|
||||
ranged_mousepointer = 'icons/effects/geis_target.dmi'
|
||||
var/obj/structure/destructible/clockwork/geis_binding/binding //we always have a reference to the binding
|
||||
var/obj/structure/destructible/clockwork/geis_binding/pulled_binding //we use this to see if we're pulling it or not
|
||||
|
||||
/obj/effect/proc_holder/slab/geis/remove_ranged_ability(msg)
|
||||
..()
|
||||
binding = null
|
||||
pulled_binding = null
|
||||
|
||||
/obj/effect/proc_holder/slab/geis/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
var/turf/T = ranged_ability_user.loc
|
||||
if(!isturf(T))
|
||||
return TRUE
|
||||
@@ -36,6 +40,20 @@
|
||||
var/target_is_binding = istype(target, /obj/structure/destructible/clockwork/geis_binding)
|
||||
|
||||
if((target_is_binding || isliving(target)) && ranged_ability_user.Adjacent(target))
|
||||
if(in_progress || ..())
|
||||
var/mob/living/L = target
|
||||
if(!pulled_binding)
|
||||
if(target == binding || (isliving(target) && L.buckled == binding))
|
||||
pulled_binding = binding
|
||||
ranged_ability_user.start_pulling(binding)
|
||||
remove_mousepointer(ranged_ability_user.client)
|
||||
ranged_mousepointer = 'icons/effects/geis_target_remove.dmi'
|
||||
add_mousepointer(ranged_ability_user.client)
|
||||
else if(target == pulled_binding || (isliving(target) && L.buckled == pulled_binding))
|
||||
ranged_ability_user.visible_message("<span class='warning'>[ranged_ability_user] dispels [pulled_binding]!</span>", "<span class='danger'>You dispel the binding!</span>")
|
||||
binding.take_damage(obj_integrity)
|
||||
remove_ranged_ability()
|
||||
return TRUE
|
||||
if(target_is_binding)
|
||||
var/obj/structure/destructible/clockwork/geis_binding/GB = target
|
||||
GB.repair_and_interrupt()
|
||||
@@ -65,19 +83,44 @@
|
||||
in_progress = TRUE
|
||||
clockwork_say(ranged_ability_user, text2ratvar("Be bound, heathen!"))
|
||||
remove_mousepointer(ranged_ability_user.client)
|
||||
ranged_mousepointer = 'icons/effects/geis_target_remove.dmi'
|
||||
add_mousepointer(ranged_ability_user.client)
|
||||
add_logs(ranged_ability_user, L, "bound with Geis")
|
||||
playsound(target, 'sound/magic/blink.ogg', 50, TRUE, 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), 5) //stop us moving for a little bit so we don't break the scripture following this
|
||||
slab.busy = null
|
||||
var/datum/clockwork_scripture/geis/conversion = new
|
||||
conversion.slab = slab
|
||||
conversion.invoker = ranged_ability_user
|
||||
conversion.target = target
|
||||
conversion.run_scripture()
|
||||
addtimer(CALLBACK(src, .proc/reset_user_notransform, ranged_ability_user), 5) //stop us moving for a little bit so we don't break the binding immediately
|
||||
if(L.buckled)
|
||||
L.buckled.unbuckle_mob(target, TRUE)
|
||||
binding = new(get_turf(target))
|
||||
binding.setDir(target.dir)
|
||||
binding.buckle_mob(target, TRUE)
|
||||
pulled_binding = binding
|
||||
ranged_ability_user.start_pulling(binding)
|
||||
slab.busy = "sustaining Geis"
|
||||
slab.flags |= NODROP
|
||||
while(!QDELETED(binding) && !QDELETED(ranged_ability_user))
|
||||
if(ranged_ability_user.pulling == binding)
|
||||
pulled_binding = binding
|
||||
if(ranged_ability_user.client && ranged_ability_user.client.mouse_pointer_icon == 'icons/effects/geis_target.dmi')
|
||||
remove_mousepointer(ranged_ability_user.client)
|
||||
ranged_mousepointer = 'icons/effects/geis_target_remove.dmi'
|
||||
add_mousepointer(ranged_ability_user.client)
|
||||
else //if we're not pulling it, swap our mousepointer
|
||||
pulled_binding = null
|
||||
if(ranged_ability_user.client && ranged_ability_user.client.mouse_pointer_icon == 'icons/effects/geis_target_remove.dmi')
|
||||
remove_mousepointer(ranged_ability_user.client)
|
||||
ranged_mousepointer = 'icons/effects/geis_target.dmi'
|
||||
add_mousepointer(ranged_ability_user.client)
|
||||
sleep(1)
|
||||
if(!QDELETED(slab))
|
||||
slab.flags &= ~NODROP
|
||||
in_progress = FALSE
|
||||
successful = TRUE
|
||||
|
||||
remove_ranged_ability()
|
||||
else
|
||||
..()
|
||||
|
||||
return TRUE
|
||||
|
||||
@@ -145,29 +188,6 @@
|
||||
|
||||
return TRUE
|
||||
|
||||
//For the Volt Void scripture, fires a ray of energy at a target location
|
||||
/obj/effect/proc_holder/slab/volt
|
||||
ranged_mousepointer = 'icons/effects/volt_target.dmi'
|
||||
|
||||
/obj/effect/proc_holder/slab/volt/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(target == slab || ..()) //we can't cancel
|
||||
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
|
||||
ranged_ability_user.visible_message("<span class='warning'>[ranged_ability_user] fires a ray of energy at [target]!</span>", "<span class='nzcrentr'>You fire a volt ray at [target].</span>")
|
||||
playsound(ranged_ability_user, 'sound/effects/light_flicker.ogg', 50, 1)
|
||||
T = get_turf(target)
|
||||
new/obj/effect/temp_visual/ratvar/volt_hit(T, ranged_ability_user)
|
||||
add_logs(ranged_ability_user, T, "fired a volt ray")
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
|
||||
//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'
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
var/selected_scripture = SCRIPTURE_DRIVER
|
||||
var/recollecting = FALSE //if we're looking at fancy recollection
|
||||
var/obj/effect/proc_holder/slab/slab_ability //the slab's current bound ability, for certain scripture
|
||||
var/list/quickbound = list(/datum/clockwork_scripture/ranged_ability/geis_prep, /datum/clockwork_scripture/create_object/replicant, \
|
||||
/datum/clockwork_scripture/create_object/tinkerers_cache) //quickbound scripture, accessed by index
|
||||
var/list/quickbound = list(/datum/clockwork_scripture/ranged_ability/geis, /datum/clockwork_scripture/create_object/sigil_of_submission, \
|
||||
/datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/tinkerers_cache) //quickbound scripture, accessed by index
|
||||
var/maximum_quickbound = 5 //how many quickbound scriptures we can have
|
||||
var/recollection_category = "Default"
|
||||
actions_types = list(/datum/action/item_action/clock/hierophant)
|
||||
@@ -53,21 +53,18 @@
|
||||
maximum_quickbound = 6 //we usually have one or two unique scriptures, so if ratvar is up let us bind one more
|
||||
actions_types = list()
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/engineer //four scriptures, plus a fabricator
|
||||
quickbound = list(/datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/cogscarab, \
|
||||
/datum/clockwork_scripture/create_object/soul_vessel, /datum/clockwork_scripture/create_object/sigil_of_transmission)
|
||||
/obj/item/clockwork/slab/cyborg/engineer //two scriptures, plus a fabricator
|
||||
quickbound = list(/datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/sigil_of_transmission)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/medical //five scriptures, plus a spear
|
||||
quickbound = list(/datum/clockwork_scripture/ranged_ability/linked_vanguard, /datum/clockwork_scripture/ranged_ability/sentinels_compromise, \
|
||||
/datum/clockwork_scripture/create_object/vitality_matrix, /datum/clockwork_scripture/channeled/mending_mantra, /datum/clockwork_scripture/fellowship_armory)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/security //four scriptures, plus a spear
|
||||
quickbound = list(/datum/clockwork_scripture/channeled/belligerent, /datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/channeled/taunting_tirade, \
|
||||
/datum/clockwork_scripture/channeled/volt_blaster)
|
||||
/obj/item/clockwork/slab/cyborg/security //twoscriptures, plus a spear
|
||||
quickbound = list(/datum/clockwork_scripture/channeled/belligerent, /datum/clockwork_scripture/ranged_ability/judicial_marker)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/peacekeeper //four scriptures, plus a spear
|
||||
quickbound = list(/datum/clockwork_scripture/channeled/belligerent, /datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/channeled/taunting_tirade, \
|
||||
/datum/clockwork_scripture/channeled/volt_blaster)
|
||||
/obj/item/clockwork/slab/cyborg/peacekeeper //two scriptures, plus a spear
|
||||
quickbound = list(/datum/clockwork_scripture/channeled/belligerent, /datum/clockwork_scripture/ranged_ability/judicial_marker)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/janitor //five scriptures, plus a fabricator
|
||||
quickbound = list(/datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/sigil_of_transgression, \
|
||||
@@ -77,8 +74,8 @@
|
||||
quickbound = list(/datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/tinkerers_cache, \
|
||||
/datum/clockwork_scripture/spatial_gateway, /datum/clockwork_scripture/fellowship_armory, /datum/clockwork_scripture/create_object/clockwork_obelisk)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/miner //three scriptures, plus a spear and xray vision
|
||||
quickbound = list(/datum/clockwork_scripture/ranged_ability/linked_vanguard, /datum/clockwork_scripture/spatial_gateway, /datum/clockwork_scripture/channeled/volt_blaster)
|
||||
/obj/item/clockwork/slab/cyborg/miner //two scriptures, plus a spear and xray vision
|
||||
quickbound = list(/datum/clockwork_scripture/ranged_ability/linked_vanguard, /datum/clockwork_scripture/spatial_gateway)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/access_display(mob/living/user)
|
||||
if(!GLOB.ratvar_awakens)
|
||||
@@ -136,7 +133,7 @@
|
||||
production_time = world.time + SLAB_PRODUCTION_TIME + production_slowdown
|
||||
var/mob/living/L
|
||||
L = get_atom_on_turf(src, /mob/living)
|
||||
if(istype(L) && can_recite_scripture(L))
|
||||
if(istype(L) && (no_cost || can_recite_scripture(L)))
|
||||
var/component_to_generate = target_component_id
|
||||
if(!component_to_generate)
|
||||
component_to_generate = get_weighted_component_id(src) //more likely to generate components that we have less of
|
||||
@@ -267,7 +264,7 @@
|
||||
if(busy)
|
||||
to_chat(user, "<span class='warning'>[src] refuses to work, displaying the message: \"[busy]!\"</span>")
|
||||
return 0
|
||||
if(!can_recite_scripture(user))
|
||||
if(!no_cost && !can_recite_scripture(user))
|
||||
to_chat(user, "<span class='nezbere'>[src] hums fitfully in your hands, but doesn't seem to do anything...</span>")
|
||||
return 0
|
||||
access_display(user)
|
||||
@@ -287,7 +284,7 @@
|
||||
ui.open()
|
||||
|
||||
/obj/item/clockwork/slab/proc/recite_scripture(datum/clockwork_scripture/scripture, mob/living/user)
|
||||
if(!scripture || !user || !user.canUseTopic(src) || !can_recite_scripture(user))
|
||||
if(!scripture || !user || !user.canUseTopic(src) || (!no_cost && !can_recite_scripture(user)))
|
||||
return FALSE
|
||||
if(user.get_active_held_item() != src)
|
||||
to_chat(user, "<span class='warning'>You need to hold the slab in your active hand to recite scripture!</span>")
|
||||
@@ -403,24 +400,21 @@
|
||||
dat += "<font color=#BE8700><b>Servant:</b></font> A person or robot who serves Ratvar. You are one of these.<br>"
|
||||
dat += "<font color=#BE8700><b>Cache:</b></font> A <i>Tinkerer's Cache</i>, which is a structure that stores and creates components.<br>"
|
||||
dat += "<font color=#BE8700><b>CV:</b></font> Construction Value. All clockwork structures, floors, and walls increase this number.<br>"
|
||||
dat += "<font color=#BE8700><b>Vitality:</b></font> Used for healing effects, produced by Ratvarian spear attacks and Vitality Matrices.<br>"
|
||||
dat += "<font color=#BE8700><b>Geis:</b></font> An important scripture used to make normal crew and robots into Servants of Ratvar.<br>"
|
||||
dat += "<font color=#6E001A><b>[get_component_icon(BELLIGERENT_EYE)]BE:</b></font> Belligerent Eye, a component type used in offensive scriptures.<br>"
|
||||
dat += "<font color=#1E8CE1><b>[get_component_icon(VANGUARD_COGWHEEL)]VC:</b></font> Vanguard Cogwheel, a component type used in defensive scriptures.<br>"
|
||||
dat += "<font color=#AF0AAF><b>[get_component_icon(GEIS_CAPACITOR)]GC:</b></font> Geis Capacitor, a component type used in mind-related scriptures.<br>"
|
||||
dat += "<font color=#5A6068><b>[get_component_icon(REPLICANT_ALLOY)]RA:</b></font> Replicant Alloy, a component type used in construction scriptures.<br>"
|
||||
dat += "<font color=#DAAA18><b>[get_component_icon(HIEROPHANT_ANSIBLE)]HA:</b></font> Hierophant Ansible, a component type used in energy scriptures.<br>"
|
||||
dat += "<font color=#DAAA18><b>[get_component_icon(HIEROPHANT_ANSIBLE)]HA:</b></font> Hierophant Ansible, a component type used in energy-related scriptures.<br>"
|
||||
dat += "<font color=#BE8700><b>Ark:</b></font> The cult's win condition, a huge structure that needs to be defended.<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>Items</font><br>"
|
||||
dat += "<font color=#BE8700><b>Slab:</b></font> A clockwork slab, a Servant's most important tool. You're holding one! Keep it safe and hidden.<br>"
|
||||
dat += "<font color=#BE8700><b>Visor:</b></font> A judicial visor, which is a pair of glasses that can stun everything in an area after a delay.<br>"
|
||||
dat += "<font color=#BE8700><b>Visor:</b></font> A judicial visor, which is a pair of glasses that can smite an area for a brief stun and delayed explosion.<br>"
|
||||
dat += "<font color=#BE8700><b>Wraith Specs:</b></font> Wraith spectacles, which provide true sight (x-ray, night vision) but damage the wearer's eyes.<br>"
|
||||
dat += "<font color=#BE8700><b>Spear:</b></font> A Ratvarian spear, which is a very powerful melee weapon.<br>"
|
||||
dat += "<font color=#BE8700><b>Spear:</b></font> A Ratvarian spear, which is a very powerful melee weapon that produces Vitality.<br>"
|
||||
dat += "<font color=#BE8700><b>Fabricator:</b></font> A replica fabricator, which converts objects into clockwork versions.<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>Constructs</font><br>"
|
||||
dat += "<font color=#BE8700><b>Vessel:</b></font> A soul vessel, a clockwork brain used to activate constructs.<br>"
|
||||
dat += "<font color=#BE8700><b>Shell:</b></font> A construct shell of some type that can accept a soul vessel to activate.<br>"
|
||||
dat += "<font color=#BE8700><b>Scarab:</b></font> A cogscarab construct, which is a drone that maintains the cult's bases.<br>"
|
||||
dat += "<font color=#BE8700><b>Fragment:</b></font> An anim[prob(1) ? "e" : "a"] fragment, which is a fragile but powerful offensive construct.<br>"
|
||||
dat += "<font color=#BE8700><b>Marauder:</b></font> A clockwork marauder, which is a powerful bodyguard that hides in its owner.<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>Structures (* = requires power)</font><br>"
|
||||
dat += "<font color=#BE8700><b>Warden:</b></font> An ocular warden, which is a ranged turret that damages non-Servants that see it.<br>"
|
||||
@@ -432,8 +426,9 @@
|
||||
dat += "<i>Note: Sigils can be stacked on top of one another, making certain sigils very effective when paired!</i><br>"
|
||||
dat += "<font color=#BE8700><b>Transgression:</b></font> Stuns the first non-Servant to cross it for ten seconds and blinds others nearby. Disappears on use.<br>"
|
||||
dat += "<font color=#BE8700><b>Submission:</b></font> Converts the first non-Servant to stand on the sigil for seven seconds. Disappears on use.<br>"
|
||||
dat += "<font color=#BE8700><b>Matrix:</b></font> Drains health from non-Servants, producing Vitality. Can heal and revive Servants.<br>"
|
||||
dat += "<font color=#BE8700><b>Accession:</b></font> Identical to the Sigil of Submission, but doesn't disappear on use. It can also convert a single mindshielded target, but will disappear after doing this.<br>"
|
||||
dat += "<font color=#BE8700><b>Transmission:</b></font> Drains and stores power for clockwork structures. Feeding it brass sheets will create power.<br><br>"
|
||||
dat += "<font color=#BE8700><b>Transmission:</b></font> Drains and stores power for clockwork structures. Feeding it brass sheets will create additional power.<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
|
||||
if("Components")
|
||||
var/servants = 0 //Calculate the current production time for slab components
|
||||
@@ -465,7 +460,7 @@
|
||||
dat += "<b>Components</b> are your primary resource as a Servant. There are five types of component, with each one being used in different roles:<br><br>"
|
||||
dat += "<font color=#6E001A>[get_component_icon(BELLIGERENT_EYE)]BE</font> Belligerent Eyes are aggressive and judgemental, and are used in offensive scripture;<br>"
|
||||
dat += "<font color=#1E8CE1>[get_component_icon(VANGUARD_COGWHEEL)]VC</font> Vanguard Cogwheels are defensive and repairing, and are used in defensive scripture;<br>"
|
||||
dat += "<font color=#AF0AAF>[get_component_icon(GEIS_CAPACITOR)]GC</font> Geis Capacitors are for conversion and control, and are used in mind-related scripture;<br>" //References the old name
|
||||
dat += "<font color=#AF0AAF>[get_component_icon(GEIS_CAPACITOR)]GC</font> Geis Capacitors are for conversion and control, and are used in mind-related scripture;<br>"
|
||||
dat += "<font color=#5A6068>[get_component_icon(REPLICANT_ALLOY)]RA</font> Replicant Alloy is a strong, malleable metal and is used for construction and creation;<br>"
|
||||
dat += "<font color=#DAAA18>[get_component_icon(HIEROPHANT_ANSIBLE)]HA</font> Hierophant Ansibles are for transmission and power, and are used in power and teleportation scripture<br><br>"
|
||||
dat += "Although this is a good rule of thumb, their effects become much more nuanced when used together. For instance, a turret might have both belligerent eyes and \
|
||||
@@ -503,8 +498,8 @@
|
||||
and can be harnessed in several ways.<br><br>"
|
||||
dat += "To begin with, if there is no other source of power nearby, structures will draw from the area's APC, assuming it has one. This is inefficient and ill-advised as \
|
||||
anything but a last resort. Instead, it is recommended that a <b>Sigil of Transmission</b> is created. This sigil serves as both battery and power generator for nearby clockwork \
|
||||
structures, and those structures will happily draw power from the sigil before they resort to pathetic APCs and other sources of energy.<br><br>"
|
||||
dat += "The most reliable and efficient way to generate power is by using brass sheets; attacking a sigil of transmission with brass sheets will convert them \
|
||||
structures, and those structures will happily draw power from the sigil before they resort to APCs.<br><br>"
|
||||
dat += "Generating power is less easy. The most reliable and efficient way is using brass sheets; attacking a sigil of transmission with brass sheets will convert them \
|
||||
to power, at a rate of <b>[POWER_FLOOR]W</b> per sheet. (Brass sheets are created from replica fabricators, which are explained more in detail in the <b>Conversion</b> section.) \
|
||||
Activating a sigil of transmission will also cause it to drain power from the nearby area, which, while effective, serves as an obvious tell that there is something wrong.<br><br>"
|
||||
dat += "Without power, many structures will not function, making a base vulnerable to attack. For this reason, it is critical that you keep an eye on your power reserves and \
|
||||
@@ -516,15 +511,15 @@
|
||||
they become a full-fledged Servant, ready and willing to serve the cause of Ratvar. It should also be noted that <i>silicon crew, such as cyborgs and the AI, can be \
|
||||
converted just like normal crew</i> and will gain special abilities; this is covered later. This section will also cover converting the station's structure itself; walls, \
|
||||
floors, windows, tables, and other objects can all be converted into clockwork versions, and serve an important purpose.<br><br>"
|
||||
dat += "<font color=#BE8700><b>Methods of Conversion:</b></font> There are several ways to convert humans and silicons. The first and most readily-available of these is \
|
||||
<b>Geis</b>, a Driver-tier scripture. Using it whispers an invocation very quickly - this is incredibly obvious - and charges your slab with power. In addition to <i>making \
|
||||
the slab visible in your hand,</i> you can now use it on a target within melee range to bind them and begin converting them. While there are six or fewer Servants, they are \
|
||||
unable to escape this binding, meaning that unless you are interrupted, the target is as good as yours. However, the scripture becomes slower for every Servant human or \
|
||||
silicon Servant past [SCRIPT_SERVANT_REQ], and the bindings can be resisted past this, meaning that eventually other methods become more desirable.<br><br>"
|
||||
dat += "The other three methods of conversion are the <b>sigils of submission and accession</b>, whose purpose is to do so, and the <b>mania motor.</b> The sigil of \
|
||||
submission is a sigil that, when stood on by a non-Servant for seven full seconds, will convert that non-Servant. This time requirement does not scale with \
|
||||
Servants, making it the preferred option after Geis becomes too inefficient. It is, however, consumed after use; the sigil of accession solves this problem, and serves as a \
|
||||
permanent conversion sigil. The mania motor is generally unreliable, only converting those who stand near it for an extended period.<br><br>"
|
||||
dat += "<font color=#BE8700><b>A Note on Geis:</b></font> There are several ways to convert humans and silicons. However, the most important tool to making them work is \
|
||||
<b>Geis</b>, a Driver-tier scripture. Using it whispers an invocation very quickly and charges your slab with power. In addition to <i>making the slab visible in your hand,</i> \
|
||||
you can now use it on a target within melee range to bind and mute them. It is by far your most reliable tool for capturing potential converts and targets, though it is incredibly \
|
||||
obvious. In addition, you are unable to take any actions other than moving while your target is bound. The binding will last for 25 seconds and mute for about 13 seconds, though \
|
||||
allies can use Geis to refresh these effects.<br><br>"
|
||||
dat += "<font color=#BE8700><b>Converting:</b></font> The two methods of conversion are the <b>sigil of submission</b>, whose purpose is to do so, and the <b>mania motor.</b> \
|
||||
The sigil of submission is a sigil that, when stood on by a non-Servant for eight seconds, will convert that non-Servant. This is the only practical way to convert targets. \
|
||||
Sigils of submission are cheap, early, and permanent! Make sure sigils of submission are placed only in bases or otherwise hidden spots, or with a sigil of transgression on them. \
|
||||
The mania motor, however, is generally unreliable and unlocked later, only converting those who stand near it for an extended period.<br><br>"
|
||||
dat += "<font color=#BE8700><b>Converting Humans:</b></font> For obvious reasons, humans are the most common conversion target. Because every crew member is different, and \
|
||||
may be armed with different equipment, you should take precautions to ensure that they aren't able to resist. If able, removing a headset is essential, as is restraining \
|
||||
them through handcuffs, cable ties, or other restraints. Some crew, like security, are also implanted with mindshield implants; these will prevent conversion and must be \
|
||||
@@ -532,9 +527,8 @@
|
||||
begins administering mindshield implants, this will greatly inhibit conversion. Also note that mindshield implants can be broken by a sigil of accession automatically, but \
|
||||
the sigil will disappear.<br><br>"
|
||||
dat += "<font color=#BE8700><b>Converting Silicons:</b></font> Due to their robotic nature, silicons are generally more predictable than humans in terms of conversion. \
|
||||
However, they are also much, much harder to subdue, especially cyborgs. The easiest way to convert a cyborg is by using a flash or a sigil of transgression to stun it, \
|
||||
then very quickly using Geis to restrain them. If you stack a sigil of transgression and one of the conversion sigils, a crossing cyborg will be stunned and helpless to \
|
||||
escape in time before the other sigil converts them.<br><br>"
|
||||
However, they are also much, much harder to subdue, especially cyborgs. The easiest way to convert a cyborg is by using Geis to restrain them, then dragging them to a sigil \
|
||||
of submission. If you stack a sigil of transgression and a sigil of submission, a crossing cyborg will be stunned and helpless to escape before they are converted.<br><br>"
|
||||
dat += "Converting AIs is very often the hardest task of the cult, and has been the downfall of countless successful Servants. Their omnipresence across the station, \
|
||||
coupled with their secure location and ability to lock themselves securely, makes them a powerful target. However, once the AI itself is reached, it is usually completely \
|
||||
helpless to resist its own conversion. A very common tactic is to take advantage of a converted cyborg to rush the AI before it is able to react.<br><br>"
|
||||
|
||||
@@ -145,7 +145,7 @@
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//Judicial marker: Created by the judicial visor. After three seconds, knocks down any non-Servants nearby and damages Nar-Sian cultists.
|
||||
//Judicial marker: Created by the judicial visor. Immediately applies Belligerent and briefly knocks down, then after 3 seconds does large damage and briefly knocks down again
|
||||
/obj/effect/clockwork/judicial_marker
|
||||
name = "judicial marker"
|
||||
desc = "You get the feeling that you shouldn't be standing here."
|
||||
@@ -165,11 +165,18 @@
|
||||
/obj/effect/clockwork/judicial_marker/proc/judicialblast()
|
||||
playsound(src, 'sound/magic/magic_missile.ogg', 50, 1, 1, 1)
|
||||
flick("judicial_marker", src)
|
||||
for(var/mob/living/carbon/C in range(1, src))
|
||||
var/datum/status_effect/belligerent/B = C.apply_status_effect(STATUS_EFFECT_BELLIGERENT)
|
||||
if(!QDELETED(B))
|
||||
B.duration = world.time + 30
|
||||
C.Knockdown(5) //knocks down for half a second if affected
|
||||
sleep(16)
|
||||
name = "judicial blast"
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
flick("judicial_explosion", src)
|
||||
set_light(1.4, 2, "#B451A1")
|
||||
sleep(13)
|
||||
name = "judicial explosion"
|
||||
var/targetsjudged = 0
|
||||
playsound(src, 'sound/effects/explosionfar.ogg', 100, 1, 1, 1)
|
||||
set_light(0)
|
||||
@@ -181,21 +188,19 @@
|
||||
L.visible_message("<span class='warning'>Strange energy flows into [L]'s [I.name]!</span>", \
|
||||
"<span class='userdanger'>Your [I.name] shields you from [src]!</span>")
|
||||
continue
|
||||
L.Knockdown(15) //knocks down briefly when exploding
|
||||
if(!iscultist(L))
|
||||
L.visible_message("<span class='warning'>[L] is struck by a judicial explosion!</span>", \
|
||||
"<span class='userdanger'>[!issilicon(L) ? "An unseen force slams you into the ground!" : "ERROR: Motor servos disabled by external source!"]</span>")
|
||||
L.Knockdown(160) //knocks down targets for 14-16 seconds
|
||||
else
|
||||
L.visible_message("<span class='warning'>[L] is struck by a judicial explosion!</span>", \
|
||||
"<span class='heavy_brass'>\"Keep an eye out, filth.\"</span>\n<span class='userdanger'>A burst of heat crushes you against the ground!</span>")
|
||||
L.Knockdown(80) //knocks down for 6-8 seconds, but set cultist targets on fire
|
||||
L.adjust_fire_stacks(2)
|
||||
L.adjust_fire_stacks(2) //sets cultist targets on fire
|
||||
L.IgniteMob()
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
C.silent += 6
|
||||
L.adjustFireLoss(5)
|
||||
targetsjudged++
|
||||
L.adjustBruteLoss(10) //do a small amount of damage
|
||||
if(!QDELETED(L))
|
||||
L.adjustBruteLoss(20) //does a decent amount of damage
|
||||
add_logs(user, L, "struck with a judicial blast")
|
||||
to_chat(user, "<span class='brass'><b>[targetsjudged ? "Successfully judged <span class='neovgre'>[targetsjudged]</span>":"Judged no"] heretic[targetsjudged == 1 ? "":"s"].</b></span>")
|
||||
sleep(3) //so the animation completes properly
|
||||
|
||||
@@ -6,14 +6,16 @@
|
||||
icon = 'icons/obj/clockwork_objects.dmi'
|
||||
icon_state = "ratvarian_spear"
|
||||
item_state = "ratvarian_spear"
|
||||
lefthand_file = 'icons/mob/inhands/antag/clockwork_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/clockwork_righthand.dmi'
|
||||
force = 15 //Extra damage is dealt to targets in attack()
|
||||
throwforce = 40
|
||||
throwforce = 25
|
||||
armour_penetration = 10
|
||||
sharpness = IS_SHARP_ACCURATE
|
||||
attack_verb = list("stabbed", "poked", "slashed")
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
var/impale_cooldown = 50 //delay, in deciseconds, where you can't impale again
|
||||
var/attack_cooldown = 10 //delay, in deciseconds, where you can't attack with the spear
|
||||
var/bonus_burn = 5
|
||||
var/timerid
|
||||
|
||||
/obj/item/clockwork/ratvarian_spear/Destroy()
|
||||
@@ -22,107 +24,44 @@
|
||||
|
||||
/obj/item/clockwork/ratvarian_spear/ratvar_act()
|
||||
if(GLOB.ratvar_awakens) //If Ratvar is alive, the spear is extremely powerful
|
||||
force = 25
|
||||
throwforce = 50
|
||||
armour_penetration = 10
|
||||
force = 20
|
||||
bonus_burn = 10
|
||||
throwforce = 40
|
||||
armour_penetration = 50
|
||||
clockwork_desc = initial(clockwork_desc)
|
||||
deltimer(timerid)
|
||||
else
|
||||
force = initial(force)
|
||||
bonus_burn = initial(bonus_burn)
|
||||
throwforce = initial(throwforce)
|
||||
armour_penetration = 0
|
||||
armour_penetration = initial(armour_penetration)
|
||||
clockwork_desc = "A powerful spear of Ratvarian making. It's more effective against enemy cultists and silicons, though it won't last for long."
|
||||
deltimer(timerid)
|
||||
timerid = addtimer(CALLBACK(src, .proc/break_spear), RATVARIAN_SPEAR_DURATION, TIMER_STOPPABLE)
|
||||
|
||||
/obj/item/clockwork/ratvarian_spear/cyborg/ratvar_act() //doesn't break!
|
||||
if(GLOB.ratvar_awakens)
|
||||
force = 25
|
||||
throwforce = 50
|
||||
armour_penetration = 10
|
||||
else
|
||||
force = initial(force)
|
||||
throwforce = initial(throwforce)
|
||||
armour_penetration = 0
|
||||
..()
|
||||
clockwork_desc = "A powerful spear of Ratvarian making. It's more effective against enemy cultists and silicons."
|
||||
deltimer(timerid)
|
||||
|
||||
/obj/item/clockwork/ratvarian_spear/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
to_chat(user, "<span class='brass'>Stabbing a human you are pulling or have grabbed with the spear will impale them, doing massive damage and stunning.</span>")
|
||||
to_chat(user, "<span class='inathneq_small'>Attacks on living non-Servants will generate <b>[bonus_burn]</b> units of vitality.</span>")
|
||||
if(!iscyborg(user))
|
||||
to_chat(user, "<span class='brass'>Throwing the spear will do massive damage, break the spear, and knock down the target.</span>")
|
||||
|
||||
/obj/item/clockwork/ratvarian_spear/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
var/impaling = FALSE
|
||||
if(attack_cooldown > world.time)
|
||||
to_chat(user, "<span class='warning'>You can't attack right now, wait [max(round((attack_cooldown - world.time)*0.1, 0.1), 0)] seconds!</span>")
|
||||
return
|
||||
if(user.pulling && ishuman(user.pulling) && user.pulling == target)
|
||||
if(impale_cooldown > world.time)
|
||||
to_chat(user, "<span class='warning'>You can't impale [target] yet, wait [max(round((impale_cooldown - world.time)*0.1, 0.1), 0)] seconds!</span>")
|
||||
else
|
||||
impaling = TRUE
|
||||
attack_verb = list("impaled")
|
||||
force += 22 //total 40 damage if ratvar isn't alive, 50 if he is
|
||||
armour_penetration += 10 //if you're impaling someone, armor sure isn't that useful
|
||||
user.stop_pulling()
|
||||
|
||||
if(hitsound)
|
||||
playsound(loc, hitsound, get_clamped_volume(), 1, -1)
|
||||
user.lastattacked = target
|
||||
target.lastattacker = user
|
||||
user.do_attack_animation(target)
|
||||
if(!target.attacked_by(src, user)) //TODO MAKE ATTACK() USE PROPER RETURN VALUES
|
||||
impaling = FALSE //if we got blocked, stop impaling
|
||||
else if(!target.null_rod_check()) //if they don't have a null rod, we do bonus damage on a successful attack
|
||||
. = ..()
|
||||
if(!QDELETED(target) && target.stat != DEAD && !target.null_rod_check() && !is_servant_of_ratvar(target)) //we do bonus damage on attacks unless they're a servant, have a null rod, or are dead
|
||||
var/bonus_damage = bonus_burn //normally a total of 20 damage, 30 with ratvar
|
||||
if(issilicon(target))
|
||||
var/mob/living/silicon/S = target
|
||||
if(S.stat != DEAD)
|
||||
S.visible_message("<span class='warning'>[S] shudders violently at [src]'s touch!</span>", "<span class='userdanger'>ERROR: Temperature rising!</span>")
|
||||
S.adjustFireLoss(22) //total 37 damage on borgs
|
||||
target.visible_message("<span class='warning'>[target] shudders violently at [src]'s touch!</span>", "<span class='userdanger'>ERROR: Temperature rising!</span>")
|
||||
bonus_damage *= 5 //total 40 damage on borgs, 70 with ratvar
|
||||
else if(iscultist(target) || isconstruct(target))
|
||||
var/mob/living/M = target
|
||||
if(M.stat != DEAD)
|
||||
to_chat(M, "<span class='userdanger'>Your body flares with agony at [src]'s presence!</span>")
|
||||
M.adjustFireLoss(15) //total 30 damage on cultists
|
||||
else
|
||||
target.adjustFireLoss(3) //anything else takes a total of 18
|
||||
add_logs(user, target, "attacked", src.name, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
|
||||
add_fingerprint(user)
|
||||
|
||||
attack_verb = list("stabbed", "poked", "slashed")
|
||||
ratvar_act()
|
||||
if(impaling)
|
||||
impale_cooldown = world.time + initial(impale_cooldown)
|
||||
attack_cooldown = world.time + initial(attack_cooldown) //can't attack until we're done impaling
|
||||
if(target)
|
||||
new /obj/effect/temp_visual/dir_setting/bloodsplatter(get_turf(target), get_dir(user, target))
|
||||
target.Stun(80) //brief stun
|
||||
to_chat(user, "<span class='brass'>You prepare to remove your ratvarian spear from [target]...</span>")
|
||||
var/remove_verb = pick("pull", "yank", "drag")
|
||||
if(do_after(user, 10, 1, target))
|
||||
var/turf/T = get_turf(target)
|
||||
var/obj/effect/temp_visual/dir_setting/bloodsplatter/B = new /obj/effect/temp_visual/dir_setting/bloodsplatter(T, get_dir(target, user))
|
||||
playsound(T, 'sound/misc/splort.ogg', 200, 1)
|
||||
playsound(T, 'sound/weapons/pierce.ogg', 200, 1)
|
||||
if(target.stat != CONSCIOUS)
|
||||
user.visible_message("<span class='warning'>[user] [remove_verb]s [src] out of [target]!</span>", "<span class='warning'>You [remove_verb] your spear from [target]!</span>")
|
||||
else
|
||||
user.visible_message("<span class='warning'>[user] kicks [target] off of [src]!</span>", "<span class='warning'>You kick [target] off of [src]!</span>")
|
||||
to_chat(target, "<span class='userdanger'>You scream in pain as you're kicked off of [src]!</span>")
|
||||
target.emote("scream")
|
||||
step(target, get_dir(user, target))
|
||||
T = get_turf(target)
|
||||
B.forceMove(T)
|
||||
target.Knockdown(40) //then knockdown if we stayed next to them
|
||||
playsound(T, 'sound/weapons/thudswoosh.ogg', 50, 1)
|
||||
flash_color(target, flash_color="#911414", flash_time=8)
|
||||
else if(target) //it's a do_after, we gotta check again to make sure they didn't get deleted
|
||||
user.visible_message("<span class='warning'>[user] [remove_verb]s [src] out of [target]!</span>", "<span class='warning'>You [remove_verb] your spear from [target]!</span>")
|
||||
if(target.stat == CONSCIOUS)
|
||||
to_chat(target, "<span class='userdanger'>You scream in pain as [src] is suddenly [remove_verb]ed out of you!</span>")
|
||||
target.emote("scream")
|
||||
flash_color(target, flash_color="#911414", flash_time=4)
|
||||
to_chat(target, "<span class='userdanger'>Your body flares with agony at [src]'s presence!</span>")
|
||||
bonus_damage *= 3 //total 30 damage on cultists, 50 with ratvar
|
||||
GLOB.clockwork_vitality += target.adjustFireLoss(bonus_damage) //adds the damage done to existing vitality
|
||||
|
||||
/obj/item/clockwork/ratvarian_spear/throw_impact(atom/target)
|
||||
var/turf/T = get_turf(target)
|
||||
@@ -139,6 +78,7 @@
|
||||
L.Knockdown(100)
|
||||
else
|
||||
L.Knockdown(40)
|
||||
GLOB.clockwork_vitality += L.adjustFireLoss(bonus_burn * 3) //normally a total of 40 damage, 70 with ratvar
|
||||
break_spear(T)
|
||||
else
|
||||
..()
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
/mob/living/simple_animal/hostile/clockwork/examine(mob/user)
|
||||
var/t_He = p_they(TRUE)
|
||||
var/t_s = p_s()
|
||||
var/msg = "<span class='brass'>*---------*\nThis is [bicon(src)] \a <b>[src]</b>!\n"
|
||||
var/msg = "<span class='brass'>*---------*\nThis is [icon2html(src, user)] \a <b>[src]</b>!\n"
|
||||
msg += "[desc]\n"
|
||||
if(health < maxHealth)
|
||||
msg += "<span class='warning'>"
|
||||
|
||||
@@ -150,7 +150,7 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or
|
||||
if(prob(ratvarian_prob))
|
||||
message = text2ratvar(message)
|
||||
to_chat(invoker, "<span class='[get_component_span(primary_component)]_large'>\"[message]\"</span>")
|
||||
invoker << 'sound/magic/clockwork/invoke_general.ogg'
|
||||
SEND_SOUND(invoker, sound('sound/magic/clockwork/invoke_general.ogg'))
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/proc/check_offstation_penalty()
|
||||
|
||||
@@ -2,28 +2,6 @@
|
||||
// APPLICATIONS //
|
||||
//////////////////
|
||||
|
||||
//Sigil of Accession: Creates a sigil of accession, which is like a sigil of submission, but can convert any number of non-implanted targets and up to one implanted target.
|
||||
/datum/clockwork_scripture/create_object/sigil_of_accession
|
||||
descname = "Trap, Permanent Conversion"
|
||||
name = "Sigil of Accession"
|
||||
desc = "Places a luminous sigil much like a Sigil of Submission, but it will remain even after successfully converting a non-implanted target. \
|
||||
It will penetrate mindshield implants once before disappearing."
|
||||
invocations = list("Divinity, enslave...", "...all who trespass here!")
|
||||
channel_time = 70
|
||||
consumed_components = list(BELLIGERENT_EYE = 4, GEIS_CAPACITOR = 2, HIEROPHANT_ANSIBLE = 2)
|
||||
whispered = TRUE
|
||||
object_path = /obj/effect/clockwork/sigil/submission/accession
|
||||
prevent_path = /obj/effect/clockwork/sigil/submission
|
||||
creator_message = "<span class='brass'>A luminous sigil appears below you. All non-servants to cross it will be enslaved after a brief time if they do not move.</span>"
|
||||
usage_tip = "It will remain after converting a target, unless that target has a mindshield implant, which it will break to convert them, but consume itself in the process."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
one_per_tile = TRUE
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 1
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Sigil of Accession, which can convert a mindshielded non-Servant that remains on it."
|
||||
|
||||
|
||||
//Fellowship Armory: Arms the invoker and nearby servants with Ratvarian armor.
|
||||
/datum/clockwork_scripture/fellowship_armory
|
||||
descname = "Area Servant Armor"
|
||||
@@ -151,26 +129,6 @@
|
||||
return TRUE
|
||||
|
||||
|
||||
//Anima Fragment: Creates an empty anima fragment, which produces an anima fragment that moves at extreme speed and does high damage.
|
||||
/datum/clockwork_scripture/create_object/anima_fragment
|
||||
descname = "Fast Soul Vessel Shell"
|
||||
name = "Anima Fragment"
|
||||
desc = "Creates a large shell fitted for soul vessels. Adding an active soul vessel to it results in a powerful construct with decent health and slight regeneration, notable melee power, \
|
||||
and exceptional speed, though taking damage will temporarily slow it down."
|
||||
invocations = list("Call forth...", "...the soldiers of Armorer.")
|
||||
channel_time = 80
|
||||
consumed_components = list(BELLIGERENT_EYE = 2, VANGUARD_COGWHEEL = 2, REPLICANT_ALLOY = 4)
|
||||
object_path = /obj/structure/destructible/clockwork/shell/fragment
|
||||
creator_message = "<span class='brass'>You form an anima fragment, a powerful soul vessel receptacle.</span>"
|
||||
observer_message = "<span class='warning'>The slab disgorges a puddle of black metal that expands and forms into a strange shell!</span>"
|
||||
usage_tip = "Useless without a soul vessel and should not be created without one."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
primary_component = REPLICANT_ALLOY
|
||||
sort_priority = 4
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Fragment Shell, which produces an Anima Fragment when filled with a Soul Vessel."
|
||||
|
||||
|
||||
//Sigil of Transmission: Creates a sigil of transmission that can drain and store power for clockwork structures.
|
||||
/datum/clockwork_scripture/create_object/sigil_of_transmission
|
||||
descname = "Structure Power Generator & Battery"
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
invocations = list("May heathens...", "...kneel under our force!")
|
||||
channel_time = 30
|
||||
primary_component = BELLIGERENT_EYE
|
||||
quickbind_desc = "Allows you to place a Judicial Marker to knock down and damage non-Servants in an area.<br><b>Click your slab to disable.</b>"
|
||||
quickbind_desc = "Allows you to smite an area, applying Belligerent and briefly stunning.<br><b>Click your slab to disable.</b>"
|
||||
slab_overlay = "judicial"
|
||||
ranged_type = /obj/effect/proc_holder/slab/judicial
|
||||
ranged_message = "<span class='neovgre_small'><i>You charge the clockwork slab with judicial force.</i>\n\
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
/datum/clockwork_scripture/channeled/belligerent/chant_effects(chant_number)
|
||||
for(var/mob/living/carbon/C in hearers(7, invoker))
|
||||
C.apply_status_effect(STATUS_EFFECT_BELLIGERENT)
|
||||
new /obj/effect/temp_visual/ratvar/belligerent(get_turf(invoker))
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -28,20 +29,20 @@
|
||||
/datum/clockwork_scripture/create_object/judicial_visor
|
||||
descname = "Delayed Area Knockdown Glasses"
|
||||
name = "Judicial Visor"
|
||||
desc = "Forms a visor that, when worn, will grant the ability to smite an area, knocking down, muting, and damaging non-Servants."
|
||||
desc = "Creates a visor that can smite an area, applying Belligerent and briefly stunning. The smote area will explode after 3 seconds."
|
||||
invocations = list("Grant me the flames of Engine!")
|
||||
channel_time = 10
|
||||
consumed_components = list(BELLIGERENT_EYE = 1)
|
||||
whispered = TRUE
|
||||
object_path = /obj/item/clothing/glasses/judicial_visor
|
||||
creator_message = "<span class='brass'>You form a judicial visor, which is capable of smiting the unworthy.</span>"
|
||||
usage_tip = "The visor has a thirty-second cooldown once used, and the marker it creates has a delay of 3 seconds before exploding."
|
||||
creator_message = "<span class='brass'>You form a judicial visor, which is capable of smiting a small area.</span>"
|
||||
usage_tip = "The visor has a thirty-second cooldown once used."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
space_allowed = TRUE
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 2
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Judicial Visor, which can create a Judicial Marker at an area, knocking down, muting, and damaging non-Servants after a delay."
|
||||
quickbind_desc = "Creates a Judicial Visor, which can smite an area, applying Belligerent and briefly stunning."
|
||||
|
||||
|
||||
//Vanguard: Provides twenty seconds of stun immunity. At the end of the twenty seconds, 25% of all stuns absorbed are applied to the invoker.
|
||||
@@ -97,28 +98,28 @@
|
||||
Click your slab to cancel.</b></span>"
|
||||
|
||||
|
||||
//Geis: Grants a short-range binding that will immediately start chanting on binding a valid target.
|
||||
/datum/clockwork_scripture/ranged_ability/geis_prep
|
||||
descname = "Melee Convert Attack"
|
||||
//Geis: Grants a short-range binding attack that allows you to mute and drag around a target in a very obvious manner.
|
||||
/datum/clockwork_scripture/ranged_ability/geis
|
||||
descname = "Melee Mute & Stun"
|
||||
name = "Geis"
|
||||
desc = "Charges your slab with divine energy, allowing you to bind a nearby heretic for conversion. This is very obvious and will make your slab visible in-hand."
|
||||
invocations = list("Divinity, grant...", "...me strength...", "...to enlighten...", "...the heathen!")
|
||||
desc = "Charges your slab with divine energy, allowing you to bind and pull a struck heretic."
|
||||
invocations = list("Divinity, grant me strength...", "...to bind the heathen!")
|
||||
whispered = TRUE
|
||||
channel_time = 20
|
||||
usage_tip = "Is melee range and does not penetrate mindshield implants. Much more efficient than a Sigil of Submission at low Servant amounts."
|
||||
usage_tip = "You CANNOT TAKE ANY NON-PULL ACTIONS while the target is bound, so Sigils of Submission should be placed before use."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 5
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to bind and start converting an adjacent target non-Servant.<br><b>Click your slab to disable.</b>"
|
||||
quickbind_desc = "Allows you to bind and mute an adjacent target non-Servant.<br><b>Click your slab to disable.</b>"
|
||||
slab_overlay = "geis"
|
||||
ranged_type = /obj/effect/proc_holder/slab/geis
|
||||
ranged_message = "<span class='sevtug_small'><i>You charge the clockwork slab with divine energy.</i>\n\
|
||||
<b>Left-click a target within melee range to convert!\n\
|
||||
<b>Left-click a target within melee range to bind!\n\
|
||||
Click your slab to cancel.</b></span>"
|
||||
timeout_time = 100
|
||||
|
||||
/datum/clockwork_scripture/ranged_ability/geis_prep/run_scripture()
|
||||
/datum/clockwork_scripture/ranged_ability/geis/run_scripture()
|
||||
var/servants = 0
|
||||
if(!GLOB.ratvar_awakens)
|
||||
for(var/mob/living/M in GLOB.living_mob_list)
|
||||
@@ -130,93 +131,25 @@
|
||||
channel_time = min(channel_time + servants*3, 50)
|
||||
return ..()
|
||||
|
||||
//The scripture that does the converting.
|
||||
/datum/clockwork_scripture/geis
|
||||
name = "Geis Conversion"
|
||||
invocations = list("Enlighten this heathen!", "All are insects before Engine!", "Purge all untruths and honor Engine.")
|
||||
channel_time = 49
|
||||
tier = SCRIPTURE_PERIPHERAL
|
||||
var/mob/living/target
|
||||
var/obj/structure/destructible/clockwork/geis_binding/binding
|
||||
|
||||
/datum/clockwork_scripture/geis/Destroy()
|
||||
if(binding && !QDELETED(binding))
|
||||
qdel(binding)
|
||||
return ..()
|
||||
|
||||
/datum/clockwork_scripture/geis/can_recite()
|
||||
if(!target)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/clockwork_scripture/geis/run_scripture()
|
||||
var/servants = 0
|
||||
if(!GLOB.ratvar_awakens)
|
||||
for(var/mob/living/M in GLOB.living_mob_list)
|
||||
if(can_recite_scripture(M, TRUE))
|
||||
servants++
|
||||
if(target.buckled)
|
||||
target.buckled.unbuckle_mob(target, TRUE)
|
||||
binding = new(get_turf(target))
|
||||
if(servants > SCRIPT_SERVANT_REQ)
|
||||
servants -= SCRIPT_SERVANT_REQ
|
||||
channel_time = min(channel_time + servants*7, 120)
|
||||
binding.can_resist = TRUE
|
||||
binding.setDir(target.dir)
|
||||
binding.buckle_mob(target, TRUE)
|
||||
return ..()
|
||||
|
||||
/datum/clockwork_scripture/geis/check_special_requirements()
|
||||
return target && binding && target.buckled == binding && !is_servant_of_ratvar(target) && target.stat != DEAD
|
||||
|
||||
/datum/clockwork_scripture/geis/scripture_effects()
|
||||
. = add_servant_of_ratvar(target)
|
||||
if(.)
|
||||
add_logs(invoker, target, "Converted", object = "Geis")
|
||||
|
||||
|
||||
//Taunting Tirade: Channeled for up to five times over thirty seconds. Confuses non-servants that can hear it and allows movement for a brief time after each chant.
|
||||
/datum/clockwork_scripture/channeled/taunting_tirade
|
||||
descname = "Channeled, Mobile Confusion Trail"
|
||||
name = "Taunting Tirade"
|
||||
desc = "Allows movement for five seconds, leaving a trail that confuses and knocks down. Chanted every second for up to thirty seconds."
|
||||
chant_invocations = list("Hostiles on my back!", "Enemies on my trail!", "Gonna try and shake my tail.", "Bogeys on my six!")
|
||||
chant_amount = 5
|
||||
chant_interval = 10
|
||||
//Sigil of Submission: Creates a sigil of submission, which converts one heretic above it after a delay.
|
||||
/datum/clockwork_scripture/create_object/sigil_of_submission
|
||||
descname = "Trap, Conversion"
|
||||
name = "Sigil of Submission"
|
||||
desc = "Places a luminous sigil that will convert any non-Servants that remain on it for 8 seconds."
|
||||
invocations = list("Divinity, enlighten...", "...those who trespass here!")
|
||||
channel_time = 60
|
||||
consumed_components = list(GEIS_CAPACITOR = 1)
|
||||
usage_tip = "Useful for fleeing attackers, as few will be able to follow someone using this scripture."
|
||||
whispered = TRUE
|
||||
object_path = /obj/effect/clockwork/sigil/submission
|
||||
creator_message = "<span class='brass'>A luminous sigil appears below you. Any non-Servants to cross it will be converted after 8 seconds if they do not move.</span>"
|
||||
usage_tip = "This is the primary conversion method, though it will not penetrate mindshield implants."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
one_per_tile = TRUE
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 6
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows movement for five seconds, leaving a trail that confuses and knocks down.<br><b>Maximum 5 chants.</b>"
|
||||
var/flee_time = 47 //allow fleeing for 5 seconds
|
||||
var/grace_period = 3 //very short grace period so you don't have to stop immediately
|
||||
var/datum/progressbar/progbar
|
||||
|
||||
/datum/clockwork_scripture/channeled/taunting_tirade/chant_effects(chant_number)
|
||||
invoker.visible_message("<span class='warning'>[invoker] is suddenly covered with a thin layer of purple smoke!</span>")
|
||||
var/invoker_old_color = invoker.color
|
||||
invoker.color = list("#AF0AAF", "#AF0AAF", "#AF0AAF", rgb(0,0,0))
|
||||
animate(invoker, color = invoker_old_color, time = flee_time+grace_period)
|
||||
addtimer(CALLBACK(invoker, /atom/proc/update_atom_colour), flee_time+grace_period)
|
||||
var/endtime = world.time + flee_time
|
||||
progbar = new(invoker, flee_time, invoker)
|
||||
progbar.bar.color = list("#AF0AAF", "#AF0AAF", "#AF0AAF", rgb(0,0,0))
|
||||
animate(progbar.bar, color = initial(progbar.bar.color), time = flee_time+grace_period)
|
||||
while(world.time < endtime && can_recite())
|
||||
sleep(1)
|
||||
new/obj/structure/destructible/clockwork/taunting_trail(invoker.loc)
|
||||
progbar.update(endtime - world.time)
|
||||
qdel(progbar)
|
||||
if(can_recite() && chant_number != chant_amount)
|
||||
sleep(grace_period)
|
||||
else
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/channeled/taunting_tirade/chant_end_effects()
|
||||
qdel(progbar)
|
||||
quickbind_desc = "Creates a Sigil of Submission, which will convert non-Servants that remain on it."
|
||||
|
||||
|
||||
//Replicant: Creates a new clockwork slab.
|
||||
|
||||
@@ -29,31 +29,12 @@
|
||||
return ..()
|
||||
|
||||
|
||||
//Cogscarab: Creates an empty cogscarab shell, which produces a cogscarab dedicated to maintaining and defending the cult.
|
||||
/datum/clockwork_scripture/create_object/cogscarab
|
||||
descname = "Constructor Soul Vessel Shell"
|
||||
name = "Cogscarab"
|
||||
desc = "Creates a small shell fitted for soul vessels. Adding an active soul vessel to it results in a small construct with tools and an inbuilt fabricator."
|
||||
invocations = list("Call forth...", "...the workers of Armorer.")
|
||||
channel_time = 60
|
||||
consumed_components = list(BELLIGERENT_EYE = 2, HIEROPHANT_ANSIBLE = 1)
|
||||
object_path = /obj/structure/destructible/clockwork/shell/cogscarab
|
||||
creator_message = "<span class='brass'>You form a cogscarab, a constructor soul vessel receptacle.</span>"
|
||||
observer_message = "<span class='warning'>The slab disgorges a puddle of black metal that contracts and forms into a strange shell!</span>"
|
||||
usage_tip = "Useless without a soul vessel and should not be created without one."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 2
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Cogscarab Shell, which produces a Cogscarab when filled with a Soul Vessel."
|
||||
|
||||
|
||||
//Vitality Matrix: Creates a sigil which will drain health from nonservants and can use that health to heal or even revive servants.
|
||||
/datum/clockwork_scripture/create_object/vitality_matrix
|
||||
descname = "Trap, Damage to Healing"
|
||||
name = "Vitality Matrix"
|
||||
desc = "Places a sigil that drains life from any living non-Servants that cross it. Servants that cross it, however, will be healed based on how much Vitality all \
|
||||
Matrices have drained from non-Servants. Dead Servants can be revived by this sigil if there is vitality equal to the target Servant's non-oxygen damage."
|
||||
desc = "Places a sigil that drains life from any living non-Servants that cross it, producing Vitality. Servants that cross it, however, will be healed using existing Vitality. \
|
||||
Dead Servants can be revived by this sigil at a cost of 150 Vitality."
|
||||
invocations = list("Divinity...", "...steal their life...", "...for these shells!")
|
||||
channel_time = 60
|
||||
consumed_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 2)
|
||||
@@ -181,46 +162,6 @@
|
||||
return TRUE
|
||||
|
||||
|
||||
//Sigil of Submission: Creates a sigil of submission, which converts one heretic above it after a delay.
|
||||
/datum/clockwork_scripture/create_object/sigil_of_submission
|
||||
descname = "Trap, Conversion"
|
||||
name = "Sigil of Submission"
|
||||
desc = "Places a luminous sigil that will enslave any valid beings standing on it after a time."
|
||||
invocations = list("Divinity, enlighten...", "...those who trespass here!")
|
||||
channel_time = 60
|
||||
consumed_components = list(BELLIGERENT_EYE = 1, GEIS_CAPACITOR = 2)
|
||||
whispered = TRUE
|
||||
object_path = /obj/effect/clockwork/sigil/submission
|
||||
creator_message = "<span class='brass'>A luminous sigil appears below you. The next non-servant to cross it will be enslaved after a brief time if they do not move.</span>"
|
||||
usage_tip = "This is not a primary conversion method - use Geis for that. It is advantageous as a trap, however, as it will transmit the name of the newly-converted."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
one_per_tile = TRUE
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 5
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Sigil of Submission, which will convert one non-Servant that remains on it."
|
||||
|
||||
|
||||
//Soul Vessel: Creates a soul vessel, which can seek a ghost or be used on the uncovered head of a dead or dying human to take their brain.
|
||||
/datum/clockwork_scripture/create_object/soul_vessel
|
||||
descname = "Clockwork Posibrain"
|
||||
name = "Soul Vessel"
|
||||
desc = "Forms an ancient positronic brain with an overriding directive to serve Ratvar."
|
||||
invocations = list("Herd the souls of...", "...the blasphemous damned!")
|
||||
channel_time = 30
|
||||
consumed_components = list(VANGUARD_COGWHEEL = 1, GEIS_CAPACITOR = 2)
|
||||
whispered = TRUE
|
||||
object_path = /obj/item/device/mmi/posibrain/soul_vessel
|
||||
creator_message = "<span class='brass'>You form a soul vessel, which can be used in-hand to attract spirits, or used on an unconscious or dead human to extract their consciousness.</span>"
|
||||
usage_tip = "The vessel can be used as a teleport target for Spatial Gateway, though it is generally better-used by placing it in a shell or cyborg body."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
space_allowed = TRUE
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 6
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Soul Vessel, which can be placed in construct shells and cyborg bodies once filled."
|
||||
|
||||
|
||||
//Replica Fabricator: Creates a replica fabricator, used to convert objects and repair clockwork structures.
|
||||
/datum/clockwork_scripture/create_object/replica_fabricator
|
||||
descname = "Replaces Objects with Ratvarian Versions"
|
||||
@@ -245,13 +186,12 @@
|
||||
/datum/clockwork_scripture/function_call
|
||||
descname = "Permanent Summonable Spear"
|
||||
name = "Function Call"
|
||||
desc = "Grants the invoker the ability to call forth a powerful Ratvarian spear every three minutes. The spear will deal significant damage to Nar-Sie's dogs and silicon lifeforms, but will \
|
||||
vanish three minutes after being summoned."
|
||||
desc = "Grants the invoker the ability to call forth a powerful Ratvarian spear every 3 minutes, with it lasting 3 minutes. The spear's attacks will generate Vitality, used for healing."
|
||||
invocations = list("Grant me...", "...the might of brass!")
|
||||
channel_time = 20
|
||||
consumed_components = list(REPLICANT_ALLOY = 2, HIEROPHANT_ANSIBLE = 1)
|
||||
whispered = TRUE
|
||||
usage_tip = "You can impale human targets with the spear by pulling them, then attacking. Throwing the spear at a mob will do massive damage and knock them down, but break the spear."
|
||||
usage_tip = "Throwing the spear at a mob will do massive damage and knock them down, but break the spear."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = REPLICANT_ALLOY
|
||||
sort_priority = 8
|
||||
@@ -345,50 +285,3 @@
|
||||
portal_uses = max(portal_uses, 100) //Very powerful if Ratvar has been summoned
|
||||
duration = max(duration, 100)
|
||||
return slab.procure_gateway(invoker, duration, portal_uses)
|
||||
|
||||
|
||||
//Volt Blaster: Channeled for up to five times over ten seconds to fire up to five rays of energy at target locations.
|
||||
/datum/clockwork_scripture/channeled/volt_blaster
|
||||
descname = "Channeled, Targeted Energy Blasts"
|
||||
name = "Volt Blaster"
|
||||
desc = "Allows you to fire five energy rays at target locations. Channeled every fourth of a second for a maximum of ten seconds."
|
||||
channel_time = 30
|
||||
invocations = list("Amperage...", "...grant me your power!")
|
||||
chant_invocations = list("Use charge to kill!", "Slay with power!", "Hunt with energy!")
|
||||
chant_amount = 5
|
||||
chant_interval = 4
|
||||
consumed_components = list(GEIS_CAPACITOR = 1, HIEROPHANT_ANSIBLE = 2)
|
||||
usage_tip = "Though it requires you to stand still, this scripture can do massive damage."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 10
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to fire energy rays at target locations.<br><b>Maximum 5 chants.</b>"
|
||||
var/static/list/nzcrentr_insults = list("You're not very good at aiming.", "You hunt badly.", "What a waste of energy.", "Almost funny to watch.",
|
||||
"Boss says </span><span class='heavy_brass'>\"Click something, you idiot!\"</span><span class='nzcrentr'>.", "Stop wasting components if you can't aim.")
|
||||
|
||||
/datum/clockwork_scripture/channeled/volt_blaster/chant_effects(chant_number)
|
||||
slab.busy = null
|
||||
var/datum/clockwork_scripture/ranged_ability/volt_ray/ray = new
|
||||
ray.slab = slab
|
||||
ray.invoker = invoker
|
||||
var/turf/T = get_turf(invoker)
|
||||
if(!ray.run_scripture() && slab && invoker)
|
||||
if(can_recite() && T == get_turf(invoker))
|
||||
to_chat(invoker, "<span class='nzcrentr'>\"[text2ratvar(pick(nzcrentr_insults))]\"</span>")
|
||||
else
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/effect/ebeam/volt_ray
|
||||
name = "volt_ray"
|
||||
layer = LYING_MOB_LAYER
|
||||
|
||||
/datum/clockwork_scripture/ranged_ability/volt_ray
|
||||
name = "Volt Ray"
|
||||
slab_overlay = "volt"
|
||||
allow_mobility = FALSE
|
||||
ranged_type = /obj/effect/proc_holder/slab/volt
|
||||
ranged_message = "<span class='nzcrentr_small'><i>You charge the clockwork slab with shocking might.</i>\n\
|
||||
<b>Left-click a target to fire, quickly!</b></span>"
|
||||
timeout_time = 20
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
//Useless on their own, these shells can create powerful constructs.
|
||||
/obj/structure/destructible/clockwork/shell
|
||||
construction_value = 0
|
||||
anchored = FALSE
|
||||
density = FALSE
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
var/mobtype = /mob/living/simple_animal/hostile/clockwork
|
||||
var/spawn_message = " is an error and you should yell at whoever spawned this shell."
|
||||
|
||||
/obj/structure/destructible/clockwork/shell/attackby(obj/item/I, mob/living/user, params)
|
||||
if(istype(I, /obj/item/device/mmi/posibrain/soul_vessel))
|
||||
if(!is_servant_of_ratvar(user))
|
||||
..()
|
||||
return 0
|
||||
var/obj/item/device/mmi/posibrain/soul_vessel/S = I
|
||||
if(!S.brainmob)
|
||||
to_chat(user, "<span class='warning'>[S] is inactive! Turn it on or capture a mind first.</span>")
|
||||
return 0
|
||||
if(S.brainmob && (!S.brainmob.client || !S.brainmob.mind))
|
||||
to_chat(user, "<span class='warning'>[S]'s trapped consciousness appears inactive!</span>")
|
||||
return 0
|
||||
user.visible_message("<span class='notice'>[user] places [S] in [src], where it fuses to the shell.</span>", "<span class='brass'>You place [S] in [src], fusing it to the shell.</span>")
|
||||
var/mob/living/simple_animal/A = new mobtype(get_turf(src))
|
||||
A.visible_message("<span class='brass'>[src][spawn_message]</span>")
|
||||
S.brainmob.mind.transfer_to(A)
|
||||
A.fully_replace_character_name(null, "[findtext(A.name, initial(A.name)) ? "[initial(A.name)]":"[A.name]"] ([S.brainmob.name])")
|
||||
user.drop_item()
|
||||
qdel(S)
|
||||
qdel(src)
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/shell/cogscarab
|
||||
name = "cogscarab shell"
|
||||
desc = "A small brass shell with a cube-shaped receptable in its center. It gives off an aura of obsessive perfectionism."
|
||||
clockwork_desc = "A dormant receptable that, when powered with a soul vessel, will become a weak construct with an inbuilt fabricator."
|
||||
icon_state = "clockdrone_shell"
|
||||
mobtype = /mob/living/simple_animal/drone/cogscarab
|
||||
spawn_message = "'s eyes blink open, glowing bright red."
|
||||
|
||||
/obj/structure/destructible/clockwork/shell/fragment
|
||||
name = "fragment shell"
|
||||
desc = "A massive brass shell with a small cube-shaped receptable in its center. It gives off an aura of contained power."
|
||||
clockwork_desc = "A dormant receptable that, when powered with a soul vessel, will become a powerful construct."
|
||||
icon_state = "anime_fragment"
|
||||
mobtype = /mob/living/simple_animal/hostile/clockwork/fragment
|
||||
spawn_message = " whirs and rises from the ground on a flickering jet of reddish fire."
|
||||
@@ -5,8 +5,9 @@
|
||||
clockwork_desc = "A binding ring around a target, preventing them from taking action while they're being converted."
|
||||
max_integrity = 25
|
||||
light_range = 2
|
||||
light_power = 0.5
|
||||
light_power = 0.8
|
||||
light_color = "#AF0AAF"
|
||||
anchored = FALSE
|
||||
density = FALSE
|
||||
immune_to_servant_attacks = TRUE
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
@@ -16,16 +17,34 @@
|
||||
debris = list()
|
||||
can_buckle = TRUE
|
||||
buckle_lying = 0
|
||||
buckle_prevents_pull = TRUE
|
||||
var/resisting = FALSE
|
||||
var/can_resist = FALSE
|
||||
var/mob_layer = MOB_LAYER
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/Initialize(mapload, obj/item/clockwork/slab/the_slab)
|
||||
. = ..()
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/Destroy()
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/examine(mob/user)
|
||||
icon_state = "geisbinding_full"
|
||||
..()
|
||||
icon_state = "geisbinding"
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/process()
|
||||
if(LAZYLEN(buckled_mobs))
|
||||
for(var/V in buckled_mobs)
|
||||
var/mob/living/L = V
|
||||
if(is_servant_of_ratvar(L)) //servants are freed automatically
|
||||
take_damage(obj_integrity)
|
||||
return
|
||||
var/tick_damage = 1
|
||||
if(!is_servant_of_ratvar(pulledby))
|
||||
tick_damage++
|
||||
take_damage(tick_damage, sound_effect = FALSE)
|
||||
playsound(src, 'sound/effects/empulse.ogg', tick_damage * 20, TRUE)
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/attack_hand(mob/living/user)
|
||||
return
|
||||
|
||||
@@ -48,10 +67,8 @@
|
||||
var/obj/item/geis_binding/B = new(M)
|
||||
M.put_in_hands(B, i)
|
||||
M.regenerate_icons()
|
||||
M.visible_message("<span class='warning'>A [name] appears around [M]!</span>", \
|
||||
"<span class='warning'>A [name] appears around you!</span>[can_resist ? "\n<span class='userdanger'>Resist!</span>":""]")
|
||||
if(!can_resist)
|
||||
repair_and_interrupt()
|
||||
M.visible_message("<span class='warning'>A [name] appears around [M]!</span>", "<span class='warning'>A [name] appears around you!</span>")
|
||||
repair_and_interrupt()
|
||||
else
|
||||
var/obj/effect/temp_visual/ratvar/geis_binding/G = new /obj/effect/temp_visual/ratvar/geis_binding(M.loc)
|
||||
var/obj/effect/temp_visual/ratvar/geis_binding/T = new /obj/effect/temp_visual/ratvar/geis_binding/top(M.loc)
|
||||
@@ -65,11 +82,6 @@
|
||||
for(var/obj/item/geis_binding/GB in M.held_items)
|
||||
M.dropItemToGround(GB, TRUE)
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/relaymove(mob/user, direction)
|
||||
if(isliving(user) && can_resist)
|
||||
var/mob/living/L = user
|
||||
L.resist()
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
||||
playsound(src, 'sound/effects/empulse.ogg', 50, 1)
|
||||
|
||||
@@ -79,7 +91,7 @@
|
||||
update_icon()
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/update_icon()
|
||||
alpha = min(initial(alpha) + ((obj_integrity - max_integrity) * 5), 255)
|
||||
alpha = min(255 * ((obj_integrity/max_integrity) + 0.2) , 255)
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/proc/repair_and_interrupt()
|
||||
obj_integrity = max_integrity
|
||||
@@ -87,10 +99,10 @@
|
||||
for(var/m in buckled_mobs)
|
||||
var/mob/living/L = m
|
||||
if(L)
|
||||
L.Stun(20, 1, 1)
|
||||
L.Stun(130, 1, 1) //basically here to act as a mute for borgs
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
C.silent += 4
|
||||
C.silent += 7
|
||||
visible_message("<span class='sevtug'>[src] flares brightly!</span>")
|
||||
var/obj/effect/temp_visual/ratvar/geis_binding/G1 = new /obj/effect/temp_visual/ratvar/geis_binding(loc)
|
||||
var/obj/effect/temp_visual/ratvar/geis_binding/G2 = new /obj/effect/temp_visual/ratvar/geis_binding(loc)
|
||||
@@ -106,18 +118,7 @@
|
||||
animate(T2, pixel_y = pixel_y - 9, alpha = 0, time = 8, easing = EASE_IN)
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/user_unbuckle_mob(mob/living/buckled_mob, mob/user)
|
||||
if(buckled_mob == user)
|
||||
if(!resisting && can_resist)
|
||||
resisting = TRUE
|
||||
user.visible_message("<span class='warning'>[user] starts struggling against [src]...</span>", "<span class='userdanger'>You start breaking out of [src]...</span>")
|
||||
while(do_after(user, 10, target = src) && resisting && obj_integrity)
|
||||
if(obj_integrity - 5 <= 0)
|
||||
user.visible_message("<span class='warning'>[user] breaks [src]!</span>", "<span class='userdanger'>You break [src]!</span>")
|
||||
take_damage(5)
|
||||
return user
|
||||
take_damage(5)
|
||||
resisting = FALSE
|
||||
else
|
||||
if(buckled_mob != user)
|
||||
return ..()
|
||||
|
||||
/obj/item/geis_binding
|
||||
@@ -128,5 +129,4 @@
|
||||
flags = NODROP|ABSTRACT|DROPDEL
|
||||
|
||||
/obj/item/geis_binding/pre_attackby(atom/target, mob/living/user, params)
|
||||
user.resist()
|
||||
return FALSE
|
||||
|
||||
@@ -203,7 +203,7 @@
|
||||
var/acolytes_survived = 0
|
||||
for(var/datum/mind/cult_mind in cult)
|
||||
if (cult_mind.current && cult_mind.current.stat != DEAD)
|
||||
if(cult_mind.current.onCentcom() || cult_mind.current.onSyndieBase())
|
||||
if(cult_mind.current.onCentCom() || cult_mind.current.onSyndieBase())
|
||||
acolytes_survived++
|
||||
if(acolytes_survived>=acolytes_needed)
|
||||
return 0
|
||||
|
||||
@@ -103,13 +103,13 @@
|
||||
if(B.current)
|
||||
B.current.update_action_buttons_icon()
|
||||
if(!B.current.incapacitated())
|
||||
B.current << 'sound/hallucinations/im_here1.ogg'
|
||||
SEND_SOUND(B.current, 'sound/hallucinations/im_here1.ogg')
|
||||
to_chat(B.current, "<span class='cultlarge'>Acolyte [Nominee] has asserted that they are worthy of leading the cult. A vote will be called shortly.</span>")
|
||||
sleep(100)
|
||||
var/list/asked_cultists = list()
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
if(B.current && B.current != Nominee && !B.current.incapacitated())
|
||||
B.current << 'sound/magic/exit_blood.ogg'
|
||||
SEND_SOUND(B.current, 'sound/magic/exit_blood.ogg')
|
||||
asked_cultists += B.current
|
||||
var/list/yes_voters = pollCandidates("[Nominee] seeks to lead your cult, do you support [Nominee.p_them()]?", poll_time = 300, group = asked_cultists)
|
||||
if(QDELETED(Nominee) || Nominee.incapacitated())
|
||||
@@ -280,7 +280,7 @@
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
if(B.current && B.current.stat != DEAD && B.current.client)
|
||||
to_chat(B.current, "<span class='cultlarge'><b>Master [ranged_ability_user] has marked [GLOB.blood_target] in the [A.name] as the cult's top priority, get there immediately!</b></span>")
|
||||
B.current << pick(sound('sound/hallucinations/over_here2.ogg',0,1,75), sound('sound/hallucinations/over_here3.ogg',0,1,75))
|
||||
SEND_SOUND(B.current, sound(pick('sound/hallucinations/over_here2.ogg','sound/hallucinations/over_here3.ogg'),0,1,75))
|
||||
B.current.client.images += GLOB.blood_target_image
|
||||
attached_action.owner.update_action_buttons_icon()
|
||||
remove_ranged_ability("<span class='cult'>The marking rite is complete! It will last for 90 seconds.</span>")
|
||||
@@ -324,7 +324,7 @@
|
||||
return FALSE
|
||||
if(cooldown > world.time)
|
||||
if(!PM.active)
|
||||
owner << "<span class='cultlarge'><b>You need to wait [round((cooldown - world.time) * 0.1)] seconds before you can pulse again!</b></span>"
|
||||
to_chat(owner, "<span class='cultlarge'><b>You need to wait [round((cooldown - world.time) * 0.1)] seconds before you can pulse again!</b></span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
@@ -367,7 +367,7 @@
|
||||
if(!attached_action.throwing)
|
||||
attached_action.throwing = TRUE
|
||||
attached_action.throwee = target
|
||||
ranged_ability_user << 'sound/weapons/thudswoosh.ogg'
|
||||
SEND_SOUND(ranged_ability_user, sound('sound/weapons/thudswoosh.ogg'))
|
||||
to_chat(ranged_ability_user,"<span class='cult'><b>You reach through the veil with your mind's eye and seize [target]!</b></span>")
|
||||
return
|
||||
else
|
||||
|
||||
@@ -161,11 +161,15 @@
|
||||
/obj/item/weapon/sharpener/cult
|
||||
name = "eldritch whetstone"
|
||||
desc = "A block, empowered by dark magic. Sharp weapons will be enhanced when used on the stone."
|
||||
icon_state = "cult_sharpener"
|
||||
used = 0
|
||||
increment = 5
|
||||
max = 40
|
||||
prefix = "darkened"
|
||||
|
||||
/obj/item/weapon/sharpener/cult/update_icon()
|
||||
icon_state = "cult_sharpener[used ? "_used" : ""]"
|
||||
|
||||
/obj/item/clothing/suit/hooded/cultrobes/cult_shield
|
||||
name = "empowered cultist armor"
|
||||
desc = "Empowered garb which creates a powerful shield around the user."
|
||||
@@ -391,7 +395,7 @@
|
||||
if(!iscultist(user))
|
||||
to_chat(user, "That doesn't seem to do anything useful.")
|
||||
return
|
||||
|
||||
|
||||
if(istype(A, /obj/item))
|
||||
|
||||
var/list/cultists = list()
|
||||
|
||||
@@ -538,7 +538,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
mob_to_revive = input(user, "Choose a cultist to revive.", "Cultist to Revive") as null|anything in potential_revive_mobs
|
||||
else
|
||||
mob_to_revive = potential_revive_mobs[1]
|
||||
if(!src || QDELETED(src) || rune_in_use || !validness_checks(mob_to_revive, user))
|
||||
if(QDELETED(src) || !validness_checks(mob_to_revive, user))
|
||||
rune_in_use = FALSE
|
||||
return
|
||||
if(user.name == "Herbert West")
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
return 0
|
||||
|
||||
/obj/item/weapon/paper/talisman/supply/Topic(href, href_list)
|
||||
world.log << "[usr], [href], [href_list]"
|
||||
if(QDELETED(src) || usr.incapacitated() || !in_range(src, usr))
|
||||
return
|
||||
|
||||
|
||||
@@ -270,7 +270,7 @@
|
||||
if(target.use(25))
|
||||
new /obj/structure/constructshell(T)
|
||||
to_chat(user, "<span class='warning'>The talisman clings to the metal and twists it into a construct shell!</span>")
|
||||
user << sound('sound/effects/magic.ogg',0,1,25)
|
||||
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
|
||||
invoke(user, 1)
|
||||
qdel(src)
|
||||
else
|
||||
@@ -281,7 +281,7 @@
|
||||
new /obj/item/stack/sheet/runed_metal(T,quantity)
|
||||
target.use(quantity)
|
||||
to_chat(user, "<span class='warning'>The talisman clings to the plasteel, transforming it into runed metal!</span>")
|
||||
user << sound('sound/effects/magic.ogg',0,1,25)
|
||||
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
|
||||
invoke(user, 1)
|
||||
if(uses <= 0)
|
||||
qdel(src)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user