Merge branch 'master' into upstream-merge-31044
This commit is contained in:
@@ -19,3 +19,6 @@
|
||||
#define ANTAG_DATUM_IAA_AI_CUSTOM /datum/antagonist/traitor/AI/internal_affairs/custom
|
||||
#define ANTAG_DATUM_IAA_AI /datum/antagonist/traitor/AI/internal_affairs
|
||||
#define ANTAG_DATUM_BROTHER /datum/antagonist/brother
|
||||
#define ANTAG_DATUM_ABDUCTOR /datum/antagonist/abductor
|
||||
#define ANTAG_DATUM_ABDUCTOR_SCIENTIST /datum/antagonist/abductor/scientist
|
||||
#define ANTAG_DATUM_ABDUCTOR_AGENT /datum/antagonist/abductor/agent
|
||||
|
||||
11
code/__DEFINES/cinematics.dm
Normal file
11
code/__DEFINES/cinematics.dm
Normal file
@@ -0,0 +1,11 @@
|
||||
#define CINEMATIC_DEFAULT 1
|
||||
#define CINEMATIC_SELFDESTRUCT 2
|
||||
#define CINEMATIC_SELFDESTRUCT_MISS 3
|
||||
#define CINEMATIC_NUKE_WIN 4
|
||||
#define CINEMATIC_NUKE_MISS 5
|
||||
#define CINEMATIC_ANNIHILATION 6
|
||||
#define CINEMATIC_MALF 7
|
||||
#define CINEMATIC_CULT 8
|
||||
#define CINEMATIC_NUKE_FAKE 9
|
||||
#define CINEMATIC_NUKE_NO_CORE 10
|
||||
#define CINEMATIC_NUKE_FAR 11
|
||||
@@ -8,43 +8,31 @@
|
||||
GLOBAL_VAR_INIT(clockwork_construction_value, 0) //The total value of all structures built by the clockwork cult
|
||||
GLOBAL_VAR_INIT(clockwork_caches, 0) //How many clockwork caches exist in the world (not each individual)
|
||||
GLOBAL_VAR_INIT(clockwork_vitality, 0) //How much Vitality is stored, total
|
||||
GLOBAL_LIST_EMPTY(active_daemons) //A list of all active tinkerer's daemons
|
||||
GLOBAL_VAR_INIT(clockwork_power, 0) //How many watts of power are globally available to the clockwork cult
|
||||
|
||||
GLOBAL_LIST_EMPTY(all_clockwork_objects) //All clockwork items, structures, and effects in existence
|
||||
GLOBAL_LIST_EMPTY(all_clockwork_mobs) //All clockwork SERVANTS (not creatures) in existence
|
||||
GLOBAL_LIST_INIT(clockwork_component_cache, list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 0, HIEROPHANT_ANSIBLE = 0)) //The pool of components that caches draw from
|
||||
|
||||
GLOBAL_VAR_INIT(ratvar_approaches, 0) //The servants can choose to "herald" Ratvar, permanently buffing them but announcing their presence to the crew.
|
||||
GLOBAL_VAR_INIT(ratvar_awakens, 0) //If Ratvar has been summoned; not a boolean, for proper handling of multiple Ratvars
|
||||
GLOBAL_VAR_INIT(ark_of_the_clockwork_justiciar, FALSE) //The Ark on the Reebe z-level
|
||||
|
||||
GLOBAL_VAR_INIT(clockwork_gateway_activated, FALSE) //if a gateway to the celestial derelict has ever been successfully activated
|
||||
GLOBAL_VAR_INIT(script_scripture_unlocked, FALSE) //If script scripture is available, through converting at least one crewmember
|
||||
GLOBAL_VAR_INIT(application_scripture_unlocked, FALSE) //If script scripture is available
|
||||
GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not used to track existing scripture
|
||||
|
||||
//Scripture tiers and requirements; peripherals should never be used
|
||||
#define SCRIPTURE_PERIPHERAL "Peripheral"
|
||||
#define SCRIPTURE_DRIVER "Driver"
|
||||
#define SCRIPTURE_SCRIPT "Script"
|
||||
#define SCRIPT_SERVANT_REQ 6
|
||||
#define SCRIPT_CACHE_REQ 1
|
||||
#define SCRIPTURE_APPLICATION "Application"
|
||||
#define APPLICATION_SERVANT_REQ 9
|
||||
#define APPLICATION_CACHE_REQ 3
|
||||
#define APPLICATION_CV_REQ 100
|
||||
#define SCRIPTURE_JUDGEMENT "Judgement"
|
||||
#define JUDGEMENT_SERVANT_REQ 12
|
||||
#define JUDGEMENT_CACHE_REQ 5
|
||||
#define JUDGEMENT_CV_REQ 300
|
||||
|
||||
//general component/cooldown things
|
||||
#define SLAB_PRODUCTION_TIME 450 //how long(deciseconds) slabs require to produce a single component; defaults to 45 seconds
|
||||
//Various costs related to power.
|
||||
#define SCRIPT_UNLOCK_THRESHOLD 50000 //Scripts will unlock if the total power reaches this amount
|
||||
#define APPLICATION_UNLOCK_THRESHOLD 100000 //Applications will unlock if the total powre reaches this amount
|
||||
|
||||
#define SLAB_SERVANT_SLOWDOWN 150 //how much each servant above 5 slows down slab-based generation; defaults to 15 seconds per sevant
|
||||
|
||||
#define SLAB_SLOWDOWN_MAXIMUM 1350 //maximum slowdown from additional servants; defaults to 2 minutes 15 seconds
|
||||
|
||||
#define CACHE_PRODUCTION_TIME 300 //how long(deciseconds) caches require to produce a component; defaults to 30 seconds
|
||||
|
||||
#define ACTIVE_CACHE_SLOWDOWN 50 //how many additional deciseconds caches take to produce a component for each linked cache; defaults to 5 seconds
|
||||
|
||||
#define LOWER_PROB_PER_COMPONENT 10 //how much each component in the cache reduces the weight of getting another of that component type
|
||||
|
||||
#define MAX_COMPONENTS_BEFORE_RAND (10*LOWER_PROB_PER_COMPONENT) //the number of each component, times LOWER_PROB_PER_COMPONENT, you need to have before component generation will become random
|
||||
#define ABSCOND_ABDUCTION_COST 95
|
||||
|
||||
//clockcult power defines
|
||||
#define MIN_CLOCKCULT_POWER 25 //the minimum amount of power clockcult machines will handle gracefully
|
||||
@@ -72,11 +60,11 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
|
||||
//Ark defines
|
||||
#define GATEWAY_SUMMON_RATE 1 //the time amount the Gateway to the Celestial Derelict gets each process tick; defaults to 1 per tick
|
||||
|
||||
#define GATEWAY_REEBE_FOUND 119 //when progress is at or above this, the gateway finds reebe and begins drawing power
|
||||
#define GATEWAY_REEBE_FOUND 240 //when progress is at or above this, the gateway finds reebe and begins drawing power
|
||||
|
||||
#define GATEWAY_RATVAR_COMING 239 //when progress is at or above this, ratvar has entered and is coming through the gateway
|
||||
#define GATEWAY_RATVAR_COMING 480 //when progress is at or above this, ratvar has entered and is coming through the gateway
|
||||
|
||||
#define GATEWAY_RATVAR_ARRIVAL 300 //when progress is at or above this, game over ratvar's here everybody go home
|
||||
#define GATEWAY_RATVAR_ARRIVAL 600 //when progress is at or above this, game over ratvar's here everybody go home
|
||||
|
||||
#define ARK_SUMMON_COST 5 //how many of each component an Ark costs to summon
|
||||
|
||||
@@ -94,6 +82,6 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
|
||||
|
||||
#define OCULAR_WARDEN_EXCLUSION_RANGE 3 //the range at which ocular wardens cannot be placed near other ocular wardens
|
||||
|
||||
#define RATVARIAN_SPEAR_DURATION 1800 //how long ratvarian spears last; defaults to 3 minutes
|
||||
#define CLOCKWORK_ARMOR_COOLDOWN 1800 //The cooldown period between summoning suits of clockwork armor
|
||||
|
||||
#define PRISM_DELAY_DURATION 1200 //how long prolonging prisms delay the shuttle for; defaults to 2 minutes
|
||||
#define RATVARIAN_SPEAR_COOLDOWN 300 //The cooldown period between summoning another Ratvarian spear
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#define HIGH_TURF_LAYER 2.03
|
||||
#define ABOVE_OPEN_TURF_LAYER 2.04
|
||||
#define CLOSED_TURF_LAYER 2.05
|
||||
#define BULLET_HOLE_LAYER 2.06
|
||||
#define ABOVE_NORMAL_TURF_LAYER 2.08
|
||||
#define LATTICE_LAYER 2.2
|
||||
#define DISPOSAL_PIPE_LAYER 2.3
|
||||
|
||||
@@ -3,10 +3,11 @@ The /tg/ codebase currently requires you to have 11 z-levels of the same size di
|
||||
z-level order is important, the order you put them in inside the map config.dm will determine what z level number they are assigned ingame.
|
||||
Names of z-level do not matter, but order does greatly, for instances such as checking alive status of revheads on z1
|
||||
|
||||
current as of 2016/6/2
|
||||
current as of september 17, 2017
|
||||
z1 = station
|
||||
z2 = centcom
|
||||
z5 = mining
|
||||
z6 = city of cogs
|
||||
Everything else = randomized space
|
||||
Last space-z level = empty
|
||||
*/
|
||||
@@ -17,6 +18,7 @@ Last space-z level = empty
|
||||
|
||||
#define MAIN_STATION "Main Station"
|
||||
#define CENTCOM "CentCom"
|
||||
#define CITY_OF_COGS "City of Cogs"
|
||||
#define EMPTY_AREA_1 "Empty Area 1"
|
||||
#define EMPTY_AREA_2 "Empty Area 2"
|
||||
#define MINING "Mining Asteroid"
|
||||
@@ -38,6 +40,7 @@ Last space-z level = empty
|
||||
#define ZLEVEL_STATION_PRIMARY 2
|
||||
#define ZLEVEL_MINING 5
|
||||
#define ZLEVEL_LAVALAND 5
|
||||
#define ZLEVEL_CITYOFCOGS 6
|
||||
#define ZLEVEL_EMPTY_SPACE 12
|
||||
#define ZLEVEL_TRANSIT 11
|
||||
|
||||
|
||||
@@ -62,6 +62,8 @@
|
||||
#define CURSE_WASTING 4 //causes gradual damage
|
||||
#define CURSE_GRASPING 8 //hands reach out from the sides of the screen, doing damage and stunning if they hit the target
|
||||
|
||||
#define STATUS_EFFECT_KINDLE /datum/status_effect/kindle //A knockdown reduced by 1 second for every 3 points of damage the target takes.
|
||||
|
||||
/////////////
|
||||
// NEUTRAL //
|
||||
/////////////
|
||||
|
||||
@@ -474,7 +474,7 @@
|
||||
#error Remie said that lummox was adding a way to get a lists
|
||||
#error contents via list.values, if that is true remove this
|
||||
#error otherwise, update the version and bug lummox
|
||||
#elseif
|
||||
#endif
|
||||
//Flattens a keyed list into a list of it's contents
|
||||
/proc/flatten_list(list/key_list)
|
||||
if(!islist(key_list))
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
/client/proc/file_spam_check()
|
||||
var/time_to_wait = GLOB.fileaccess_timer - world.time
|
||||
if(time_to_wait > 0)
|
||||
to_chat(src, "<font color='red'>Error: file_spam_check(): Spam. Please wait [round(time_to_wait/10)] seconds.</font>")
|
||||
to_chat(src, "<font color='red'>Error: file_spam_check(): Spam. Please wait [DisplayTimeText(time_to_wait)].</font>")
|
||||
return 1
|
||||
GLOB.fileaccess_timer = world.time + FTPDELAY
|
||||
return 0
|
||||
|
||||
@@ -421,7 +421,7 @@
|
||||
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))
|
||||
switch(ignore_category ? askuser(M,Question,"Please answer in [DisplayTimeText(poll_time)]!","Yes","No","Never for this round", StealFocus=0, Timeout=poll_time) : askuser(M,Question,"Please answer in [DisplayTimeText(poll_time)]!","Yes","No", StealFocus=0, Timeout=poll_time))
|
||||
if(1)
|
||||
to_chat(M, "<span class='notice'>Choice registered: Yes.</span>")
|
||||
if(time_passed + poll_time <= world.time)
|
||||
|
||||
@@ -219,3 +219,8 @@ GLOBAL_LIST_INIT(sqrtTable, list(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4,
|
||||
new_x = Clamp(new_x, 0, world.maxx)
|
||||
new_y = Clamp(new_y, 0, world.maxy)
|
||||
return locate(new_x, new_y, starting.z)
|
||||
|
||||
/proc/round_down(num)
|
||||
if(round(num) != num)
|
||||
return round(num--)
|
||||
else return num
|
||||
|
||||
@@ -465,13 +465,17 @@ Proc for attack log creation, because really why not
|
||||
if(H.dna && istype(H.dna.species, species_datum))
|
||||
. = TRUE
|
||||
|
||||
/proc/spawn_atom_to_turf(spawn_type, target, amount, admin_spawn=FALSE)
|
||||
/proc/spawn_atom_to_turf(spawn_type, target, amount, admin_spawn=FALSE, list/extra_args)
|
||||
var/turf/T = get_turf(target)
|
||||
if(!T)
|
||||
CRASH("attempt to spawn atom type: [spawn_type] in nullspace")
|
||||
|
||||
for(var/j in 1 to amount)
|
||||
var/atom/X = new spawn_type(T)
|
||||
var/list/new_args = list(T)
|
||||
if(extra_args)
|
||||
new_args += extra_args
|
||||
|
||||
for(var/j in 1 to amount)
|
||||
var/atom/X = new spawn_type(arglist(new_args))
|
||||
X.admin_spawned = admin_spawn
|
||||
|
||||
/proc/spawn_and_random_walk(spawn_type, target, amount, walk_chance=100, max_walk=3, always_max_walk=FALSE, admin_spawn=FALSE)
|
||||
|
||||
@@ -414,34 +414,159 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
|
||||
end = temp
|
||||
return end
|
||||
|
||||
|
||||
/proc/parsepencode(t, mob/user=null, signfont=SIGNFONT)
|
||||
if(length(t) < 1) //No input means nothing needs to be parsed
|
||||
/proc/parsemarkdown_basic_step1(t, limited=FALSE)
|
||||
if(length(t) <= 0)
|
||||
return
|
||||
|
||||
t = replacetext(t, "\[center\]", "<center>")
|
||||
t = replacetext(t, "\[/center\]", "</center>")
|
||||
t = replacetext(t, "\[br\]", "<BR>")
|
||||
t = replacetext(t, "\[b\]", "<B>")
|
||||
t = replacetext(t, "\[/b\]", "</B>")
|
||||
t = replacetext(t, "\[i\]", "<I>")
|
||||
t = replacetext(t, "\[/i\]", "</I>")
|
||||
t = replacetext(t, "\[u\]", "<U>")
|
||||
t = replacetext(t, "\[/u\]", "</U>")
|
||||
t = replacetext(t, "\[large\]", "<font size=\"4\">")
|
||||
t = replacetext(t, "\[/large\]", "</font>")
|
||||
if(user)
|
||||
t = replacetext(t, "\[sign\]", "<font face=\"[signfont]\"><i>[user.real_name]</i></font>")
|
||||
else
|
||||
t = replacetext(t, "\[sign\]", "")
|
||||
t = replacetext(t, "\[field\]", "<span class=\"paper_field\"></span>")
|
||||
// This parses markdown with no custom rules
|
||||
|
||||
t = replacetext(t, "\[*\]", "<li>")
|
||||
t = replacetext(t, "\[hr\]", "<HR>")
|
||||
t = replacetext(t, "\[small\]", "<font size = \"1\">")
|
||||
t = replacetext(t, "\[/small\]", "</font>")
|
||||
t = replacetext(t, "\[list\]", "<ul>")
|
||||
t = replacetext(t, "\[/list\]", "</ul>")
|
||||
// Escape backslashed
|
||||
|
||||
t = replacetext(t, "$", "$-")
|
||||
t = replacetext(t, "\\\\", "$1")
|
||||
t = replacetext(t, "\\**", "$2")
|
||||
t = replacetext(t, "\\*", "$3")
|
||||
t = replacetext(t, "\\__", "$4")
|
||||
t = replacetext(t, "\\_", "$5")
|
||||
t = replacetext(t, "\\^", "$6")
|
||||
t = replacetext(t, "\\((", "$7")
|
||||
t = replacetext(t, "\\))", "$8")
|
||||
t = replacetext(t, "\\|", "$9")
|
||||
t = replacetext(t, "\\%", "$0")
|
||||
|
||||
// Escape single characters that will be used
|
||||
|
||||
t = replacetext(t, "!", "$a")
|
||||
|
||||
// Parse hr and small
|
||||
|
||||
if(!limited)
|
||||
t = replacetext(t, "((", "<font size=\"1\">")
|
||||
t = replacetext(t, "))", "</font>")
|
||||
t = replacetext(t, regex("^-{3,}$", "gm"), "<hr>")
|
||||
t = replacetext(t, regex("^\\(-{3,})$", "gm"), "$1")
|
||||
|
||||
// Parse lists
|
||||
|
||||
var/list/tlist = splittext(t, "\n")
|
||||
var/tlistlen = tlist.len
|
||||
var/listlevel = -1
|
||||
var/singlespace = -1 // if 0, double spaces are used before asterisks, if 1, single are
|
||||
for(var/i = 1, i <= tlistlen, i++)
|
||||
var/line = tlist[i]
|
||||
var/count_asterisk = length(replacetext(line, regex("\[^\\*\]+", "g"), ""))
|
||||
if(count_asterisk % 2 == 1 && findtext(line, regex("^\\s*\\*", "g"))) // there is an extra asterisk in the beggining
|
||||
|
||||
var/count_w = length(replacetext(line, regex("^( *)\\*.*$", "g"), "$1")) // whitespace before asterisk
|
||||
line = replacetext(line, regex("^ *(\\*.*)$", "g"), "$1")
|
||||
|
||||
if(singlespace == -1 && count_w == 2)
|
||||
if(listlevel == 0)
|
||||
singlespace = 0
|
||||
else
|
||||
singlespace = 1
|
||||
|
||||
if(singlespace == 0)
|
||||
count_w = count_w % 2 ? round(count_w / 2 + 0.25) : count_w / 2
|
||||
|
||||
line = replacetext(line, regex("\\*", ""), "<li>")
|
||||
while(listlevel < count_w)
|
||||
line = "<ul>" + line
|
||||
listlevel++
|
||||
while(listlevel > count_w)
|
||||
line = "</ul>" + line
|
||||
listlevel--
|
||||
|
||||
else while(listlevel >= 0)
|
||||
line = "</ul>" + line
|
||||
listlevel--
|
||||
|
||||
tlist[i] = line
|
||||
// end for
|
||||
|
||||
t = tlist[1]
|
||||
for(var/i = 2, i <= tlistlen, i++)
|
||||
t += "\n" + tlist[i]
|
||||
|
||||
while(listlevel >= 0)
|
||||
t += "</ul>"
|
||||
listlevel--
|
||||
|
||||
else
|
||||
t = replacetext(t, "((", "")
|
||||
t = replacetext(t, "))", "")
|
||||
|
||||
// Parse headers
|
||||
|
||||
t = replacetext(t, regex("^#(?!#) ?(.+)$", "gm"), "<h2>$1</h2>")
|
||||
t = replacetext(t, regex("^##(?!#) ?(.+)$", "gm"), "<h3>$1</h3>")
|
||||
t = replacetext(t, regex("^###(?!#) ?(.+)$", "gm"), "<h4>$1</h4>")
|
||||
t = replacetext(t, regex("^#### ?(.+)$", "gm"), "<h5>$1</h5>")
|
||||
|
||||
// Parse most rules
|
||||
|
||||
t = replacetext(t, regex("\\*(\[^\\*\]*)\\*", "g"), "<i>$1</i>")
|
||||
t = replacetext(t, regex("_(\[^_\]*)_", "g"), "<i>$1</i>")
|
||||
t = replacetext(t, "<i></i>", "!")
|
||||
t = replacetext(t, "</i><i>", "!")
|
||||
t = replacetext(t, regex("\\!(\[^\\!\]+)\\!", "g"), "<b>$1</b>")
|
||||
t = replacetext(t, regex("\\^(\[^\\^\]+)\\^", "g"), "<font size=\"4\">$1</font>")
|
||||
t = replacetext(t, regex("\\|(\[^\\|\]+)\\|", "g"), "<center>$1</center>")
|
||||
t = replacetext(t, "!", "</i><i>")
|
||||
|
||||
return t
|
||||
|
||||
/proc/parsemarkdown_basic_step2(t)
|
||||
if(length(t) <= 0)
|
||||
return
|
||||
|
||||
// Restore the single characters used
|
||||
|
||||
t = replacetext(t, "$a", "!")
|
||||
|
||||
// Redo the escaping
|
||||
|
||||
t = replacetext(t, "$1", "\\")
|
||||
t = replacetext(t, "$2", "**")
|
||||
t = replacetext(t, "$3", "*")
|
||||
t = replacetext(t, "$4", "__")
|
||||
t = replacetext(t, "$5", "_")
|
||||
t = replacetext(t, "$6", "^")
|
||||
t = replacetext(t, "$7", "((")
|
||||
t = replacetext(t, "$8", "))")
|
||||
t = replacetext(t, "$9", "|")
|
||||
t = replacetext(t, "$0", "%")
|
||||
t = replacetext(t, "$-", "$")
|
||||
|
||||
return t
|
||||
|
||||
/proc/parsemarkdown_basic(t, limited=FALSE)
|
||||
t = parsemarkdown_basic_step1(t, limited)
|
||||
t = parsemarkdown_basic_step2(t)
|
||||
return t
|
||||
|
||||
/proc/parsemarkdown(t, mob/user=null, limited=FALSE)
|
||||
if(length(t) <= 0)
|
||||
return
|
||||
|
||||
// Premanage whitespace
|
||||
|
||||
t = replacetext(t, regex("\[^\\S\\r\\n \]", "g"), " ")
|
||||
|
||||
t = parsemarkdown_basic_step1(t)
|
||||
|
||||
t = replacetext(t, regex("%s(?:ign)?(?=\\s|$)", "igm"), user ? "<font face=\"[SIGNFONT]\"><i>[user.real_name]</i></font>" : "<span class=\"paper_field\"></span>")
|
||||
t = replacetext(t, regex("%f(?:ield)?(?=\\s|$)", "igm"), "<span class=\"paper_field\"></span>")
|
||||
|
||||
t = parsemarkdown_basic_step2(t)
|
||||
|
||||
// Manage whitespace
|
||||
|
||||
t = replacetext(t, regex("(?:\\r\\n?|\\n)", "g"), "<br>")
|
||||
|
||||
t = replacetext(t, " ", " ")
|
||||
|
||||
// Done
|
||||
|
||||
return t
|
||||
|
||||
|
||||
@@ -1,52 +1,148 @@
|
||||
//Returns the world time in english
|
||||
/proc/worldtime2text()
|
||||
return gameTimestamp("hh:mm:ss", world.time)
|
||||
|
||||
/proc/time_stamp(format = "hh:mm:ss", show_ds)
|
||||
var/time_string = time2text(world.timeofday, format)
|
||||
return show_ds ? "[time_string]:[world.timeofday % 10]" : time_string
|
||||
|
||||
/proc/gameTimestamp(format = "hh:mm:ss", wtime=null)
|
||||
if(!wtime)
|
||||
wtime = world.time
|
||||
return time2text(wtime - GLOB.timezoneOffset + SSticker.gametime_offset - SSticker.round_start_time, format)
|
||||
|
||||
/* Returns 1 if it is the selected month and day */
|
||||
/proc/isDay(month, day)
|
||||
if(isnum(month) && isnum(day))
|
||||
var/MM = text2num(time2text(world.timeofday, "MM")) // get the current month
|
||||
var/DD = text2num(time2text(world.timeofday, "DD")) // get the current day
|
||||
if(month == MM && day == DD)
|
||||
return 1
|
||||
|
||||
// Uncomment this out when debugging!
|
||||
//else
|
||||
//return 1
|
||||
|
||||
//returns timestamp in a sql and ISO 8601 friendly format
|
||||
/proc/SQLtime(timevar)
|
||||
if(!timevar)
|
||||
timevar = world.realtime
|
||||
return time2text(timevar, "YYYY-MM-DD hh:mm:ss")
|
||||
|
||||
|
||||
GLOBAL_VAR_INIT(midnight_rollovers, 0)
|
||||
GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0)
|
||||
/proc/update_midnight_rollover()
|
||||
if (world.timeofday < GLOB.rollovercheck_last_timeofday) //TIME IS GOING BACKWARDS!
|
||||
return GLOB.midnight_rollovers++
|
||||
return GLOB.midnight_rollovers
|
||||
|
||||
/proc/weekdayofthemonth()
|
||||
var/DD = text2num(time2text(world.timeofday, "DD")) // get the current day
|
||||
switch(DD)
|
||||
if(8 to 13)
|
||||
return 2
|
||||
if(14 to 20)
|
||||
return 3
|
||||
if(21 to 27)
|
||||
return 4
|
||||
if(28 to INFINITY)
|
||||
return 5
|
||||
else
|
||||
return 1
|
||||
//Returns the world time in english
|
||||
/proc/worldtime2text()
|
||||
return gameTimestamp("hh:mm:ss", world.time)
|
||||
|
||||
/proc/time_stamp(format = "hh:mm:ss", show_ds)
|
||||
var/time_string = time2text(world.timeofday, format)
|
||||
return show_ds ? "[time_string]:[world.timeofday % 10]" : time_string
|
||||
|
||||
/proc/gameTimestamp(format = "hh:mm:ss", wtime=null)
|
||||
if(!wtime)
|
||||
wtime = world.time
|
||||
return time2text(wtime - GLOB.timezoneOffset + SSticker.gametime_offset - SSticker.round_start_time, format)
|
||||
|
||||
/* Returns 1 if it is the selected month and day */
|
||||
/proc/isDay(month, day)
|
||||
if(isnum(month) && isnum(day))
|
||||
var/MM = text2num(time2text(world.timeofday, "MM")) // get the current month
|
||||
var/DD = text2num(time2text(world.timeofday, "DD")) // get the current day
|
||||
if(month == MM && day == DD)
|
||||
return 1
|
||||
|
||||
// Uncomment this out when debugging!
|
||||
//else
|
||||
//return 1
|
||||
|
||||
//returns timestamp in a sql and ISO 8601 friendly format
|
||||
/proc/SQLtime(timevar)
|
||||
if(!timevar)
|
||||
timevar = world.realtime
|
||||
return time2text(timevar, "YYYY-MM-DD hh:mm:ss")
|
||||
|
||||
|
||||
GLOBAL_VAR_INIT(midnight_rollovers, 0)
|
||||
GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0)
|
||||
/proc/update_midnight_rollover()
|
||||
if (world.timeofday < GLOB.rollovercheck_last_timeofday) //TIME IS GOING BACKWARDS!
|
||||
return GLOB.midnight_rollovers++
|
||||
return GLOB.midnight_rollovers
|
||||
|
||||
/proc/weekdayofthemonth()
|
||||
var/DD = text2num(time2text(world.timeofday, "DD")) // get the current day
|
||||
switch(DD)
|
||||
if(8 to 13)
|
||||
return 2
|
||||
if(14 to 20)
|
||||
return 3
|
||||
if(21 to 27)
|
||||
return 4
|
||||
if(28 to INFINITY)
|
||||
return 5
|
||||
else
|
||||
return 1
|
||||
|
||||
//Takes a value of time in deciseconds.
|
||||
//Returns a text value of that number in hours, minutes, or seconds.
|
||||
/proc/DisplayTimeText(time_value)
|
||||
var/second = time_value*0.1
|
||||
var/second_adjusted = null
|
||||
var/second_rounded = FALSE
|
||||
var/minute = null
|
||||
var/hour = null
|
||||
var/day = null
|
||||
|
||||
if(!second)
|
||||
return "0 seconds"
|
||||
if(second >= 60)
|
||||
minute = round_down(second/60)
|
||||
second = round(second - (minute*60), 0.1)
|
||||
second_rounded = TRUE
|
||||
if(second) //check if we still have seconds remaining to format, or if everything went into minute.
|
||||
second_adjusted = round(second) //used to prevent '1 seconds' being shown
|
||||
if(day || hour || minute)
|
||||
if(second_adjusted == 1 && second >= 1)
|
||||
second = " and 1 second"
|
||||
else if(second > 1)
|
||||
second = " and [second_adjusted] seconds"
|
||||
else //shows a fraction if seconds is < 1
|
||||
if(second_rounded) //no sense rounding again if it's already done
|
||||
second = " and [second] seconds"
|
||||
else
|
||||
second = " and [round(second, 0.1)] seconds"
|
||||
else
|
||||
if(second_adjusted == 1 && second >= 1)
|
||||
second = "1 second"
|
||||
else if(second > 1)
|
||||
second = "[second_adjusted] seconds"
|
||||
else
|
||||
if(second_rounded)
|
||||
second = "[second] seconds"
|
||||
else
|
||||
second = "[round(second, 0.1)] seconds"
|
||||
else
|
||||
second = null
|
||||
|
||||
if(!minute)
|
||||
return "[second]"
|
||||
if(minute >= 60)
|
||||
hour = round_down(minute/60,1)
|
||||
minute = (minute - (hour*60))
|
||||
if(minute) //alot simpler from here since you don't have to worry about fractions
|
||||
if(minute != 1)
|
||||
if((day || hour) && second)
|
||||
minute = ", [minute] minutes"
|
||||
else if((day || hour) && !second)
|
||||
minute = " and [minute] minutes"
|
||||
else
|
||||
minute = "[minute] minutes"
|
||||
else
|
||||
if((day || hour) && second)
|
||||
minute = ", 1 minute"
|
||||
else if((day || hour) && !second)
|
||||
minute = " and 1 minute"
|
||||
else
|
||||
minute = "1 minute"
|
||||
else
|
||||
minute = null
|
||||
|
||||
if(!hour)
|
||||
return "[minute][second]"
|
||||
if(hour >= 24)
|
||||
day = round_down(hour/24,1)
|
||||
hour = (hour - (day*24))
|
||||
if(hour)
|
||||
if(hour != 1)
|
||||
if(day && (minute || second))
|
||||
hour = ", [hour] hours"
|
||||
else if(day && (!minute || !second))
|
||||
hour = " and [hour] hours"
|
||||
else
|
||||
hour = "[hour] hours"
|
||||
else
|
||||
if(day && (minute || second))
|
||||
hour = ", 1 hour"
|
||||
else if(day && (!minute || !second))
|
||||
hour = " and 1 hour"
|
||||
else
|
||||
hour = "1 hour"
|
||||
else
|
||||
hour = null
|
||||
|
||||
if(!day)
|
||||
return "[hour][minute][second]"
|
||||
if(day > 1)
|
||||
day = "[day] days"
|
||||
else
|
||||
day = "1 day"
|
||||
|
||||
return "[day][hour][minute][second]"
|
||||
|
||||
@@ -502,28 +502,12 @@ Turf and target are separate in case you want to teleport some distance from a t
|
||||
var/y=arcsin(x/sqrt(1+x*x))
|
||||
return y
|
||||
|
||||
/atom/proc/GetAllContents(list/ignore_typecache)
|
||||
var/list/processing_list = list(src)
|
||||
var/list/assembled = list()
|
||||
if(ignore_typecache) //If there's a typecache, use it.
|
||||
while(processing_list.len)
|
||||
var/atom/A = processing_list[1]
|
||||
processing_list -= A
|
||||
if(ignore_typecache[A.type])
|
||||
continue
|
||||
processing_list |= (A.contents - assembled)
|
||||
assembled |= A
|
||||
|
||||
else //If there's none, only make this check once for performance.
|
||||
while(processing_list.len)
|
||||
var/atom/A = processing_list[1]
|
||||
processing_list -= A
|
||||
|
||||
processing_list |= (A.contents - assembled)
|
||||
|
||||
assembled |= A
|
||||
|
||||
return assembled
|
||||
/atom/proc/GetAllContents(list/output=list())
|
||||
. = output
|
||||
output += src
|
||||
for(var/i in 1 to contents.len)
|
||||
var/atom/thing = contents[i]
|
||||
thing.GetAllContents(output)
|
||||
|
||||
//Step-towards method of determining whether one atom can see another. Similar to viewers()
|
||||
/proc/can_see(atom/source, atom/target, length=5) // I couldnt be arsed to do actual raycasting :I This is horribly inaccurate.
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#define MAX_CHARTER_LEN 80
|
||||
|
||||
//MINOR TWEAKS/MISC
|
||||
#define AGE_MIN 17 //youngest a character can be
|
||||
#define AGE_MIN 18 //youngest a character can be
|
||||
#define AGE_MAX 85 //oldest a character can be
|
||||
#define WIZARD_AGE_MIN 30 //youngest a wizard can be
|
||||
#define SHOES_SLOWDOWN 0 //How much shoes slow you down by default. Negative values speed you up
|
||||
|
||||
@@ -33,6 +33,8 @@ GLOBAL_LIST_EMPTY(department_security_spawns) //list of all department security
|
||||
GLOBAL_LIST_EMPTY(generic_event_spawns) //list of all spawns for events
|
||||
|
||||
GLOBAL_LIST_EMPTY(wizardstart)
|
||||
GLOBAL_LIST_EMPTY(nukeop_start)
|
||||
GLOBAL_LIST_EMPTY(nukeop_leader_start)
|
||||
GLOBAL_LIST_EMPTY(newplayer_start)
|
||||
GLOBAL_LIST_EMPTY(prisonwarp) //prisoners go to these
|
||||
GLOBAL_LIST_EMPTY(holdingfacility) //captured people go here
|
||||
@@ -46,6 +48,8 @@ GLOBAL_LIST_EMPTY(blobstart)
|
||||
GLOBAL_LIST_EMPTY(secequipment)
|
||||
GLOBAL_LIST_EMPTY(deathsquadspawn)
|
||||
GLOBAL_LIST_EMPTY(emergencyresponseteamspawn)
|
||||
GLOBAL_LIST_EMPTY(servant_spawns) //Servants of Ratvar spawn here
|
||||
GLOBAL_LIST_EMPTY(city_of_cogs_spawns) //Anyone entering the City of Cogs spawns here
|
||||
GLOBAL_LIST_EMPTY(ruin_landmarks)
|
||||
|
||||
//away missions
|
||||
|
||||
@@ -378,90 +378,6 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
|
||||
/obj/screen/alert/clockwork
|
||||
alerttooltipstyle = "clockcult"
|
||||
|
||||
/obj/screen/alert/clockwork/scripture_reqs
|
||||
name = "Next Tier Requirements"
|
||||
desc = "You shouldn't be seeing this description unless you're very fast. If you're very fast, good job!"
|
||||
icon_state = "no-servants-caches"
|
||||
|
||||
/obj/screen/alert/clockwork/scripture_reqs/Initialize()
|
||||
. = ..()
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
process()
|
||||
|
||||
/obj/screen/alert/clockwork/scripture_reqs/Destroy()
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
return ..()
|
||||
|
||||
/obj/screen/alert/clockwork/scripture_reqs/process()
|
||||
if(GLOB.clockwork_gateway_activated)
|
||||
mob_viewer.clear_alert("scripturereq")
|
||||
return
|
||||
var/current_state
|
||||
for(var/i in SSticker.scripture_states)
|
||||
if(!SSticker.scripture_states[i])
|
||||
current_state = i
|
||||
break
|
||||
icon_state = "no"
|
||||
if(!current_state)
|
||||
name = "Current Objective"
|
||||
for(var/obj/structure/destructible/clockwork/massive/celestial_gateway/G in GLOB.all_clockwork_objects)
|
||||
var/area/gate_area = get_area(G)
|
||||
desc = "<b>Protect the Ark at [gate_area.map_name]!</b>"
|
||||
return
|
||||
desc = "<b>All tiers of Scripture are unlocked.<br>\
|
||||
Acquire components and summon the Ark.</b>"
|
||||
else
|
||||
name = "Next Tier Requirements"
|
||||
var/validservants = 0
|
||||
var/unconverted_ais_exist = get_unconverted_ais()
|
||||
for(var/mob/living/L in GLOB.living_mob_list)
|
||||
if(is_servant_of_ratvar(L) && (ishuman(L) || issilicon(L)))
|
||||
validservants++
|
||||
var/req_servants = 0
|
||||
var/req_caches = 0
|
||||
var/req_cv = 0
|
||||
var/req_ai = FALSE
|
||||
var/list/textlist = list("Requirements for <b>[current_state] Scripture:</b>")
|
||||
switch(current_state) //get our requirements based on the tier
|
||||
if(SCRIPTURE_SCRIPT)
|
||||
req_servants = SCRIPT_SERVANT_REQ
|
||||
req_caches = SCRIPT_CACHE_REQ
|
||||
if(SCRIPTURE_APPLICATION)
|
||||
req_servants = APPLICATION_SERVANT_REQ
|
||||
req_caches = APPLICATION_CACHE_REQ
|
||||
req_cv = APPLICATION_CV_REQ
|
||||
if(SCRIPTURE_JUDGEMENT)
|
||||
req_servants = JUDGEMENT_SERVANT_REQ
|
||||
req_caches = JUDGEMENT_CACHE_REQ
|
||||
req_cv = JUDGEMENT_CV_REQ
|
||||
req_ai = TRUE
|
||||
textlist += "<br><b>[validservants]/[req_servants]</b> Servants"
|
||||
if(validservants < req_servants)
|
||||
icon_state += "-servants" //in this manner, generate an icon key based on what we're missing
|
||||
else
|
||||
textlist += ": <b><font color=#5A6068>\[CHECK\]</font></b>"
|
||||
textlist += "<br><b>[GLOB.clockwork_caches]/[req_caches]</b> Tinkerer's Caches"
|
||||
if(GLOB.clockwork_caches < req_caches)
|
||||
icon_state += "-caches"
|
||||
else
|
||||
textlist += ": <b><font color=#5A6068>\[CHECK\]</font></b>"
|
||||
if(req_cv) //cv only shows up if the tier requires it
|
||||
textlist += "<br><b>[GLOB.clockwork_construction_value]/[req_cv]</b> Construction Value"
|
||||
if(GLOB.clockwork_construction_value < req_cv)
|
||||
icon_state += "-cv"
|
||||
else
|
||||
textlist += ": <b><font color=#5A6068>\[CHECK\]</font></b>"
|
||||
if(req_ai) //same for ai
|
||||
if(unconverted_ais_exist)
|
||||
if(unconverted_ais_exist > 1)
|
||||
textlist += "<br><b>[unconverted_ais_exist] unconverted AIs exist!</b><br>"
|
||||
else
|
||||
textlist += "<br><b>An unconverted AI exists!</b>"
|
||||
icon_state += "-ai"
|
||||
else
|
||||
textlist += "<br>No unconverted AIs exist: <b><font color=#5A6068>\[CHECK\]</font></b>"
|
||||
desc = textlist.Join()
|
||||
|
||||
/obj/screen/alert/clockwork/infodump
|
||||
name = "Global Records"
|
||||
desc = "You shouldn't be seeing this description, because it should be dynamically generated."
|
||||
@@ -473,7 +389,6 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
|
||||
else
|
||||
var/servants = 0
|
||||
var/validservants = 0
|
||||
var/unconverted_ais_exist = get_unconverted_ais()
|
||||
var/list/textlist
|
||||
for(var/mob/living/L in GLOB.living_mob_list)
|
||||
if(is_servant_of_ratvar(L))
|
||||
@@ -487,29 +402,25 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
|
||||
textlist = list("<b>[servants]</b> Servants, [validservants ? "<b>[validservants]</b> of which counts":"none of which count"] towards scripture.<br>")
|
||||
else
|
||||
textlist = list("<b>[servants]</b> Servant, who [validservants ? "counts":"does not count"] towards scripture.<br>")
|
||||
textlist += "<b>[GLOB.clockwork_caches ? "[GLOB.clockwork_caches]</b> Tinkerer's Caches.":"No Tinkerer's Caches, construct one!</b>"]<br>\
|
||||
<b>[GLOB.clockwork_construction_value]</b> Construction Value.<br>"
|
||||
textlist += "<b>[Floor(servants * 0.2)]</b> Tinkerer's Daemons can be active at once. <b>[LAZYLEN(GLOB.active_daemons)]</b> are active.<br>"
|
||||
for(var/obj/structure/destructible/clockwork/massive/celestial_gateway/G in GLOB.all_clockwork_objects)
|
||||
var/area/gate_area = get_area(G)
|
||||
textlist += "Ark Location: <b>[uppertext(gate_area.map_name)]</b><br>"
|
||||
if(G.still_needs_components())
|
||||
textlist += "Ark Components required:<br>"
|
||||
for(var/i in G.required_components)
|
||||
if(G.required_components[i])
|
||||
textlist += "[get_component_icon(i)] <b><font color=[get_component_color_bright(i)]>[G.required_components[i]]</font></b> "
|
||||
textlist += "<br>"
|
||||
else
|
||||
textlist += "Seconds until Ratvar's arrival: <b>[G.get_arrival_text(TRUE)]</b><br>"
|
||||
break
|
||||
if(unconverted_ais_exist)
|
||||
if(unconverted_ais_exist > 1)
|
||||
textlist += "<b>[unconverted_ais_exist] unconverted AIs exist!</b><br>"
|
||||
else
|
||||
textlist += "<b>An unconverted AI exists!</b><br>"
|
||||
for(var/i in SSticker.scripture_states)
|
||||
if(i != SCRIPTURE_DRIVER) //ignore the always-unlocked stuff
|
||||
textlist += "[i] Scripture: <b>[SSticker.scripture_states[i] ? "UNLOCKED":"LOCKED"]</b><br>"
|
||||
for(var/i in SSticker.scripture_states)
|
||||
if(i != SCRIPTURE_DRIVER) //ignore the always-unlocked stuff
|
||||
textlist += "[i] Scripture: <b>[SSticker.scripture_states[i] ? "UNLOCKED":"LOCKED"]</b><br>"
|
||||
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
|
||||
if(G)
|
||||
var/time_info
|
||||
var/time_name
|
||||
if(G.seconds_until_activation)
|
||||
time_info = G.seconds_until_activation
|
||||
time_name = "until the Ark activates"
|
||||
else if(G.grace_period)
|
||||
time_info = G.grace_period
|
||||
time_name = "of grace period remaining"
|
||||
else if(G.progress_in_seconds)
|
||||
time_info = GATEWAY_RATVAR_ARRIVAL - G.progress_in_seconds
|
||||
time_name = "until the Ark finishes summoning"
|
||||
if(time_info)
|
||||
textlist += "<b>[time_info / 60] minutes</b> [time_name].<br>"
|
||||
textlist += "<b>[DisplayPower(get_clockwork_power())]</b> power available for use."
|
||||
desc = textlist.Join()
|
||||
..()
|
||||
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/datum/hud/marauder
|
||||
var/obj/screen/hosthealth
|
||||
var/obj/screen/blockchance
|
||||
var/obj/screen/counterchance
|
||||
|
||||
/datum/hud/marauder/New(mob/living/simple_animal/hostile/guardian/owner)
|
||||
..()
|
||||
var/obj/screen/using
|
||||
|
||||
healths = new /obj/screen/healths/clock()
|
||||
infodisplay += healths
|
||||
|
||||
hosthealth = new /obj/screen/healths/clock()
|
||||
hosthealth.screen_loc = ui_internal
|
||||
infodisplay += hosthealth
|
||||
|
||||
using = new /obj/screen/marauder/emerge()
|
||||
using.screen_loc = ui_zonesel
|
||||
static_inventory += using
|
||||
|
||||
/datum/hud/marauder/Destroy()
|
||||
blockchance = null
|
||||
counterchance = null
|
||||
hosthealth = null
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/create_mob_hud()
|
||||
if(client && !hud_used)
|
||||
hud_used = new /datum/hud/marauder(src, ui_style2icon(client.prefs.UI_style))
|
||||
|
||||
/obj/screen/marauder
|
||||
icon = 'icons/mob/clockwork_mobs.dmi'
|
||||
|
||||
/obj/screen/marauder/emerge
|
||||
icon_state = "marauder_emerge"
|
||||
name = "Emerge/Return"
|
||||
desc = "Emerge or Return."
|
||||
|
||||
/obj/screen/marauder/emerge/Click()
|
||||
if(istype(usr, /mob/living/simple_animal/hostile/clockwork/marauder))
|
||||
var/mob/living/simple_animal/hostile/clockwork/marauder/M = usr
|
||||
if(M.is_in_host())
|
||||
M.try_emerge()
|
||||
else
|
||||
M.return_to_host()
|
||||
@@ -172,6 +172,27 @@
|
||||
spread = 30 //should be 40 for XCOM memes, but since its adminspawn only, might as well make it useable
|
||||
recoil = 1
|
||||
|
||||
///toy memes///
|
||||
|
||||
/obj/item/ammo_box/magazine/toy/x9
|
||||
name = "foam force X9 magazine"
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "toy9magazine"
|
||||
max_ammo = 30
|
||||
multiple_sprites = 2
|
||||
|
||||
/obj/item/gun/ballistic/automatic/x9/toy
|
||||
name = "donksoft X9"
|
||||
desc = "An old but reliable assault rifle made for combat against unknown enemies. Appears to be hastily converted. Ages 8 and up."
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "toy9"
|
||||
can_suppress = 0
|
||||
needs_permit = 0
|
||||
mag_type = /obj/item/ammo_box/magazine/toy/x9
|
||||
casing_ejector = 0
|
||||
spread = 45 //MAXIMUM XCOM MEMES (actually that'd be 90 spread)
|
||||
|
||||
|
||||
////////XCOM2 Magpistol/////////
|
||||
|
||||
//////projectiles//////
|
||||
@@ -213,7 +234,7 @@
|
||||
|
||||
//////magazines/////
|
||||
|
||||
/obj/item/ammo_box/magazine/mmags
|
||||
/obj/item/ammo_box/magazine/mmag/small
|
||||
name = "magpistol magazine (non-lethal disabler)"
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "nlmagmag"
|
||||
@@ -223,7 +244,7 @@
|
||||
max_ammo = 7
|
||||
multiple_sprites = 2
|
||||
|
||||
/obj/item/ammo_box/magazine/mmags/lethal
|
||||
/obj/item/ammo_box/magazine/mmag/small/lethal
|
||||
name = "magpistol magazine (lethal)"
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "smallmagmag"
|
||||
@@ -239,7 +260,7 @@
|
||||
icon_state = "magpistol"
|
||||
force = 10
|
||||
fire_sound = 'sound/weapons/magpistol.ogg'
|
||||
mag_type = /obj/item/ammo_box/magazine/mmags
|
||||
mag_type = /obj/item/ammo_box/magazine/mmag/small
|
||||
can_suppress = 0
|
||||
casing_ejector = 0
|
||||
fire_delay = 5
|
||||
@@ -276,7 +297,7 @@
|
||||
req_tech = list("combat" = 5, "magnets" = 6, "materials" = 5, "syndicate" = 3)
|
||||
build_type = PROTOLATHE
|
||||
materials = list(MAT_METAL = 4000, MAT_SILVER = 500)
|
||||
build_path = /obj/item/ammo_box/magazine/mmags/lethal
|
||||
build_path = /obj/item/ammo_box/magazine/mmag/small/lethal
|
||||
category = list("Ammo")
|
||||
|
||||
/datum/design/mag_magpistol/nl
|
||||
@@ -285,7 +306,7 @@
|
||||
id = "mag_magpistol_nl"
|
||||
req_tech = list("combat" = 5, "magnets" = 6, "materials" = 5)
|
||||
materials = list(MAT_METAL = 3000, MAT_SILVER = 250, MAT_TITANIUM = 250)
|
||||
build_path = /obj/item/ammo_box/magazine/mmags
|
||||
build_path = /obj/item/ammo_box/magazine/mmag/small
|
||||
|
||||
//////toy memes/////
|
||||
|
||||
@@ -339,3 +360,412 @@
|
||||
materials = list(MAT_METAL = 7500, MAT_GLASS = 1000)
|
||||
build_path = /obj/item/gun/ballistic/shotgun/toy/mag
|
||||
category = list("hacked", "Misc")
|
||||
|
||||
//////Magrifle//////
|
||||
|
||||
///projectiles///
|
||||
|
||||
/obj/item/projectile/bullet/magrifle
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "magjectile-large"
|
||||
damage = 30
|
||||
armour_penetration = 25
|
||||
light_range = 3
|
||||
light_color = LIGHT_COLOR_RED
|
||||
|
||||
/obj/item/projectile/bullet/nlmagrifle //non-lethal boolets
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "magjectile-large-nl"
|
||||
damage = 5
|
||||
knockdown = 30
|
||||
stamina = 75
|
||||
armour_penetration = 0
|
||||
light_range = 3
|
||||
light_color = LIGHT_COLOR_BLUE
|
||||
|
||||
///ammo casings///
|
||||
|
||||
/obj/item/ammo_casing/caseless/amagm
|
||||
desc = "A large ferromagnetic slug intended to be launched out of a compatible weapon."
|
||||
caliber = "magm"
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "mag-casing-live"
|
||||
projectile_type = /obj/item/projectile/bullet/magrifle
|
||||
|
||||
/obj/item/ammo_casing/caseless/anlmagm
|
||||
desc = "A large, specialized ferromagnetic slug designed with a less-than-lethal payload."
|
||||
caliber = "magm"
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "mag-casing-live"
|
||||
projectile_type = /obj/item/projectile/bullet/nlmagrifle
|
||||
|
||||
///magazines///
|
||||
|
||||
/obj/item/ammo_box/magazine/mmag/
|
||||
name = "magrifle magazine (non-lethal disabler)"
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "mediummagmag"
|
||||
origin_tech = "magnets=6"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/anlmagm
|
||||
caliber = "magm"
|
||||
max_ammo = 15
|
||||
multiple_sprites = 2
|
||||
|
||||
/obj/item/ammo_box/magazine/mmag/lethal
|
||||
name = "magrifle magazine (lethal)"
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "mediummagmag"
|
||||
origin_tech = "combat=6"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/amagm
|
||||
|
||||
///the gun itself///
|
||||
|
||||
/obj/item/gun/ballistic/automatic/magrifle
|
||||
name = "\improper Magnetic Rifle"
|
||||
desc = "A simple upscalling of the technologies used in the magpistol, the magrifle is capable of firing slightly larger slugs in bursts. Compatible with the magpistol's slugs."
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "magrifle"
|
||||
item_state = "arg"
|
||||
slot_flags = 0
|
||||
origin_tech = "combat=6;engineering=6;magnets=6"
|
||||
mag_type = /obj/item/ammo_box/magazine/mmag
|
||||
fire_sound = 'sound/weapons/magrifle.ogg'
|
||||
can_suppress = 0
|
||||
burst_size = 3
|
||||
fire_delay = 2
|
||||
spread = 15
|
||||
recoil = 1
|
||||
casing_ejector = 0
|
||||
|
||||
///research///
|
||||
|
||||
/obj/item/gun/ballistic/automatic/magrifle/nopin
|
||||
pin = null
|
||||
|
||||
/datum/design/magrifle
|
||||
name = "Magrifle"
|
||||
desc = "An upscaled Magpistol in rifle form."
|
||||
id = "magrifle"
|
||||
req_tech = list("combat" = 7, "magnets" = 7, "powerstorage" = 7)
|
||||
build_type = PROTOLATHE
|
||||
materials = list(MAT_METAL = 10000, MAT_GLASS = 2000, MAT_URANIUM = 2000, MAT_TITANIUM = 10000, MAT_SILVER = 4000, MAT_GOLD = 2000)
|
||||
build_path = /obj/item/gun/ballistic/automatic/magrifle/nopin
|
||||
category = list("Weapons")
|
||||
|
||||
/datum/design/mag_magrifle
|
||||
name = "Magrifle Magazine (Lethal)"
|
||||
desc = "A 15 round magazine for the Magrifle."
|
||||
id = "mag_magrifle"
|
||||
req_tech = list("combat" = 7, "magnets" = 7, "materials" = 5, "syndicate" = 4)
|
||||
build_type = PROTOLATHE
|
||||
materials = list(MAT_METAL = 8000, MAT_SILVER = 1000)
|
||||
build_path = /obj/item/ammo_box/magazine/mmag/lethal
|
||||
category = list("Ammo")
|
||||
|
||||
/datum/design/mag_magrifle/nl
|
||||
name = "Magrifle Magazine (Non-Lethal)"
|
||||
desc = "A 15 round non-lethal magazine for the Magrifle."
|
||||
id = "mag_magrifle_nl"
|
||||
req_tech = list("combat" = 7, "magnets" = 7, "materials" = 5)
|
||||
materials = list(MAT_METAL = 6000, MAT_SILVER = 500, MAT_TITANIUM = 500)
|
||||
build_path = /obj/item/ammo_box/magazine/mmag
|
||||
|
||||
//////Hyper-Burst Rifle//////
|
||||
|
||||
///projectiles///
|
||||
|
||||
/obj/item/projectile/bullet/mags/hyper
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "magjectile"
|
||||
damage = 10
|
||||
armour_penetration = 10
|
||||
stamina = 10
|
||||
forcedodge = TRUE
|
||||
range = 6
|
||||
light_range = 1
|
||||
light_color = LIGHT_COLOR_RED
|
||||
|
||||
/obj/item/projectile/bullet/mags/hyper/inferno
|
||||
icon_state = "magjectile-large"
|
||||
stamina = 0
|
||||
forcedodge = FALSE
|
||||
range = 25
|
||||
light_range = 4
|
||||
|
||||
/obj/item/projectile/bullet/mags/hyper/inferno/on_hit(atom/target, blocked = FALSE)
|
||||
..()
|
||||
explosion(target, -1, 1, 2, 4, 5)
|
||||
return 1
|
||||
|
||||
///ammo casings///
|
||||
|
||||
/obj/item/ammo_casing/caseless/ahyper
|
||||
desc = "A large block of speciallized ferromagnetic material designed to be fired out of the experimental Hyper-Burst Rifle."
|
||||
caliber = "hypermag"
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "hyper-casing-live"
|
||||
projectile_type = /obj/item/projectile/bullet/mags/hyper
|
||||
pellets = 12
|
||||
variance = 40
|
||||
|
||||
/obj/item/ammo_casing/caseless/ahyper/inferno
|
||||
projectile_type = /obj/item/projectile/bullet/mags/hyper/inferno
|
||||
pellets = 1
|
||||
variance = 0
|
||||
|
||||
///magazines///
|
||||
|
||||
/obj/item/ammo_box/magazine/mhyper
|
||||
name = "hyper-burst rifle magazine"
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "hypermag-4"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/ahyper
|
||||
caliber = "hypermag"
|
||||
desc = "A magazine for the Hyper-Burst Rifle. Loaded with a special slug that fragments into 12 smaller shards which can absolutely puncture anything, but has rather short effective range."
|
||||
max_ammo = 4
|
||||
|
||||
/obj/item/ammo_box/magazine/mhyper/update_icon()
|
||||
..()
|
||||
icon_state = "hypermag-[ammo_count() ? "4" : "0"]"
|
||||
|
||||
/obj/item/ammo_box/magazine/mhyper/inferno
|
||||
name = "hyper-burst rifle magazine (inferno)"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/ahyper/inferno
|
||||
desc = "A magazine for the Hyper-Burst Rifle. Loaded with a special slug that violently reacts with whatever surface it strikes, generating a massive amount of heat and light."
|
||||
|
||||
///gun itself///
|
||||
|
||||
/obj/item/gun/ballistic/automatic/hyperburst
|
||||
name = "\improper Hyper-Burst Rifle"
|
||||
desc = "An extremely beefed up version of a stolen Nanotrasen weapon prototype, this 'rifle' is more like a cannon, with an extremely large bore barrel capable of generating several smaller magnetic 'barrels' to simultaneously launch multiple projectiles at once."
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "hyperburst"
|
||||
item_state = "arg"
|
||||
slot_flags = 0
|
||||
origin_tech = "combat=6;engineering=6;magnets=6;syndicate=6"
|
||||
mag_type = /obj/item/ammo_box/magazine/mhyper
|
||||
fire_sound = 'sound/weapons/magburst.ogg'
|
||||
can_suppress = 0
|
||||
burst_size = 1
|
||||
fire_delay = 40
|
||||
recoil = 2
|
||||
casing_ejector = 0
|
||||
weapon_weight = WEAPON_HEAVY
|
||||
|
||||
/obj/item/gun/ballistic/automatic/hyperburst/update_icon()
|
||||
..()
|
||||
icon_state = "hyperburst[magazine ? "-[get_ammo()]" : ""][chambered ? "" : "-e"]"
|
||||
|
||||
/* made redundant by reskinnable stetchkins
|
||||
//////Stealth Pistol//////
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/stealth
|
||||
name = "stealth pistol"
|
||||
desc = "A unique bullpup pistol with a compact frame. Has an integrated surpressor."
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "stealthpistol"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
origin_tech = "combat=3;materials=3;syndicate=4"
|
||||
mag_type = /obj/item/ammo_box/magazine/m10mm
|
||||
can_suppress = 0
|
||||
fire_sound = 'sound/weapons/gunshot_silenced.ogg'
|
||||
suppressed = 1
|
||||
burst_size = 1
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/stealth/update_icon()
|
||||
..()
|
||||
if(magazine)
|
||||
cut_overlays()
|
||||
add_overlay("stealthpistol-magazine")
|
||||
else
|
||||
cut_overlays()
|
||||
icon_state = "[initial(icon_state)][chambered ? "" : "-e"]"
|
||||
|
||||
*/
|
||||
|
||||
//////10mm soporific bullets//////
|
||||
|
||||
obj/item/projectile/bullet/c10mm/soporific
|
||||
name ="10mm soporific bullet"
|
||||
armour_penetration = 0
|
||||
nodamage = TRUE
|
||||
dismemberment = 0
|
||||
knockdown = 0
|
||||
|
||||
/obj/item/projectile/bullet/c10mm/soporific/on_hit(atom/target, blocked = FALSE)
|
||||
if((blocked != 100) && isliving(target))
|
||||
var/mob/living/L = target
|
||||
L.blur_eyes(6)
|
||||
if(L.staminaloss >= 40)
|
||||
L.Sleeping(250)
|
||||
else
|
||||
L.adjustStaminaLoss(58)
|
||||
return 1
|
||||
|
||||
/obj/item/ammo_casing/c10mm/soporific
|
||||
name = ".10mm soporific bullet casing"
|
||||
desc = "A 10mm soporific bullet casing."
|
||||
projectile_type = /obj/item/projectile/bullet/c10mm/soporific
|
||||
|
||||
/obj/item/ammo_box/magazine/m10mm/soporific
|
||||
name = "pistol magazine (10mm soporific)"
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "9x19pS"
|
||||
desc = "A gun magazine. Loaded with rounds which inject the target with a variety of illegal substances to induce sleep in the target."
|
||||
ammo_type = /obj/item/ammo_casing/c10mm/soporific
|
||||
|
||||
/obj/item/ammo_box/c10mm/soporific
|
||||
name = "ammo box (10mm soporific)"
|
||||
ammo_type = /obj/item/ammo_casing/c10mm/soporific
|
||||
max_ammo = 24
|
||||
|
||||
//////Flechette Launcher//////
|
||||
|
||||
///projectiles///
|
||||
|
||||
/obj/item/projectile/bullet/cflechetteap //shreds armor
|
||||
name = "flechette (armor piercing)"
|
||||
damage = 8
|
||||
armour_penetration = 80
|
||||
|
||||
/obj/item/projectile/bullet/cflechettes //shreds flesh and forces bleeding
|
||||
name = "flechette (serrated)"
|
||||
damage = 8
|
||||
dismemberment = 10
|
||||
armour_penetration = -80
|
||||
|
||||
/obj/item/projectile/bullet/cflechettes/on_hit(atom/target, blocked = FALSE)
|
||||
if((blocked != 100) && iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
C.bleed(10)
|
||||
return ..()
|
||||
|
||||
///ammo casings (CASELESS AMMO CASINGS WOOOOOOOO)///
|
||||
|
||||
/obj/item/ammo_casing/caseless/flechetteap
|
||||
name = "flechette (armor piercing)"
|
||||
desc = "A flechette made with a tungsten alloy."
|
||||
projectile_type = /obj/item/projectile/bullet/cflechetteap
|
||||
caliber = "flechette"
|
||||
throwforce = 1
|
||||
throw_speed = 3
|
||||
|
||||
/obj/item/ammo_casing/caseless/flechettes
|
||||
name = "flechette (serrated)"
|
||||
desc = "A serrated flechette made of a special alloy intended to deform drastically upon penetration of human flesh."
|
||||
projectile_type = /obj/item/projectile/bullet/cflechettes
|
||||
caliber = "flechette"
|
||||
throwforce = 2
|
||||
throw_speed = 3
|
||||
embed_chance = 75
|
||||
|
||||
///magazine///
|
||||
|
||||
/obj/item/ammo_box/magazine/flechette
|
||||
name = "flechette magazine (armor piercing)"
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "flechettemag"
|
||||
origin_tech = "combat=5;syndicate=1"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/flechetteap
|
||||
caliber = "flechette"
|
||||
max_ammo = 40
|
||||
multiple_sprites = 2
|
||||
|
||||
/obj/item/ammo_box/magazine/flechette/s
|
||||
name = "flechette magazine (serrated)"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/flechettes
|
||||
|
||||
///the gun itself///
|
||||
|
||||
/obj/item/gun/ballistic/automatic/flechette
|
||||
name = "\improper CX Flechette Launcher"
|
||||
desc = "A flechette launching machine pistol with an unconventional bullpup frame."
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "flechettegun"
|
||||
item_state = "gun"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
slot_flags = 0
|
||||
/obj/item/device/firing_pin/implant/pindicate
|
||||
origin_tech = "combat=6;materials=2;syndicate=5"
|
||||
mag_type = /obj/item/ammo_box/magazine/flechette/
|
||||
fire_sound = 'sound/weapons/gunshot_smg.ogg'
|
||||
can_suppress = 0
|
||||
burst_size = 5
|
||||
fire_delay = 1
|
||||
casing_ejector = 0
|
||||
spread = 20
|
||||
|
||||
/obj/item/gun/ballistic/automatic/flechette/update_icon()
|
||||
..()
|
||||
if(magazine)
|
||||
cut_overlays()
|
||||
add_overlay("flechettegun-magazine")
|
||||
else
|
||||
cut_overlays()
|
||||
icon_state = "[initial(icon_state)][chambered ? "" : "-e"]"
|
||||
|
||||
///unique variant///
|
||||
|
||||
/obj/item/projectile/bullet/cflechetteshredder
|
||||
name = "flechette (shredder)"
|
||||
damage = 5
|
||||
dismemberment = 40
|
||||
|
||||
/obj/item/ammo_casing/caseless/flechetteshredder
|
||||
name = "flechette (shredder)"
|
||||
desc = "A serrated flechette made of a special alloy that forms a monofilament edge."
|
||||
projectile_type = /obj/item/projectile/bullet/cflechettes
|
||||
|
||||
/obj/item/ammo_box/magazine/flechette/shredder
|
||||
name = "flechette magazine (shredder)"
|
||||
icon_state = "shreddermag"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/flechetteshredder
|
||||
|
||||
/obj/item/gun/ballistic/automatic/flechette/shredder
|
||||
name = "\improper CX Shredder"
|
||||
desc = "A flechette launching machine pistol made of ultra-light CFRP optimized for firing serrated monofillament flechettes."
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
mag_type = /obj/item/ammo_box/magazine/flechette/shredder
|
||||
spread = 30
|
||||
|
||||
/obj/item/gun/ballistic/automatic/flechette/shredder/update_icon()
|
||||
..()
|
||||
if(magazine)
|
||||
cut_overlays()
|
||||
add_overlay("shreddergun-magazine")
|
||||
else
|
||||
cut_overlays()
|
||||
icon_state = "[initial(icon_state)][chambered ? "" : "-e"]"
|
||||
|
||||
//////modular pistol////// (reskinnable stetchkins)
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/modular
|
||||
name = "modular pistol"
|
||||
desc = "A small, easily concealable 10mm handgun. Has a threaded barrel for suppressors."
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "cde"
|
||||
can_unsuppress = TRUE
|
||||
unique_rename = TRUE
|
||||
unique_reskin = list("Default" = "cde",
|
||||
"NT-99" = "n99",
|
||||
"Stealth" = "stealthpistol",
|
||||
"HKVP-78" = "vp78",
|
||||
"Luger" = "p08b",
|
||||
"Mk.58" = "secguncomp",
|
||||
"PX4 Storm" = "px4"
|
||||
)
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/modular/update_icon()
|
||||
..()
|
||||
if(current_skin)
|
||||
icon_state = "[unique_reskin[current_skin]][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]"
|
||||
else
|
||||
icon_state = "[initial(icon_state)][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]"
|
||||
if(magazine && suppressed)
|
||||
cut_overlays()
|
||||
add_overlay("[unique_reskin[current_skin]]-magazine-sup") //Yes, this means the default iconstate can't have a magazine overlay
|
||||
else if (magazine)
|
||||
cut_overlays()
|
||||
add_overlay("[unique_reskin[current_skin]]-magazine")
|
||||
else
|
||||
cut_overlays()
|
||||
198
code/controllers/configuration/config_entry.dm
Normal file
198
code/controllers/configuration/config_entry.dm
Normal file
@@ -0,0 +1,198 @@
|
||||
#undef CURRENT_RESIDENT_FILE
|
||||
|
||||
#define LIST_MODE_NUM 0
|
||||
#define LIST_MODE_TEXT 1
|
||||
#define LIST_MODE_FLAG 2
|
||||
|
||||
/datum/config_entry
|
||||
var/name //read-only, this is determined by the last portion of the derived entry type
|
||||
var/value
|
||||
var/default //read-only, just set value directly
|
||||
|
||||
var/resident_file //the file which this belongs to, must be set
|
||||
var/modified = FALSE //set to TRUE if the default has been overridden by a config entry
|
||||
|
||||
var/protection = NONE
|
||||
var/abstract_type = /datum/config_entry //do not instantiate if type matches this
|
||||
|
||||
var/dupes_allowed = FALSE
|
||||
|
||||
/datum/config_entry/New()
|
||||
if(!resident_file)
|
||||
CRASH("Config entry [type] has no resident_file set")
|
||||
if(type == abstract_type)
|
||||
CRASH("Abstract config entry [type] instatiated!")
|
||||
name = lowertext(type2top(type))
|
||||
if(islist(value))
|
||||
var/list/L = value
|
||||
default = L.Copy()
|
||||
else
|
||||
default = value
|
||||
|
||||
/datum/config_entry/Destroy()
|
||||
config.RemoveEntry(src)
|
||||
return ..()
|
||||
|
||||
/datum/config_entry/can_vv_get(var_name)
|
||||
. = ..()
|
||||
if(var_name == "value" || var_name == "default")
|
||||
. &= !(protection & CONFIG_ENTRY_HIDDEN)
|
||||
|
||||
/datum/config_entry/vv_edit_var(var_name, var_value)
|
||||
var/static/list/banned_edits = list("name", "default", "resident_file", "protection", "abstract_type", "modified", "dupes_allowed")
|
||||
if(var_name == "value")
|
||||
if(protection & CONFIG_ENTRY_LOCKED)
|
||||
return FALSE
|
||||
. = ValidateAndSet("[var_value]")
|
||||
if(.)
|
||||
var_edited = TRUE
|
||||
return
|
||||
if(var_name in banned_edits)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/config_entry/proc/VASProcCallGuard(str_val)
|
||||
. = !(IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "ValidateAndSet" && GLOB.LastAdminCalledTargetRef == "\ref[src]")
|
||||
if(!.)
|
||||
log_admin_private("Config set of [type] to [str_val] attempted by [key_name(usr)]")
|
||||
|
||||
/datum/config_entry/proc/ValidateAndSet(str_val)
|
||||
VASProcCallGuard(str_val)
|
||||
CRASH("Invalid config entry type!")
|
||||
|
||||
/datum/config_entry/proc/ValidateKeyedList(str_val, list_mode, splitter)
|
||||
str_val = trim(str_val)
|
||||
var/key_pos = findtext(str_val, splitter)
|
||||
var/key_name = null
|
||||
var/key_value = null
|
||||
|
||||
if(key_pos || list_mode == LIST_MODE_FLAG)
|
||||
key_name = lowertext(copytext(str_val, 1, key_pos))
|
||||
key_value = copytext(str_val, key_pos + 1)
|
||||
var/temp
|
||||
var/continue_check
|
||||
switch(list_mode)
|
||||
if(LIST_MODE_FLAG)
|
||||
temp = TRUE
|
||||
continue_check = TRUE
|
||||
if(LIST_MODE_NUM)
|
||||
temp = text2num(key_value)
|
||||
continue_check = !isnull(temp)
|
||||
if(LIST_MODE_TEXT)
|
||||
temp = key_value
|
||||
continue_check = temp
|
||||
if(continue_check && ValidateKeyName(key_name))
|
||||
value[key_name] = temp
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/config_entry/proc/ValidateKeyName(key_name)
|
||||
return TRUE
|
||||
|
||||
/datum/config_entry/string
|
||||
value = ""
|
||||
abstract_type = /datum/config_entry/string
|
||||
var/auto_trim = TRUE
|
||||
|
||||
/datum/config_entry/string/vv_edit_var(var_name, var_value)
|
||||
return var_name != "auto_trim" && ..()
|
||||
|
||||
/datum/config_entry/string/ValidateAndSet(str_val)
|
||||
if(!VASProcCallGuard(str_val))
|
||||
return FALSE
|
||||
value = auto_trim ? trim(str_val) : str_val
|
||||
return TRUE
|
||||
|
||||
/datum/config_entry/number
|
||||
value = 0
|
||||
abstract_type = /datum/config_entry/number
|
||||
var/integer = TRUE
|
||||
var/max_val = INFINITY
|
||||
var/min_val = -INFINITY
|
||||
|
||||
/datum/config_entry/number/ValidateAndSet(str_val)
|
||||
if(!VASProcCallGuard(str_val))
|
||||
return FALSE
|
||||
var/temp = text2num(trim(str_val))
|
||||
if(!isnull(temp))
|
||||
value = Clamp(integer ? round(temp) : temp, min_val, max_val)
|
||||
if(value != temp && !var_edited)
|
||||
log_config("Changing [name] from [temp] to [value]!")
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/config_entry/number/vv_edit_var(var_name, var_value)
|
||||
var/static/list/banned_edits = list("max_val", "min_val", "integer")
|
||||
return !(var_name in banned_edits) && ..()
|
||||
|
||||
/datum/config_entry/flag
|
||||
value = FALSE
|
||||
abstract_type = /datum/config_entry/flag
|
||||
|
||||
/datum/config_entry/flag/ValidateAndSet(str_val)
|
||||
if(!VASProcCallGuard(str_val))
|
||||
return FALSE
|
||||
value = text2num(trim(str_val)) != 0
|
||||
return TRUE
|
||||
|
||||
/datum/config_entry/number_list
|
||||
abstract_type = /datum/config_entry/number_list
|
||||
value = list()
|
||||
|
||||
/datum/config_entry/number_list/ValidateAndSet(str_val)
|
||||
if(!VASProcCallGuard(str_val))
|
||||
return FALSE
|
||||
str_val = trim(str_val)
|
||||
var/list/new_list = list()
|
||||
var/list/values = splittext(str_val," ")
|
||||
for(var/I in values)
|
||||
var/temp = text2num(I)
|
||||
if(isnull(temp))
|
||||
return FALSE
|
||||
new_list += temp
|
||||
if(!new_list.len)
|
||||
return FALSE
|
||||
value = new_list
|
||||
return TRUE
|
||||
|
||||
/datum/config_entry/keyed_flag_list
|
||||
abstract_type = /datum/config_entry/keyed_flag_list
|
||||
value = list()
|
||||
dupes_allowed = TRUE
|
||||
|
||||
/datum/config_entry/keyed_flag_list/ValidateAndSet(str_val)
|
||||
if(!VASProcCallGuard(str_val))
|
||||
return FALSE
|
||||
return ValidateKeyedList(str_val, LIST_MODE_FLAG, " ")
|
||||
|
||||
/datum/config_entry/keyed_number_list
|
||||
abstract_type = /datum/config_entry/keyed_number_list
|
||||
value = list()
|
||||
dupes_allowed = TRUE
|
||||
var/splitter = " "
|
||||
|
||||
/datum/config_entry/keyed_number_list/vv_edit_var(var_name, var_value)
|
||||
return var_name != "splitter" && ..()
|
||||
|
||||
/datum/config_entry/keyed_number_list/ValidateAndSet(str_val)
|
||||
if(!VASProcCallGuard(str_val))
|
||||
return FALSE
|
||||
return ValidateKeyedList(str_val, LIST_MODE_NUM, splitter)
|
||||
|
||||
/datum/config_entry/keyed_string_list
|
||||
abstract_type = /datum/config_entry/keyed_string_list
|
||||
value = list()
|
||||
dupes_allowed = TRUE
|
||||
var/splitter = " "
|
||||
|
||||
/datum/config_entry/keyed_string_list/vv_edit_var(var_name, var_value)
|
||||
return var_name != "splitter" && ..()
|
||||
|
||||
/datum/config_entry/keyed_string_list/ValidateAndSet(str_val)
|
||||
if(!VASProcCallGuard(str_val))
|
||||
return FALSE
|
||||
return ValidateKeyedList(str_val, LIST_MODE_TEXT, splitter)
|
||||
|
||||
#undef LIST_MODE_NUM
|
||||
#undef LIST_MODE_TEXT
|
||||
#undef LIST_MODE_FLAG
|
||||
287
code/controllers/configuration/configuration.dm
Normal file
287
code/controllers/configuration/configuration.dm
Normal file
@@ -0,0 +1,287 @@
|
||||
GLOBAL_VAR_INIT(config_dir, "config/")
|
||||
GLOBAL_PROTECT(config_dir)
|
||||
|
||||
/datum/controller/configuration
|
||||
name = "Configuration"
|
||||
|
||||
var/hiding_entries_by_type = TRUE //Set for readability, admins can set this to FALSE if they want to debug it
|
||||
var/list/entries
|
||||
var/list/entries_by_type
|
||||
|
||||
var/list/maplist
|
||||
var/datum/map_config/defaultmap
|
||||
|
||||
var/list/modes // allowed modes
|
||||
var/list/gamemode_cache
|
||||
var/list/votable_modes // votable modes
|
||||
var/list/mode_names
|
||||
var/list/mode_reports
|
||||
var/list/mode_false_report_weight
|
||||
|
||||
/datum/controller/configuration/New()
|
||||
config = src
|
||||
var/list/config_files = InitEntries()
|
||||
LoadModes()
|
||||
for(var/I in config_files)
|
||||
LoadEntries(I)
|
||||
if(Get(/datum/config_entry/flag/maprotation))
|
||||
loadmaplist(CONFIG_MAPS_FILE)
|
||||
|
||||
/datum/controller/configuration/Destroy()
|
||||
entries_by_type.Cut()
|
||||
QDEL_LIST_ASSOC_VAL(entries)
|
||||
QDEL_LIST_ASSOC_VAL(maplist)
|
||||
QDEL_NULL(defaultmap)
|
||||
|
||||
config = null
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/controller/configuration/proc/InitEntries()
|
||||
var/list/_entries = list()
|
||||
entries = _entries
|
||||
var/list/_entries_by_type = list()
|
||||
entries_by_type = _entries_by_type
|
||||
|
||||
. = list()
|
||||
|
||||
for(var/I in typesof(/datum/config_entry)) //typesof is faster in this case
|
||||
var/datum/config_entry/E = I
|
||||
if(initial(E.abstract_type) == I)
|
||||
continue
|
||||
E = new I
|
||||
_entries_by_type[I] = E
|
||||
var/esname = E.name
|
||||
var/datum/config_entry/test = _entries[esname]
|
||||
if(test)
|
||||
log_config("Error: [test.type] has the same name as [E.type]: [esname]! Not initializing [E.type]!")
|
||||
qdel(E)
|
||||
continue
|
||||
_entries[esname] = E
|
||||
.[E.resident_file] = TRUE
|
||||
|
||||
/datum/controller/configuration/proc/RemoveEntry(datum/config_entry/CE)
|
||||
entries -= CE.name
|
||||
entries_by_type -= CE.type
|
||||
|
||||
/datum/controller/configuration/proc/LoadEntries(filename)
|
||||
log_config("Loading config file [filename]...")
|
||||
var/list/lines = world.file2list("[GLOB.config_dir][filename]")
|
||||
var/list/_entries = entries
|
||||
for(var/L in lines)
|
||||
if(!L)
|
||||
continue
|
||||
|
||||
if(copytext(L, 1, 2) == "#")
|
||||
continue
|
||||
|
||||
var/pos = findtext(L, " ")
|
||||
var/entry = null
|
||||
var/value = null
|
||||
|
||||
if(pos)
|
||||
entry = lowertext(copytext(L, 1, pos))
|
||||
value = copytext(L, pos + 1)
|
||||
else
|
||||
entry = lowertext(L)
|
||||
|
||||
if(!entry)
|
||||
continue
|
||||
|
||||
var/datum/config_entry/E = _entries[entry]
|
||||
if(!E)
|
||||
log_config("Unknown setting in configuration: '[entry]'")
|
||||
continue
|
||||
|
||||
if(filename != E.resident_file)
|
||||
log_config("Found [entry] in [filename] when it should have been in [E.resident_file]! Ignoring.")
|
||||
continue
|
||||
|
||||
var/validated = E.ValidateAndSet(value)
|
||||
if(!validated)
|
||||
log_config("Failed to validate setting \"[value]\" for [entry]")
|
||||
else if(E.modified && !E.dupes_allowed)
|
||||
log_config("Duplicate setting for [entry] ([value]) detected! Using latest.")
|
||||
|
||||
if(validated)
|
||||
E.modified = TRUE
|
||||
|
||||
/datum/controller/configuration/can_vv_get(var_name)
|
||||
return (var_name != "entries_by_type" || !hiding_entries_by_type) && ..()
|
||||
|
||||
/datum/controller/configuration/vv_edit_var(var_name, var_value)
|
||||
return !(var_name in list("entries_by_type", "entries")) && ..()
|
||||
|
||||
/datum/controller/configuration/stat_entry()
|
||||
if(!statclick)
|
||||
statclick = new/obj/effect/statclick/debug(null, "Edit", src)
|
||||
stat("[name]:", statclick)
|
||||
|
||||
/datum/controller/configuration/proc/Get(entry_type)
|
||||
if(IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Get" && GLOB.LastAdminCalledTargetRef == "\ref[src]")
|
||||
log_admin_private("Config access of [entry_type] attempted by [key_name(usr)]")
|
||||
return
|
||||
var/datum/config_entry/E = entry_type
|
||||
var/entry_is_abstract = initial(E.abstract_type) == entry_type
|
||||
if(entry_is_abstract)
|
||||
CRASH("Tried to retrieve an abstract config_entry: [entry_type]")
|
||||
E = entries_by_type[entry_type]
|
||||
if(!E)
|
||||
CRASH("Missing config entry for [entry_type]!")
|
||||
return E.value
|
||||
|
||||
/datum/controller/configuration/proc/Set(entry_type, new_val)
|
||||
if(IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Set" && GLOB.LastAdminCalledTargetRef == "\ref[src]")
|
||||
log_admin_private("Config rewrite of [entry_type] to [new_val] attempted by [key_name(usr)]")
|
||||
return
|
||||
var/datum/config_entry/E = entry_type
|
||||
var/entry_is_abstract = initial(E.abstract_type) == entry_type
|
||||
if(entry_is_abstract)
|
||||
CRASH("Tried to retrieve an abstract config_entry: [entry_type]")
|
||||
E = entries_by_type[entry_type]
|
||||
if(!E)
|
||||
CRASH("Missing config entry for [entry_type]!")
|
||||
return E.ValidateAndSet(new_val)
|
||||
|
||||
/datum/controller/configuration/proc/LoadModes()
|
||||
gamemode_cache = typecacheof(/datum/game_mode, TRUE)
|
||||
modes = list()
|
||||
mode_names = list()
|
||||
mode_reports = list()
|
||||
mode_false_report_weight = list()
|
||||
votable_modes = list()
|
||||
var/list/probabilities = Get(/datum/config_entry/keyed_number_list/probability)
|
||||
for(var/T in gamemode_cache)
|
||||
// I wish I didn't have to instance the game modes in order to look up
|
||||
// their information, but it is the only way (at least that I know of).
|
||||
var/datum/game_mode/M = new T()
|
||||
|
||||
if(M.config_tag)
|
||||
if(!(M.config_tag in modes)) // ensure each mode is added only once
|
||||
modes += M.config_tag
|
||||
mode_names[M.config_tag] = M.name
|
||||
probabilities[M.config_tag] = M.probability
|
||||
mode_reports[M.config_tag] = M.generate_report()
|
||||
mode_false_report_weight[M.config_tag] = M.false_report_weight
|
||||
if(M.votable)
|
||||
votable_modes += M.config_tag
|
||||
qdel(M)
|
||||
votable_modes += "secret"
|
||||
|
||||
/datum/controller/configuration/proc/loadmaplist(filename)
|
||||
filename = "[GLOB.config_dir][filename]"
|
||||
var/list/Lines = world.file2list(filename)
|
||||
|
||||
var/datum/map_config/currentmap = null
|
||||
for(var/t in Lines)
|
||||
if(!t)
|
||||
continue
|
||||
|
||||
t = trim(t)
|
||||
if(length(t) == 0)
|
||||
continue
|
||||
else if(copytext(t, 1, 2) == "#")
|
||||
continue
|
||||
|
||||
var/pos = findtext(t, " ")
|
||||
var/command = null
|
||||
var/data = null
|
||||
|
||||
if(pos)
|
||||
command = lowertext(copytext(t, 1, pos))
|
||||
data = copytext(t, pos + 1)
|
||||
else
|
||||
command = lowertext(t)
|
||||
|
||||
if(!command)
|
||||
continue
|
||||
|
||||
if (!currentmap && command != "map")
|
||||
continue
|
||||
|
||||
switch (command)
|
||||
if ("map")
|
||||
currentmap = new ("_maps/[data].json")
|
||||
if(currentmap.defaulted)
|
||||
log_config("Failed to load map config for [data]!")
|
||||
if ("minplayers","minplayer")
|
||||
currentmap.config_min_users = text2num(data)
|
||||
if ("maxplayers","maxplayer")
|
||||
currentmap.config_max_users = text2num(data)
|
||||
if ("weight","voteweight")
|
||||
currentmap.voteweight = text2num(data)
|
||||
if ("default","defaultmap")
|
||||
defaultmap = currentmap
|
||||
if ("endmap")
|
||||
LAZYINITLIST(maplist)
|
||||
maplist[currentmap.map_name] = currentmap
|
||||
currentmap = null
|
||||
if ("disabled")
|
||||
currentmap = null
|
||||
else
|
||||
WRITE_FILE(GLOB.config_error_log, "Unknown command in map vote config: '[command]'")
|
||||
|
||||
|
||||
/datum/controller/configuration/proc/pick_mode(mode_name)
|
||||
// I wish I didn't have to instance the game modes in order to look up
|
||||
// their information, but it is the only way (at least that I know of).
|
||||
// ^ This guy didn't try hard enough
|
||||
for(var/T in gamemode_cache)
|
||||
var/datum/game_mode/M = T
|
||||
var/ct = initial(M.config_tag)
|
||||
if(ct && ct == mode_name)
|
||||
return new T
|
||||
return new /datum/game_mode/extended()
|
||||
|
||||
/datum/controller/configuration/proc/get_runnable_modes()
|
||||
var/list/datum/game_mode/runnable_modes = new
|
||||
var/list/probabilities = Get(/datum/config_entry/keyed_number_list/probability)
|
||||
var/list/min_pop = Get(/datum/config_entry/keyed_number_list/min_pop)
|
||||
var/list/max_pop = Get(/datum/config_entry/keyed_number_list/max_pop)
|
||||
var/list/repeated_mode_adjust = Get(/datum/config_entry/number_list/repeated_mode_adjust)
|
||||
for(var/T in gamemode_cache)
|
||||
var/datum/game_mode/M = new T()
|
||||
if(!(M.config_tag in modes))
|
||||
qdel(M)
|
||||
continue
|
||||
if(probabilities[M.config_tag]<=0)
|
||||
qdel(M)
|
||||
continue
|
||||
if(min_pop[M.config_tag])
|
||||
M.required_players = min_pop[M.config_tag]
|
||||
if(max_pop[M.config_tag])
|
||||
M.maximum_players = max_pop[M.config_tag]
|
||||
if(M.can_start())
|
||||
var/final_weight = probabilities[M.config_tag]
|
||||
if(SSpersistence.saved_modes.len == 3 && repeated_mode_adjust.len == 3)
|
||||
var/recent_round = min(SSpersistence.saved_modes.Find(M.config_tag),3)
|
||||
var/adjustment = 0
|
||||
while(recent_round)
|
||||
adjustment += repeated_mode_adjust[recent_round]
|
||||
recent_round = SSpersistence.saved_modes.Find(M.config_tag,recent_round+1,0)
|
||||
final_weight *= ((100-adjustment)/100)
|
||||
runnable_modes[M] = final_weight
|
||||
return runnable_modes
|
||||
|
||||
/datum/controller/configuration/proc/get_runnable_midround_modes(crew)
|
||||
var/list/datum/game_mode/runnable_modes = new
|
||||
var/list/probabilities = Get(/datum/config_entry/keyed_number_list/probability)
|
||||
var/list/min_pop = Get(/datum/config_entry/keyed_number_list/min_pop)
|
||||
var/list/max_pop = Get(/datum/config_entry/keyed_number_list/max_pop)
|
||||
for(var/T in (gamemode_cache - SSticker.mode.type))
|
||||
var/datum/game_mode/M = new T()
|
||||
if(!(M.config_tag in modes))
|
||||
qdel(M)
|
||||
continue
|
||||
if(probabilities[M.config_tag]<=0)
|
||||
qdel(M)
|
||||
continue
|
||||
if(min_pop[M.config_tag])
|
||||
M.required_players = min_pop[M.config_tag]
|
||||
if(max_pop[M.config_tag])
|
||||
M.maximum_players = max_pop[M.config_tag]
|
||||
if(M.required_players <= crew)
|
||||
if(M.maximum_players >= 0 && M.maximum_players < crew)
|
||||
continue
|
||||
runnable_modes[M] = probabilities[M.config_tag]
|
||||
return runnable_modes
|
||||
@@ -69,7 +69,7 @@
|
||||
can_fire = 0
|
||||
flags |= SS_NO_FIRE
|
||||
Master.subsystems -= src
|
||||
|
||||
return ..()
|
||||
|
||||
//Queue it to run.
|
||||
// (we loop thru a linked list until we get to the end or find the right point)
|
||||
|
||||
@@ -322,7 +322,7 @@ SUBSYSTEM_DEF(air)
|
||||
EG.dismantle()
|
||||
CHECK_TICK
|
||||
|
||||
var/msg = "HEY! LISTEN! [(world.timeofday - timer)/10] Seconds were wasted processing [starting_ats] turf(s) (connected to [ending_ats] other turfs) with atmos differences at round start."
|
||||
var/msg = "HEY! LISTEN! [DisplayTimeText(world.timeofday - timer)] were wasted processing [starting_ats] turf(s) (connected to [ending_ats] other turfs) with atmos differences at round start."
|
||||
to_chat(world, "<span class='boldannounce'>[msg]</span>")
|
||||
warning(msg)
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ SUBSYSTEM_DEF(mapping)
|
||||
var/space_zlevels = list()
|
||||
for(var/i in ZLEVEL_SPACEMIN to ZLEVEL_SPACEMAX)
|
||||
switch(i)
|
||||
if(ZLEVEL_MINING, ZLEVEL_LAVALAND, ZLEVEL_EMPTY_SPACE, ZLEVEL_TRANSIT)
|
||||
if(ZLEVEL_MINING, ZLEVEL_LAVALAND, ZLEVEL_EMPTY_SPACE, ZLEVEL_TRANSIT, ZLEVEL_CITYOFCOGS)
|
||||
continue
|
||||
else
|
||||
space_zlevels += i
|
||||
|
||||
@@ -29,7 +29,7 @@ SUBSYSTEM_DEF(server_maint)
|
||||
var/cmob = C.mob
|
||||
if(!(isobserver(cmob) || (isdead(cmob) && C.holder)))
|
||||
log_access("AFK: [key_name(C)]")
|
||||
to_chat(C, "<span class='danger'>You have been inactive for more than [config.afk_period / 600] minutes and have been disconnected.</span>")
|
||||
to_chat(C, "<span class='danger'>You have been inactive for more than [DisplayTimeText(config.afk_period)] and have been disconnected.</span>")
|
||||
qdel(C)
|
||||
|
||||
if (!(!C || world.time - C.connection_time < PING_BUFFER_TIME || C.inactivity >= (wait-1)))
|
||||
|
||||
@@ -178,7 +178,7 @@ SUBSYSTEM_DEF(shuttle)
|
||||
emergency = backup_shuttle
|
||||
|
||||
if(world.time - SSticker.round_start_time < config.shuttle_refuel_delay)
|
||||
to_chat(user, "The emergency shuttle is refueling. Please wait another [abs(round(((world.time - SSticker.round_start_time) - config.shuttle_refuel_delay)/600))] minutes before trying again.")
|
||||
to_chat(user, "The emergency shuttle is refueling. Please wait [DisplayTimeText((world.time - SSticker.round_start_time) - config.shuttle_refuel_delay)] before trying again.")
|
||||
return
|
||||
|
||||
switch(emergency.mode)
|
||||
|
||||
@@ -11,6 +11,7 @@ SUBSYSTEM_DEF(squeak)
|
||||
|
||||
/datum/controller/subsystem/squeak/Initialize(timeofday)
|
||||
trigger_migration(config.mice_roundstart)
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/squeak/proc/trigger_migration(num_mice=10)
|
||||
if(!num_mice)
|
||||
|
||||
@@ -57,6 +57,9 @@ SUBSYSTEM_DEF(throwing)
|
||||
var/pure_diagonal
|
||||
var/diagonal_error
|
||||
var/datum/callback/callback
|
||||
var/paused = FALSE
|
||||
var/delayed_time = 0
|
||||
var/last_move = 0
|
||||
|
||||
/datum/thrownthing/proc/tick()
|
||||
var/atom/movable/AM = thrownthing
|
||||
@@ -64,14 +67,20 @@ SUBSYSTEM_DEF(throwing)
|
||||
finalize()
|
||||
return
|
||||
|
||||
if(paused)
|
||||
delayed_time += world.time - last_move
|
||||
return
|
||||
|
||||
if (dist_travelled && hitcheck()) //to catch sneaky things moving on our tile while we slept
|
||||
finalize()
|
||||
return
|
||||
|
||||
var/atom/step
|
||||
|
||||
last_move = world.time
|
||||
|
||||
//calculate how many tiles to move, making up for any missed ticks.
|
||||
var/tilestomove = Ceiling(min(((((world.time+world.tick_lag) - start_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed*MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait))
|
||||
var/tilestomove = Ceiling(min(((((world.time+world.tick_lag) - start_time + delayed_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed*MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait))
|
||||
while (tilestomove-- > 0)
|
||||
if ((dist_travelled >= maxrange || AM.loc == target_turf) && AM.has_gravity(AM.loc))
|
||||
finalize()
|
||||
|
||||
@@ -51,14 +51,14 @@ SUBSYSTEM_DEF(ticker)
|
||||
var/queue_delay = 0
|
||||
var/list/queued_players = list() //used for join queues when the server exceeds the hard population cap
|
||||
|
||||
var/obj/screen/cinematic = null //used for station explosion cinematic
|
||||
|
||||
var/maprotatechecked = 0
|
||||
|
||||
var/news_report
|
||||
|
||||
var/late_join_disabled
|
||||
|
||||
var/roundend_check_paused = FALSE
|
||||
|
||||
var/round_start_time = 0
|
||||
var/list/round_start_events
|
||||
var/mode_result = "undefined"
|
||||
@@ -137,7 +137,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
scripture_states = scripture_unlock_alert(scripture_states)
|
||||
SSshuttle.autoEnd()
|
||||
|
||||
if(!mode.explosion_in_progress && mode.check_finished(force_ending) || force_ending)
|
||||
if(!roundend_check_paused && mode.check_finished(force_ending) || force_ending)
|
||||
current_state = GAME_STATE_FINISHED
|
||||
toggle_ooc(TRUE) // Turn it on
|
||||
toggle_dooc(TRUE)
|
||||
@@ -273,144 +273,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
qdel(bomb)
|
||||
if(epi)
|
||||
explosion(epi, 0, 256, 512, 0, TRUE, TRUE, 0, TRUE)
|
||||
|
||||
//Plus it provides an easy way to make cinematics for other events. Just use this as a template
|
||||
/datum/controller/subsystem/ticker/proc/station_explosion_cinematic(station_missed=0, override = null, atom/bomb = null)
|
||||
if( cinematic )
|
||||
return //already a cinematic in progress!
|
||||
|
||||
for (var/datum/html_interface/hi in GLOB.html_interfaces)
|
||||
hi.closeAll()
|
||||
SStgui.close_all_uis()
|
||||
|
||||
//Turn off the shuttles, there's no escape now
|
||||
if(!station_missed && bomb)
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
SSshuttle.lockdown = TRUE
|
||||
|
||||
//initialise our cinematic screen object
|
||||
cinematic = new /obj/screen{icon='icons/effects/station_explosion.dmi';icon_state="station_intact";layer=21;mouse_opacity = MOUSE_OPACITY_TRANSPARENT;screen_loc="1,0";}(src)
|
||||
|
||||
for(var/mob/M in GLOB.mob_list)
|
||||
M.notransform = TRUE //stop everything moving
|
||||
if(M.client)
|
||||
M.client.screen += cinematic //show every client the cinematic
|
||||
|
||||
var/actually_blew_up = TRUE
|
||||
//Now animate the cinematic
|
||||
switch(station_missed)
|
||||
if(NUKE_NEAR_MISS) //nuke was nearby but (mostly) missed
|
||||
if(mode && !override )
|
||||
override = mode.name
|
||||
switch( override )
|
||||
if("nuclear emergency") //Nuke wasn't on station when it blew up
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
|
||||
station_explosion_detonation(bomb)
|
||||
flick("station_intact_fade_red",cinematic)
|
||||
cinematic.icon_state = "summary_nukefail"
|
||||
if("cult")
|
||||
cinematic.icon_state = null
|
||||
flick("intro_cult",cinematic)
|
||||
sleep(25)
|
||||
SEND_SOUND(world, sound('sound/magic/enter_blood.ogg'))
|
||||
sleep(28)
|
||||
SEND_SOUND(world, sound('sound/machines/terminal_off.ogg'))
|
||||
sleep(20)
|
||||
flick("station_corrupted",cinematic)
|
||||
SEND_SOUND(world, sound('sound/effects/ghost.ogg'))
|
||||
actually_blew_up = FALSE
|
||||
if("fake") //The round isn't over, we're just freaking people out for fun
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
SEND_SOUND(world, sound('sound/items/bikehorn.ogg'))
|
||||
flick("summary_selfdes",cinematic)
|
||||
actually_blew_up = FALSE
|
||||
else
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
|
||||
station_explosion_detonation(bomb)
|
||||
|
||||
|
||||
if(NUKE_MISS_STATION || NUKE_SYNDICATE_BASE) //nuke was nowhere nearby //TODO: a really distant explosion animation
|
||||
sleep(50)
|
||||
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
|
||||
station_explosion_detonation(bomb)
|
||||
actually_blew_up = station_missed == NUKE_SYNDICATE_BASE //don't kill everyone on station if it detonated off station
|
||||
else //station was destroyed
|
||||
if( mode && !override )
|
||||
override = mode.name
|
||||
switch( override )
|
||||
if("nuclear emergency") //Nuke Ops successfully bombed the station
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
flick("station_explode_fade_red",cinematic)
|
||||
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
|
||||
station_explosion_detonation(bomb)
|
||||
cinematic.icon_state = "summary_nukewin"
|
||||
if("AI malfunction") //Malf (screen,explosion,summary)
|
||||
flick("intro_malf",cinematic)
|
||||
sleep(76)
|
||||
flick("station_explode_fade_red",cinematic)
|
||||
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
|
||||
station_explosion_detonation(bomb) //TODO: If we ever decide to actually detonate the vault bomb
|
||||
cinematic.icon_state = "summary_malf"
|
||||
if("blob") //Station nuked (nuke,explosion,summary)
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
flick("station_explode_fade_red",cinematic)
|
||||
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
|
||||
station_explosion_detonation(bomb) //TODO: no idea what this case could be
|
||||
cinematic.icon_state = "summary_selfdes"
|
||||
if("cult") //Station nuked (nuke,explosion,summary)
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
flick("station_explode_fade_red",cinematic)
|
||||
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
|
||||
station_explosion_detonation(bomb) //TODO: no idea what this case could be
|
||||
cinematic.icon_state = "summary_cult"
|
||||
if("no_core") //Nuke failed to detonate as it had no core
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
flick("station_intact",cinematic)
|
||||
SEND_SOUND(world, sound('sound/ambience/signal.ogg'))
|
||||
addtimer(CALLBACK(src, .proc/finish_cinematic, null, FALSE), 100)
|
||||
return //Faster exit, since nothing happened
|
||||
else //Station nuked (nuke,explosion,summary)
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
flick("station_explode_fade_red", cinematic)
|
||||
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
|
||||
station_explosion_detonation(bomb)
|
||||
cinematic.icon_state = "summary_selfdes"
|
||||
//If its actually the end of the round, wait for it to end.
|
||||
//Otherwise if its a verb it will continue on afterwards.
|
||||
|
||||
var/bombloc = null
|
||||
if(actually_blew_up)
|
||||
if(bomb && bomb.loc)
|
||||
bombloc = bomb.z
|
||||
else if(!station_missed)
|
||||
bombloc = ZLEVEL_STATION_PRIMARY
|
||||
|
||||
if(mode)
|
||||
mode.explosion_in_progress = 0
|
||||
to_chat(world, "<B>The station was destoyed by the nuclear blast!</B>")
|
||||
mode.station_was_nuked = (station_missed<2) //station_missed==1 is a draw. the station becomes irradiated and needs to be evacuated.
|
||||
|
||||
addtimer(CALLBACK(src, .proc/finish_cinematic, bombloc, actually_blew_up), 300)
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/finish_cinematic(killz, actually_blew_up)
|
||||
if(cinematic)
|
||||
qdel(cinematic) //end the cinematic
|
||||
cinematic = null
|
||||
for(var/mob/M in GLOB.mob_list)
|
||||
M.notransform = FALSE
|
||||
if(actually_blew_up && !isnull(killz) && M.stat != DEAD && M.z == killz)
|
||||
M.gib()
|
||||
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/create_characters()
|
||||
for(var/mob/dead/new_player/player in GLOB.player_list)
|
||||
if(player.ready == PLAYER_READY_TO_PLAY && player.mind)
|
||||
@@ -505,7 +368,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
end_state.count()
|
||||
var/station_integrity = min(PERCENT(GLOB.start_state.score(end_state)), 100)
|
||||
|
||||
to_chat(world, "<BR>[GLOB.TAB]Shift Duration: <B>[round(world.time / 36000)]:[add_zero("[world.time / 600 % 60]", 2)]:[world.time / 100 % 6][world.time / 100 % 10]</B>")
|
||||
to_chat(world, "<BR>[GLOB.TAB]Shift Duration: <B>[DisplayTimeText(world.time - SSticker.round_start_time)]</B>")
|
||||
to_chat(world, "<BR>[GLOB.TAB]Station Integrity: <B>[mode.station_was_nuked ? "<font color='red'>Destroyed</font>" : "[station_integrity]%"]</B>")
|
||||
if(mode.station_was_nuked)
|
||||
SSticker.news_report = STATION_DESTROYED_NUKE
|
||||
@@ -711,13 +574,11 @@ SUBSYSTEM_DEF(ticker)
|
||||
|
||||
queue_delay = SSticker.queue_delay
|
||||
queued_players = SSticker.queued_players
|
||||
cinematic = SSticker.cinematic
|
||||
maprotatechecked = SSticker.maprotatechecked
|
||||
round_start_time = SSticker.round_start_time
|
||||
|
||||
queue_delay = SSticker.queue_delay
|
||||
queued_players = SSticker.queued_players
|
||||
cinematic = SSticker.cinematic
|
||||
maprotatechecked = SSticker.maprotatechecked
|
||||
|
||||
modevoted = SSticker.modevoted
|
||||
|
||||
@@ -169,7 +169,7 @@ SUBSYSTEM_DEF(vote)
|
||||
admin = TRUE
|
||||
|
||||
if(next_allowed_time > world.time && !admin)
|
||||
to_chat(usr, "<span class='warning'>A vote was initiated recently, you must wait roughly [(next_allowed_time-world.time)/10] seconds before a new vote can be started!</span>")
|
||||
to_chat(usr, "<span class='warning'>A vote was initiated recently, you must wait [DisplayTimeText(next_allowed_time-world.time)] before a new vote can be started!</span>")
|
||||
return 0
|
||||
|
||||
reset()
|
||||
@@ -198,7 +198,7 @@ SUBSYSTEM_DEF(vote)
|
||||
if(mode == "custom")
|
||||
text += "\n[question]"
|
||||
log_vote(text)
|
||||
to_chat(world, "\n<font color='purple'><b>[text]</b>\nType <b>vote</b> or click <a href='?src=\ref[src]'>here</a> to place your votes.\nYou have [config.vote_period/10] seconds to vote.</font>")
|
||||
to_chat(world, "\n<font color='purple'><b>[text]</b>\nType <b>vote</b> or click <a href='?src=\ref[src]'>here</a> to place your votes.\nYou have [DisplayTimeText(config.vote_period)] to vote.</font>")
|
||||
time_remaining = round(config.vote_period/10)
|
||||
for(var/c in GLOB.clients)
|
||||
var/client/C = c
|
||||
|
||||
@@ -485,7 +485,7 @@
|
||||
|
||||
/datum/action/spell_action/New(Target)
|
||||
..()
|
||||
var/obj/effect/proc_holder/spell/S = target
|
||||
var/obj/effect/proc_holder/S = target
|
||||
S.action = src
|
||||
name = S.name
|
||||
desc = S.desc
|
||||
@@ -495,36 +495,40 @@
|
||||
button.name = name
|
||||
|
||||
/datum/action/spell_action/Destroy()
|
||||
var/obj/effect/proc_holder/spell/S = target
|
||||
var/obj/effect/proc_holder/S = target
|
||||
S.action = null
|
||||
return ..()
|
||||
|
||||
/datum/action/spell_action/Trigger()
|
||||
if(!..())
|
||||
return 0
|
||||
return FALSE
|
||||
if(target)
|
||||
var/obj/effect/proc_holder/spell = target
|
||||
spell.Click()
|
||||
return 1
|
||||
var/obj/effect/proc_holder/S = target
|
||||
S.Click()
|
||||
return TRUE
|
||||
|
||||
/datum/action/spell_action/IsAvailable()
|
||||
if(!target)
|
||||
return 0
|
||||
var/obj/effect/proc_holder/spell/spell = target
|
||||
if(owner)
|
||||
return spell.can_cast(owner)
|
||||
return 0
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/action/spell_action/spell/IsAvailable()
|
||||
if(!target)
|
||||
return FALSE
|
||||
var/obj/effect/proc_holder/spell/S = target
|
||||
if(owner)
|
||||
return S.can_cast(owner)
|
||||
return FALSE
|
||||
|
||||
/datum/action/spell_action/alien
|
||||
|
||||
/datum/action/spell_action/alien/IsAvailable()
|
||||
if(!target)
|
||||
return 0
|
||||
return FALSE
|
||||
var/obj/effect/proc_holder/alien/ab = target
|
||||
if(owner)
|
||||
return ab.cost_check(ab.check_turf,owner,1)
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
|
||||
|
||||
|
||||
60
code/datums/antagonists/datum_abductor.dm
Normal file
60
code/datums/antagonists/datum_abductor.dm
Normal file
@@ -0,0 +1,60 @@
|
||||
/datum/antagonist/abductor
|
||||
name = "Abductor"
|
||||
var/datum/objective_team/abductor_team/team
|
||||
var/sub_role
|
||||
var/outfit
|
||||
var/landmark_type
|
||||
var/greet_text
|
||||
|
||||
/datum/antagonist/abductor/agent
|
||||
sub_role = "Agent"
|
||||
outfit = /datum/outfit/abductor/agent
|
||||
landmark_type = /obj/effect/landmark/abductor/agent
|
||||
greet_text = "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve."
|
||||
|
||||
/datum/antagonist/abductor/scientist
|
||||
sub_role = "Scientist"
|
||||
outfit = /datum/outfit/abductor/scientist
|
||||
landmark_type = /obj/effect/landmark/abductor/scientist
|
||||
greet_text = "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve."
|
||||
|
||||
/datum/antagonist/abductor/New(datum/mind/new_owner, datum/objective_team/abductor_team/T)
|
||||
team = T
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/abductor/on_gain()
|
||||
SSticker.mode.abductors += owner
|
||||
owner.special_role = "[name] [sub_role]"
|
||||
owner.objectives += team.objectives
|
||||
finalize_abductor()
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/abductor/on_removal()
|
||||
SSticker.mode.abductors -= owner
|
||||
team.members -= owner
|
||||
owner.objectives -= team.objectives
|
||||
if(owner.current)
|
||||
to_chat(owner.current,"<span class='userdanger'>You are no longer the [owner.special_role]!</span>")
|
||||
owner.special_role = null
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/abductor/greet()
|
||||
to_chat(owner.current, "<span class='notice'>You are the [owner.special_role]!</span>")
|
||||
to_chat(owner.current, "<span class='notice'>With the help of your teammate, kidnap and experiment on station crew members!</span>")
|
||||
to_chat(owner.current, "<span class='notice'>[greet_text]</span>")
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/antagonist/abductor/proc/finalize_abductor()
|
||||
//Equip
|
||||
var/mob/living/carbon/human/H = owner.current
|
||||
H.set_species(/datum/species/abductor)
|
||||
H.real_name = "[team.name] [sub_role]"
|
||||
H.equipOutfit(outfit)
|
||||
|
||||
//Teleport to ship
|
||||
for(var/obj/effect/landmark/abductor/LM in GLOB.landmarks_list)
|
||||
if(istype(LM, landmark_type) && LM.team_number == team.team_number)
|
||||
H.forceMove(LM.loc)
|
||||
break
|
||||
|
||||
SSticker.mode.update_abductor_icons_added(owner)
|
||||
@@ -103,23 +103,22 @@
|
||||
S.laws.associate(S)
|
||||
S.update_icons()
|
||||
S.show_laws()
|
||||
hierophant_network.Grant(S)
|
||||
hierophant_network.title = "Silicon"
|
||||
hierophant_network.span_for_name = "nezbere"
|
||||
hierophant_network.span_for_message = "brass"
|
||||
else if(isbrain(current))
|
||||
hierophant_network.Grant(current)
|
||||
hierophant_network.title = "Vessel"
|
||||
hierophant_network.span_for_name = "nezbere"
|
||||
hierophant_network.span_for_message = "alloy"
|
||||
else if(isclockmob(current))
|
||||
hierophant_network.Grant(current)
|
||||
hierophant_network.title = "Construct"
|
||||
hierophant_network.span_for_name = "nezbere"
|
||||
hierophant_network.span_for_message = "brass"
|
||||
hierophant_network.Grant(current)
|
||||
current.throw_alert("clockinfo", /obj/screen/alert/clockwork/infodump)
|
||||
if(!GLOB.clockwork_gateway_activated)
|
||||
current.throw_alert("scripturereq", /obj/screen/alert/clockwork/scripture_reqs)
|
||||
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
|
||||
if(G.active && ishuman(current))
|
||||
current.add_overlay(mutable_appearance('icons/effects/genetics.dmi', "servitude", -MUTATIONS_LAYER))
|
||||
|
||||
/datum/antagonist/clockcult/remove_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/current = owner.current
|
||||
@@ -129,9 +128,10 @@
|
||||
current.faction -= "ratvar"
|
||||
current.remove_language(/datum/language/ratvar)
|
||||
current.clear_alert("clockinfo")
|
||||
current.clear_alert("scripturereq")
|
||||
for(var/datum/action/innate/function_call/F in owner.current.actions) //Removes any bound Ratvarian spears
|
||||
qdel(F)
|
||||
for(var/datum/action/innate/clockwork_arnaments/C in owner.current.actions) //Removes any bound clockwork armor
|
||||
qdel(C)
|
||||
for(var/datum/action/innate/call_weapon/W in owner.current.actions) //and weapons too
|
||||
qdel(W)
|
||||
if(issilicon(current))
|
||||
var/mob/living/silicon/S = current
|
||||
if(isAI(S))
|
||||
@@ -149,6 +149,8 @@
|
||||
R.module.rebuild_modules()
|
||||
if(temp_owner)
|
||||
temp_owner.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them, we need to update buttons
|
||||
temp_owner.cut_overlays()
|
||||
temp_owner.regenerate_icons()
|
||||
|
||||
/datum/antagonist/clockcult/on_removal()
|
||||
SSticker.mode.servants_of_ratvar -= owner
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/datum/antagonist/ninja
|
||||
name = "Ninja"
|
||||
var/team
|
||||
var/helping_station = 0
|
||||
var/give_objectives = TRUE
|
||||
|
||||
@@ -19,36 +18,8 @@
|
||||
..(new_owner)
|
||||
helping_station = rand(0,1)
|
||||
|
||||
/datum/antagonist/ninja/proc/equip_space_ninja(mob/living/carbon/human/H = owner.current, safety=0)//Safety in case you need to unequip stuff for existing characters.
|
||||
if(safety)
|
||||
qdel(H.w_uniform)
|
||||
qdel(H.wear_suit)
|
||||
qdel(H.wear_mask)
|
||||
qdel(H.head)
|
||||
qdel(H.shoes)
|
||||
qdel(H.gloves)
|
||||
|
||||
var/obj/item/clothing/suit/space/space_ninja/theSuit = new(H)
|
||||
var/obj/item/dash/energy_katana/EK = new(H)
|
||||
theSuit.energyKatana = EK
|
||||
|
||||
H.equip_to_slot_or_del(new /obj/item/device/radio/headset(H), slot_ears)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/under/color/black(H), slot_w_uniform)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/space_ninja(H), slot_shoes)
|
||||
H.equip_to_slot_or_del(theSuit, slot_wear_suit)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/gloves/space_ninja(H), slot_gloves)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/space_ninja(H), slot_head)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/space_ninja(H), slot_wear_mask)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/glasses/night(H), slot_glasses)
|
||||
H.equip_to_slot_or_del(EK, slot_belt)
|
||||
H.equip_to_slot_or_del(new /obj/item/grenade/plastic/x4(H), slot_l_store)
|
||||
H.equip_to_slot_or_del(new /obj/item/tank/internals/emergency_oxygen(H), slot_s_store)
|
||||
H.equip_to_slot_or_del(new /obj/item/tank/jetpack/carbondioxide(H), slot_back)
|
||||
theSuit.randomize_param()
|
||||
|
||||
var/obj/item/implant/explosive/E = new/obj/item/implant/explosive(H)
|
||||
E.implant(H)
|
||||
return 1
|
||||
/datum/antagonist/ninja/proc/equip_space_ninja(mob/living/carbon/human/H = owner.current)
|
||||
return H.equipOutfit(/datum/outfit/ninja)
|
||||
|
||||
/datum/antagonist/ninja/proc/addMemories()
|
||||
owner.store_memory("I am an elite mercenary assassin of the mighty Spider Clan. A <font color='red'><B>SPACE NINJA</B></font>!")
|
||||
|
||||
223
code/datums/cinematic.dm
Normal file
223
code/datums/cinematic.dm
Normal file
@@ -0,0 +1,223 @@
|
||||
GLOBAL_LIST_EMPTY(cinematics)
|
||||
|
||||
// Use to play cinematics.
|
||||
// Watcher can be world,mob, or a list of mobs
|
||||
// Blocks until sequence is done.
|
||||
/proc/Cinematic(id,watcher,datum/callback/special_callback)
|
||||
var/datum/cinematic/playing
|
||||
for(var/V in subtypesof(/datum/cinematic))
|
||||
var/datum/cinematic/C = V
|
||||
if(initial(C.id) == id)
|
||||
playing = new V()
|
||||
break
|
||||
if(!playing)
|
||||
CRASH("Cinematic type not found")
|
||||
if(special_callback)
|
||||
playing.special_callback = special_callback
|
||||
if(watcher == world)
|
||||
playing.is_global = TRUE
|
||||
watcher = GLOB.mob_list
|
||||
playing.play(watcher)
|
||||
|
||||
/obj/screen/cinematic
|
||||
icon = 'icons/effects/station_explosion.dmi'
|
||||
icon_state = "station_intact"
|
||||
layer = 21
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
screen_loc = "1,1"
|
||||
|
||||
/datum/cinematic
|
||||
var/id = CINEMATIC_DEFAULT
|
||||
var/list/watching = list() //List of clients watching this
|
||||
var/list/locked = list() //Who had notransform set during the cinematic
|
||||
var/is_global = FALSE //Global cinematics will override mob-specific ones
|
||||
var/obj/screen/cinematic/screen
|
||||
var/datum/callback/special_callback //For special effects synced with animation (explosions after the countdown etc)
|
||||
var/cleanup_time = 300 //How long for the final screen to remain
|
||||
|
||||
/datum/cinematic/New()
|
||||
GLOB.cinematics += src
|
||||
screen = new(src)
|
||||
|
||||
/datum/cinematic/Destroy()
|
||||
GLOB.cinematics -= src
|
||||
QDEL_NULL(screen)
|
||||
for(var/mob/M in locked)
|
||||
M.notransform = FALSE
|
||||
return ..()
|
||||
|
||||
/datum/cinematic/proc/play(watchers)
|
||||
//Check if you can actually play it (stop mob cinematics for global ones) and create screen objects
|
||||
for(var/A in GLOB.cinematics)
|
||||
var/datum/cinematic/C = A
|
||||
if(C == src)
|
||||
continue
|
||||
if(C.is_global || !is_global)
|
||||
return //Can't play two global or local cinematics at the same time
|
||||
|
||||
//Close all open windows if global
|
||||
if(is_global)
|
||||
for (var/datum/html_interface/hi in GLOB.html_interfaces)
|
||||
hi.closeAll()
|
||||
SStgui.close_all_uis()
|
||||
|
||||
|
||||
for(var/mob/M in GLOB.mob_list)
|
||||
if(M in watchers)
|
||||
M.notransform = TRUE //Should this be done for non-global cinematics or even at all ?
|
||||
locked += M
|
||||
//Close watcher ui's
|
||||
SStgui.close_user_uis(M)
|
||||
if(M.client)
|
||||
watching += M.client
|
||||
M.client.screen += screen
|
||||
else
|
||||
if(is_global)
|
||||
M.notransform = TRUE
|
||||
locked += M
|
||||
|
||||
//Actually play it
|
||||
content()
|
||||
//Cleanup
|
||||
sleep(cleanup_time)
|
||||
qdel(src)
|
||||
|
||||
//Sound helper
|
||||
/datum/cinematic/proc/cinematic_sound(s)
|
||||
if(is_global)
|
||||
SEND_SOUND(world,s)
|
||||
else
|
||||
for(var/C in watching)
|
||||
SEND_SOUND(C,s)
|
||||
|
||||
//Fire up special callback for actual effects synchronized with animation (eg real nuke explosion happens midway)
|
||||
/datum/cinematic/proc/special()
|
||||
if(special_callback)
|
||||
special_callback.Invoke()
|
||||
|
||||
//Actual cinematic goes in here
|
||||
/datum/cinematic/proc/content()
|
||||
sleep(50)
|
||||
|
||||
/datum/cinematic/nuke_win
|
||||
id = CINEMATIC_NUKE_WIN
|
||||
|
||||
/datum/cinematic/nuke_win/content()
|
||||
flick("intro_nuke",screen)
|
||||
sleep(35)
|
||||
flick("station_explode_fade_red",screen)
|
||||
cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
|
||||
special()
|
||||
screen.icon_state = "summary_nukewin"
|
||||
|
||||
/datum/cinematic/nuke_miss
|
||||
id = CINEMATIC_NUKE_MISS
|
||||
|
||||
/datum/cinematic/nuke_miss/content()
|
||||
flick("intro_nuke",screen)
|
||||
sleep(35)
|
||||
cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
|
||||
special()
|
||||
flick("station_intact_fade_red",screen)
|
||||
screen.icon_state = "summary_nukefail"
|
||||
|
||||
//Also used for blob
|
||||
/datum/cinematic/nuke_selfdestruct
|
||||
id = CINEMATIC_SELFDESTRUCT
|
||||
|
||||
/datum/cinematic/nuke_selfdestruct/content()
|
||||
flick("intro_nuke",screen)
|
||||
sleep(35)
|
||||
flick("station_explode_fade_red", screen)
|
||||
cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
|
||||
special()
|
||||
screen.icon_state = "summary_selfdes"
|
||||
|
||||
/datum/cinematic/nuke_selfdestruct_miss
|
||||
id = CINEMATIC_SELFDESTRUCT_MISS
|
||||
|
||||
/datum/cinematic/nuke_selfdestruct_miss/content()
|
||||
flick("intro_nuke",screen)
|
||||
sleep(35)
|
||||
cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
|
||||
special()
|
||||
screen.icon_state = "station_intact"
|
||||
|
||||
/datum/cinematic/malf
|
||||
id = CINEMATIC_MALF
|
||||
|
||||
/datum/cinematic/malf/content()
|
||||
flick("intro_malf",screen)
|
||||
sleep(76)
|
||||
flick("station_explode_fade_red",screen)
|
||||
cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
|
||||
special()
|
||||
screen.icon_state = "summary_malf"
|
||||
|
||||
/datum/cinematic/cult
|
||||
id = CINEMATIC_CULT
|
||||
|
||||
/datum/cinematic/cult/content()
|
||||
screen.icon_state = null
|
||||
flick("intro_cult",screen)
|
||||
sleep(25)
|
||||
cinematic_sound(sound('sound/magic/enter_blood.ogg'))
|
||||
sleep(28)
|
||||
cinematic_sound(sound('sound/machines/terminal_off.ogg'))
|
||||
sleep(20)
|
||||
flick("station_corrupted",screen)
|
||||
cinematic_sound(sound('sound/effects/ghost.ogg'))
|
||||
sleep(70)
|
||||
special()
|
||||
|
||||
/datum/cinematic/nuke_annihilation
|
||||
id = CINEMATIC_ANNIHILATION
|
||||
|
||||
/datum/cinematic/nuke_annihilation/content()
|
||||
flick("intro_nuke",screen)
|
||||
sleep(35)
|
||||
flick("station_explode_fade_red",screen)
|
||||
cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
|
||||
special()
|
||||
screen.icon_state = "summary_totala"
|
||||
|
||||
/datum/cinematic/fake
|
||||
id = CINEMATIC_NUKE_FAKE
|
||||
cleanup_time = 100
|
||||
|
||||
/datum/cinematic/fake/content()
|
||||
flick("intro_nuke",screen)
|
||||
sleep(35)
|
||||
cinematic_sound(sound('sound/items/bikehorn.ogg'))
|
||||
flick("summary_selfdes",screen) //???
|
||||
special()
|
||||
|
||||
/datum/cinematic/no_core
|
||||
id = CINEMATIC_NUKE_NO_CORE
|
||||
cleanup_time = 100
|
||||
|
||||
/datum/cinematic/no_core/content()
|
||||
flick("intro_nuke",screen)
|
||||
sleep(35)
|
||||
flick("station_intact",screen)
|
||||
cinematic_sound(sound('sound/ambience/signal.ogg'))
|
||||
sleep(100)
|
||||
|
||||
/datum/cinematic/nuke_far
|
||||
id = CINEMATIC_NUKE_FAR
|
||||
cleanup_time = 0
|
||||
|
||||
/datum/cinematic/nuke_far/content()
|
||||
cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
|
||||
special()
|
||||
|
||||
/* Intended usage.
|
||||
Nuke.Explosion()
|
||||
-> Cinematic(NUKE_BOOM,world)
|
||||
-> ActualExplosion()
|
||||
-> Mode.OnExplosion()
|
||||
|
||||
|
||||
Narsie()
|
||||
-> Cinematic(CULT,world)
|
||||
*/
|
||||
@@ -94,7 +94,8 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
|
||||
* Allows the component to react to ownership transfers
|
||||
1. `/datum/component/proc/_RemoveNoSignal()` (private, final)
|
||||
* Internal, clears the parent var and removes the component from the parents component list
|
||||
1. `/datum/component/proc/RegisterSignal(signal(string), proc_ref(type), override(boolean))` (protected, final) (Consider removing for performance gainz)
|
||||
1. `/datum/component/proc/RegisterSignal(signal(string/list of strings), proc_ref(type), override(boolean))` (protected, final) (Consider removing for performance gainz)
|
||||
* If signal is a list it will be as if RegisterSignal was called for each of the entries with the same following arguments
|
||||
* Makes a component listen for the specified `signal` on it's `parent` datum.
|
||||
* When that signal is recieved `proc_ref` will be called on the component, along with associated arguments
|
||||
* Example proc ref: `.proc/OnEvent`
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
P.datum_components = null
|
||||
parent = null
|
||||
|
||||
/datum/component/proc/RegisterSignal(sig_type, proc_on_self, override = FALSE)
|
||||
/datum/component/proc/RegisterSignal(sig_type_or_types, proc_on_self, override = FALSE)
|
||||
if(QDELETED(src))
|
||||
return
|
||||
var/list/procs = signal_procs
|
||||
@@ -103,12 +103,14 @@
|
||||
procs = list()
|
||||
signal_procs = procs
|
||||
|
||||
if(!override)
|
||||
. = procs[sig_type]
|
||||
if(.)
|
||||
stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning")
|
||||
|
||||
procs[sig_type] = CALLBACK(src, proc_on_self)
|
||||
var/list/sig_types = islist(sig_type_or_types) ? sig_type_or_types : list(sig_type_or_types)
|
||||
for(var/sig_type in sig_types)
|
||||
if(!override)
|
||||
. = procs[sig_type]
|
||||
if(.)
|
||||
stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning")
|
||||
|
||||
procs[sig_type] = CALLBACK(src, proc_on_self)
|
||||
|
||||
/datum/component/proc/InheritComponent(datum/component/C, i_am_original)
|
||||
return
|
||||
|
||||
@@ -6,10 +6,7 @@
|
||||
/datum/component/slippery/Initialize(_intensity, _lube_flags = NONE)
|
||||
intensity = max(_intensity, 0)
|
||||
lube_flags = _lube_flags
|
||||
if(ismovableatom(parent))
|
||||
RegisterSignal(COMSIG_MOVABLE_CROSSED, .proc/Slip)
|
||||
else
|
||||
RegisterSignal(COMSIG_ATOM_ENTERED, .proc/Slip)
|
||||
RegisterSignal(list(COMSIG_MOVABLE_CROSSED, COMSIG_ATOM_ENTERED), .proc/Slip)
|
||||
|
||||
/datum/component/slippery/proc/Slip(atom/movable/AM)
|
||||
var/mob/victim = AM
|
||||
|
||||
@@ -24,22 +24,9 @@
|
||||
if(use_delay_override)
|
||||
use_delay = use_delay_override
|
||||
|
||||
if(istype(parent, /atom))
|
||||
RegisterSignal(COMSIG_ATOM_BLOB_ACT, .proc/play_squeak)
|
||||
RegisterSignal(COMSIG_ATOM_HULK_ATTACK, .proc/play_squeak)
|
||||
RegisterSignal(COMSIG_PARENT_ATTACKBY, .proc/play_squeak)
|
||||
if(istype(parent, /atom/movable))
|
||||
RegisterSignal(COMSIG_MOVABLE_CROSSED, .proc/play_squeak)
|
||||
RegisterSignal(COMSIG_MOVABLE_COLLIDE, .proc/play_squeak)
|
||||
RegisterSignal(COMSIG_MOVABLE_IMPACT, .proc/play_squeak)
|
||||
if(istype(parent, /obj/item))
|
||||
RegisterSignal(COMSIG_ITEM_ATTACK, .proc/play_squeak)
|
||||
RegisterSignal(COMSIG_ITEM_ATTACK_SELF, .proc/use_squeak)
|
||||
RegisterSignal(COMSIG_ITEM_ATTACK_OBJ, .proc/play_squeak)
|
||||
if(istype(parent, /obj/item/clothing/shoes))
|
||||
RegisterSignal(COMSIG_SHOES_STEP_ACTION, .proc/step_squeak)
|
||||
else
|
||||
RegisterSignal(COMSIG_ATOM_ENTERED, .proc/play_squeak)
|
||||
RegisterSignal(list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_BLOB_ACT, COMSIG_ATOM_HULK_ATTACK, COMSIG_PARENT_ATTACKBY, COMSIG_MOVABLE_CROSSED, COMSIG_MOVABLE_COLLIDE, COMSIG_MOVABLE_IMPACT, COMSIG_ITEM_ATTACK, COMSIG_ITEM_ATTACK_OBJ, COMSIG_ITEM_ATTACK_OBJ), .proc/play_squeak)
|
||||
RegisterSignal(COMSIG_ITEM_ATTACK_SELF, .proc/use_squeak)
|
||||
RegisterSignal(COMSIG_SHOES_STEP_ACTION, .proc/step_squeak)
|
||||
|
||||
/datum/component/squeak/proc/play_squeak()
|
||||
if(prob(squeak_chance))
|
||||
|
||||
@@ -1,103 +1,111 @@
|
||||
#define FORWARD -1
|
||||
#define BACKWARD 1
|
||||
|
||||
/datum/construction
|
||||
var/list/steps
|
||||
var/atom/holder
|
||||
var/result
|
||||
var/list/steps_desc
|
||||
|
||||
/datum/construction/New(atom)
|
||||
..()
|
||||
holder = atom
|
||||
if(!holder) //don't want this without a holder
|
||||
qdel(src)
|
||||
set_desc(steps.len)
|
||||
return
|
||||
|
||||
/datum/construction/proc/next_step()
|
||||
steps.len--
|
||||
if(!steps.len)
|
||||
spawn_result()
|
||||
else
|
||||
set_desc(steps.len)
|
||||
return
|
||||
|
||||
/datum/construction/proc/action(atom/used_atom,mob/user)
|
||||
return
|
||||
|
||||
/datum/construction/proc/check_step(atom/used_atom,mob/user) //check last step only
|
||||
var/valid_step = is_right_key(used_atom)
|
||||
if(valid_step)
|
||||
if(custom_action(valid_step, used_atom, user))
|
||||
next_step()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/construction/proc/is_right_key(atom/used_atom) // returns current step num if used_atom is of the right type.
|
||||
var/list/L = steps[steps.len]
|
||||
if(istype(used_atom, L["key"]))
|
||||
return steps.len
|
||||
return 0
|
||||
|
||||
/datum/construction/proc/custom_action(step, used_atom, user)
|
||||
return 1
|
||||
|
||||
/datum/construction/proc/check_all_steps(atom/used_atom,mob/user) //check all steps, remove matching one.
|
||||
for(var/i=1;i<=steps.len;i++)
|
||||
var/list/L = steps[i];
|
||||
if(istype(used_atom, L["key"]))
|
||||
if(custom_action(i, used_atom, user))
|
||||
steps[i]=null;//stupid byond list from list removal...
|
||||
listclearnulls(steps);
|
||||
if(!steps.len)
|
||||
spawn_result()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
/datum/construction/proc/spawn_result()
|
||||
if(result)
|
||||
new result(get_turf(holder))
|
||||
qdel(holder)
|
||||
return
|
||||
|
||||
/datum/construction/proc/set_desc(index as num)
|
||||
var/list/step = steps[index]
|
||||
holder.desc = step["desc"]
|
||||
return
|
||||
|
||||
/datum/construction/reversible
|
||||
var/index
|
||||
|
||||
/datum/construction/reversible/New(atom)
|
||||
..()
|
||||
index = steps.len
|
||||
return
|
||||
|
||||
/datum/construction/reversible/proc/update_index(diff as num)
|
||||
index+=diff
|
||||
if(index==0)
|
||||
spawn_result()
|
||||
else
|
||||
set_desc(index)
|
||||
return
|
||||
|
||||
/datum/construction/reversible/is_right_key(atom/used_atom) // returns index step
|
||||
var/list/L = steps[index]
|
||||
if(istype(used_atom, L["key"]))
|
||||
return FORWARD //to the first step -> forward
|
||||
else if(L["backkey"] && istype(used_atom, L["backkey"]))
|
||||
return BACKWARD //to the last step -> backwards
|
||||
return 0
|
||||
|
||||
/datum/construction/reversible/check_step(atom/used_atom,mob/user)
|
||||
var/diff = is_right_key(used_atom)
|
||||
if(diff)
|
||||
if(custom_action(index, diff, used_atom, user))
|
||||
update_index(diff)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/construction/reversible/custom_action(index, diff, used_atom, user)
|
||||
return 1
|
||||
#define FORWARD -1
|
||||
#define BACKWARD 1
|
||||
|
||||
/datum/construction
|
||||
var/list/steps
|
||||
var/atom/holder
|
||||
var/result
|
||||
var/list/steps_desc
|
||||
|
||||
/datum/construction/New(atom)
|
||||
..()
|
||||
holder = atom
|
||||
if(!holder) //don't want this without a holder
|
||||
qdel(src)
|
||||
set_desc(steps.len)
|
||||
return
|
||||
|
||||
/datum/construction/proc/next_step()
|
||||
steps.len--
|
||||
if(!steps.len)
|
||||
spawn_result()
|
||||
else
|
||||
set_desc(steps.len)
|
||||
return
|
||||
|
||||
/datum/construction/proc/action(atom/used_atom,mob/user)
|
||||
return
|
||||
|
||||
/datum/construction/proc/check_step(atom/used_atom,mob/user) //check last step only
|
||||
var/valid_step = is_right_key(used_atom)
|
||||
if(valid_step)
|
||||
if(custom_action(valid_step, used_atom, user))
|
||||
next_step()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/construction/proc/is_right_key(atom/used_atom) // returns current step num if used_atom is of the right type.
|
||||
var/list/L = steps[steps.len]
|
||||
if(istype(used_atom, L["key"]))
|
||||
return steps.len
|
||||
return 0
|
||||
|
||||
/datum/construction/proc/custom_action(step, used_atom, user)
|
||||
return 1
|
||||
|
||||
/datum/construction/proc/check_all_steps(atom/used_atom,mob/user) //check all steps, remove matching one.
|
||||
for(var/i=1;i<=steps.len;i++)
|
||||
var/list/L = steps[i];
|
||||
if(istype(used_atom, L["key"]))
|
||||
if(custom_action(i, used_atom, user))
|
||||
steps[i]=null;//stupid byond list from list removal...
|
||||
listclearnulls(steps);
|
||||
if(!steps.len)
|
||||
spawn_result()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
/datum/construction/proc/spawn_result()
|
||||
if(result)
|
||||
new result(get_turf(holder))
|
||||
qdel(holder)
|
||||
return
|
||||
|
||||
/datum/construction/proc/spawn_mecha_result()
|
||||
if(result)
|
||||
var/obj/mecha/m = new result(get_turf(holder))
|
||||
var/obj/item/oldcell = locate (/obj/item/stock_parts/cell) in m
|
||||
QDEL_NULL(oldcell)
|
||||
m.CheckParts(holder.contents)
|
||||
QDEL_NULL(holder)
|
||||
|
||||
/datum/construction/proc/set_desc(index as num)
|
||||
var/list/step = steps[index]
|
||||
holder.desc = step["desc"]
|
||||
return
|
||||
|
||||
/datum/construction/reversible
|
||||
var/index
|
||||
|
||||
/datum/construction/reversible/New(atom)
|
||||
..()
|
||||
index = steps.len
|
||||
return
|
||||
|
||||
/datum/construction/reversible/proc/update_index(diff as num)
|
||||
index+=diff
|
||||
if(index==0)
|
||||
spawn_result()
|
||||
else
|
||||
set_desc(index)
|
||||
return
|
||||
|
||||
/datum/construction/reversible/is_right_key(atom/used_atom) // returns index step
|
||||
var/list/L = steps[index]
|
||||
if(istype(used_atom, L["key"]))
|
||||
return FORWARD //to the first step -> forward
|
||||
else if(L["backkey"] && istype(used_atom, L["backkey"]))
|
||||
return BACKWARD //to the last step -> backwards
|
||||
return 0
|
||||
|
||||
/datum/construction/reversible/check_step(atom/used_atom,mob/user)
|
||||
var/diff = is_right_key(used_atom)
|
||||
if(diff)
|
||||
if(custom_action(index, diff, used_atom, user))
|
||||
update_index(diff)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/construction/reversible/custom_action(index, diff, used_atom, user)
|
||||
return 1
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
var/minetype = "lavaland"
|
||||
|
||||
var/list/transition_config = list(CENTCOM = SELFLOOPING,
|
||||
CITY_OF_COGS = SELFLOOPING,
|
||||
MAIN_STATION = CROSSLINKED,
|
||||
EMPTY_AREA_1 = CROSSLINKED,
|
||||
EMPTY_AREA_2 = CROSSLINKED,
|
||||
@@ -119,6 +120,8 @@
|
||||
return MAIN_STATION
|
||||
if("CENTCOM")
|
||||
return CENTCOM
|
||||
if("CITY_OF_COGS")
|
||||
return CITY_OF_COGS
|
||||
if("MINING")
|
||||
return MINING
|
||||
if("EMPTY_AREA_1")
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
/datum/action/neck_chop/Trigger()
|
||||
if(owner.incapacitated())
|
||||
to_chat(owner, "<span class='warning'>You can't use Krav Maga while you're incapacitated.</span>")
|
||||
to_chat(owner, "<span class='warning'>You can't use [name] while you're incapacitated.</span>")
|
||||
return
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if (H.mind.martial_art.streak == "neck_chop")
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
/datum/action/leg_sweep/Trigger()
|
||||
if(owner.incapacitated())
|
||||
to_chat(owner, "<span class='warning'>You can't use Krav Maga while you're incapacitated.</span>")
|
||||
to_chat(owner, "<span class='warning'>You can't use [name] while you're incapacitated.</span>")
|
||||
return
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if (H.mind.martial_art.streak == "leg_sweep")
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
/datum/action/lung_punch/Trigger()
|
||||
if(owner.incapacitated())
|
||||
to_chat(owner, "<span class='warning'>You can't use Krav Maga while you're incapacitated.</span>")
|
||||
to_chat(owner, "<span class='warning'>You can't use [name] while you're incapacitated.</span>")
|
||||
return
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if (H.mind.martial_art.streak == "quick_choke")
|
||||
@@ -57,14 +57,14 @@
|
||||
|
||||
/datum/martial_art/krav_maga/teach(mob/living/carbon/human/H,make_temporary=0)
|
||||
if(..())
|
||||
to_chat(H, "<span class = 'userdanger'>You know the arts of Krav Maga!</span>")
|
||||
to_chat(H, "<span class = 'userdanger'>You know the arts of [name]!</span>")
|
||||
to_chat(H, "<span class = 'danger'>Place your cursor over a move at the top of the screen to see what it does.</span>")
|
||||
neckchop.Grant(H)
|
||||
legsweep.Grant(H)
|
||||
lungpunch.Grant(H)
|
||||
|
||||
/datum/martial_art/krav_maga/on_remove(mob/living/carbon/human/H)
|
||||
to_chat(H, "<span class = 'userdanger'>You suddenly forget the arts of Krav Maga...</span>")
|
||||
to_chat(H, "<span class = 'userdanger'>You suddenly forget the arts of [name]...</span>")
|
||||
neckchop.Remove(H)
|
||||
legsweep.Remove(H)
|
||||
lungpunch.Remove(H)
|
||||
@@ -140,7 +140,7 @@
|
||||
playsound(get_turf(D), 'sound/effects/hit_punch.ogg', 50, 1, -1)
|
||||
D.visible_message("<span class='danger'>[A] [picked_hit_type] [D]!</span>", \
|
||||
"<span class='userdanger'>[A] [picked_hit_type] you!</span>")
|
||||
add_logs(A, D, "[picked_hit_type] with Krav Maga")
|
||||
add_logs(A, D, "[picked_hit_type] with [name]")
|
||||
return 1
|
||||
|
||||
/datum/martial_art/krav_maga/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
|
||||
|
||||
@@ -590,8 +590,6 @@
|
||||
if(src in SSticker.mode.abductors)
|
||||
text += "<b>Abductor</b> | <a href='?src=\ref[src];abductor=clear'>human</a>"
|
||||
text += " | <a href='?src=\ref[src];common=undress'>undress</a> | <a href='?src=\ref[src];abductor=equip'>equip</a>"
|
||||
else
|
||||
text += "<a href='?src=\ref[src];abductor=abductor'>abductor</a> | <b>human</b>"
|
||||
|
||||
if(current && current.client && (ROLE_ABDUCTOR in current.client.prefs.be_special))
|
||||
text += " | Enabled in Prefs"
|
||||
@@ -674,7 +672,7 @@
|
||||
text = "<i><b>[text]</b></i>: "
|
||||
if(is_servant_of_ratvar(current))
|
||||
text += "not mindshielded | <a href='?src=\ref[src];clockcult=clear'>employee</a> | <b>SERVANT</b>"
|
||||
text += "<br><a href='?src=\ref[src];clockcult=slab'>Give slab</a>"
|
||||
text += "<br><a href='?src=\ref[src];clockcult=slab'>Equip</a>"
|
||||
else if(is_eligible_servant(current))
|
||||
text += "not mindshielded | <b>EMPLOYEE</b> | <a href='?src=\ref[src];clockcult=servant'>servant</a>"
|
||||
else
|
||||
@@ -1037,9 +1035,9 @@
|
||||
log_admin("[key_name(usr)] has made [current] into a servant of Ratvar.")
|
||||
if("slab")
|
||||
if(!SSticker.mode.equip_servant(current))
|
||||
to_chat(usr, "<span class='warning'>Failed to outfit [current] with a slab!</span>")
|
||||
to_chat(usr, "<span class='warning'>Failed to outfit [current]!</span>")
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>Successfully gave [current] a clockwork slab!</span>")
|
||||
to_chat(usr, "<span class='notice'>Successfully gave [current] servant equipment!</span>")
|
||||
|
||||
else if (href_list["wizard"])
|
||||
switch(href_list["wizard"])
|
||||
@@ -1244,13 +1242,6 @@
|
||||
if("clear")
|
||||
to_chat(usr, "Not implemented yet. Sorry!")
|
||||
//SSticker.mode.update_abductor_icons_removed(src)
|
||||
if("abductor")
|
||||
if(!ishuman(current))
|
||||
to_chat(usr, "<span class='warning'>This only works on humans!</span>")
|
||||
return
|
||||
make_Abductor()
|
||||
log_admin("[key_name(usr)] turned [current] into abductor.")
|
||||
SSticker.mode.update_abductor_icons_added(src)
|
||||
if("equip")
|
||||
if(!ishuman(current))
|
||||
to_chat(usr, "<span class='warning'>This only works on humans!</span>")
|
||||
@@ -1496,52 +1487,7 @@
|
||||
take_uplink()
|
||||
var/fail = 0
|
||||
fail |= !SSticker.mode.equip_revolutionary(current)
|
||||
|
||||
/datum/mind/proc/make_Abductor()
|
||||
var/role = alert("Abductor Role ?","Role","Agent","Scientist")
|
||||
var/team = input("Abductor Team ?","Team ?") in list(1,2,3,4)
|
||||
var/teleport = alert("Teleport to ship ?","Teleport","Yes","No")
|
||||
|
||||
if(!role || !team || !teleport)
|
||||
return
|
||||
|
||||
if(!ishuman(current))
|
||||
return
|
||||
|
||||
SSticker.mode.abductors |= src
|
||||
|
||||
var/datum/objective/experiment/O = new
|
||||
O.owner = src
|
||||
objectives += O
|
||||
|
||||
var/mob/living/carbon/human/H = current
|
||||
|
||||
H.set_species(/datum/species/abductor)
|
||||
var/datum/species/abductor/S = H.dna.species
|
||||
|
||||
if(role == "Scientist")
|
||||
S.scientist = TRUE
|
||||
S.team = team
|
||||
|
||||
var/list/obj/effect/landmark/abductor/agent_landmarks = new
|
||||
var/list/obj/effect/landmark/abductor/scientist_landmarks = new
|
||||
agent_landmarks.len = 4
|
||||
scientist_landmarks.len = 4
|
||||
for(var/obj/effect/landmark/abductor/A in GLOB.landmarks_list)
|
||||
if(istype(A, /obj/effect/landmark/abductor/agent))
|
||||
agent_landmarks[text2num(A.team)] = A
|
||||
else if(istype(A, /obj/effect/landmark/abductor/scientist))
|
||||
scientist_landmarks[text2num(A.team)] = A
|
||||
|
||||
var/obj/effect/landmark/L
|
||||
if(teleport=="Yes")
|
||||
switch(role)
|
||||
if("Agent")
|
||||
L = agent_landmarks[team]
|
||||
if("Scientist")
|
||||
L = scientist_landmarks[team]
|
||||
H.forceMove(L.loc)
|
||||
|
||||
|
||||
/datum/mind/proc/AddSpell(obj/effect/proc_holder/spell/S)
|
||||
spell_list += S
|
||||
S.action.Grant(current)
|
||||
|
||||
@@ -102,10 +102,10 @@
|
||||
if(implants)
|
||||
for(var/implant_type in implants)
|
||||
var/obj/item/implant/I = new implant_type(H)
|
||||
I.implant(H, null, silent=TRUE)
|
||||
I.implant(H, null, TRUE)
|
||||
|
||||
H.update_body()
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/datum/outfit/proc/apply_fingerprints(mob/living/carbon/human/H)
|
||||
if(!istype(H))
|
||||
|
||||
@@ -148,21 +148,6 @@
|
||||
if(owner.m_intent == MOVE_INTENT_WALK)
|
||||
owner.toggle_move_intent()
|
||||
|
||||
/datum/status_effect/geis_tracker
|
||||
id = "geis_tracker"
|
||||
duration = -1
|
||||
alert_type = null
|
||||
var/obj/structure/destructible/clockwork/geis_binding/binding
|
||||
|
||||
/datum/status_effect/geis_tracker/on_creation(mob/living/new_owner, obj/structure/destructible/clockwork/geis_binding/new_binding)
|
||||
. = ..()
|
||||
if(.)
|
||||
binding = new_binding
|
||||
|
||||
/datum/status_effect/geis_tracker/tick()
|
||||
if(QDELETED(binding))
|
||||
qdel(src)
|
||||
|
||||
/datum/status_effect/maniamotor
|
||||
id = "maniamotor"
|
||||
duration = -1
|
||||
@@ -200,7 +185,7 @@
|
||||
return
|
||||
if(!motor.active) //it being off makes it fall off much faster
|
||||
if(!is_servant && !warned_turnoff)
|
||||
if(motor.total_accessable_power() > motor.mania_cost)
|
||||
if(can_access_clockwork_power(motor, motor.mania_cost))
|
||||
to_chat(owner, "<span class='sevtug[span_part]'>\"[text2ratvar(pick(turnoff_messages))]\"</span>")
|
||||
else
|
||||
var/pickedmessage = pick(powerloss_messages)
|
||||
@@ -461,3 +446,40 @@
|
||||
/obj/effect/temp_visual/curse/Initialize()
|
||||
. = ..()
|
||||
deltimer(timerid)
|
||||
|
||||
|
||||
//Kindle: Used by servants of Ratvar. 10-second knockdown, reduced by 1 second per 5 damage taken while the effect is active.
|
||||
/datum/status_effect/kindle
|
||||
id = "kindle"
|
||||
status_type = STATUS_EFFECT_UNIQUE
|
||||
tick_interval = 5
|
||||
duration = 100
|
||||
alert_type = /obj/screen/alert/status_effect/kindle
|
||||
var/old_health
|
||||
|
||||
/datum/status_effect/kindle/tick()
|
||||
owner.Knockdown(15)
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/C = owner
|
||||
C.silent = max(2, C.silent)
|
||||
C.stuttering = max(5, C.stuttering)
|
||||
if(!old_health)
|
||||
old_health = owner.health
|
||||
var/health_difference = old_health - owner.health
|
||||
if(!health_difference)
|
||||
return
|
||||
owner.visible_message("<span class='warning'>The light in [owner]'s eyes dims as they're harmed!</span>", \
|
||||
"<span class='boldannounce'>The dazzling lights dim as you're harmed!</span>")
|
||||
health_difference *= 2 //so 10 health difference translates to 20 deciseconds of stun reduction
|
||||
duration -= health_difference
|
||||
old_health = owner.health
|
||||
|
||||
/datum/status_effect/kindle/on_remove()
|
||||
owner.visible_message("<span class='warning'>The light in [owner]'s eyes fades!</span>", \
|
||||
"<span class='boldannounce'>You snap out of your daze!</span>")
|
||||
|
||||
/obj/screen/alert/status_effect/kindle
|
||||
name = "Dazzling Lights"
|
||||
desc = "Blinding light dances in your vision, stunning and silencing you. <i>Any damage taken will shorten the light's effects!</i>"
|
||||
icon_state = "kindle"
|
||||
alerttooltipstyle = "clockcult"
|
||||
|
||||
@@ -143,3 +143,18 @@
|
||||
|
||||
/area/ctf/flag_room2
|
||||
name = "Flag Room B"
|
||||
|
||||
// REEBE
|
||||
|
||||
/area/reebe
|
||||
name = "Reebe"
|
||||
icon_state = "yellow"
|
||||
requires_power = FALSE
|
||||
has_gravity = TRUE
|
||||
noteleport = TRUE
|
||||
hidden = TRUE
|
||||
|
||||
/area/reebe/city_of_cogs
|
||||
name = "City of Cogs"
|
||||
icon_state = "purple"
|
||||
hidden = FALSE
|
||||
|
||||
@@ -225,6 +225,17 @@
|
||||
A.CollidedWith(src)
|
||||
|
||||
/atom/movable/proc/forceMove(atom/destination)
|
||||
. = FALSE
|
||||
if(destination)
|
||||
. = doMove(destination)
|
||||
else
|
||||
CRASH("No valid destination passed into forceMove")
|
||||
|
||||
/atom/movable/proc/moveToNullspace()
|
||||
return doMove(null)
|
||||
|
||||
/atom/movable/proc/doMove(atom/destination)
|
||||
. = FALSE
|
||||
if(destination)
|
||||
if(pulledby)
|
||||
pulledby.stop_pulling()
|
||||
@@ -251,8 +262,17 @@
|
||||
AM.Crossed(src, oldloc)
|
||||
|
||||
Moved(oldloc, 0)
|
||||
return 1
|
||||
return 0
|
||||
. = TRUE
|
||||
|
||||
//If no destination, move the atom into nullspace (don't do this unless you know what you're doing)
|
||||
else
|
||||
. = TRUE
|
||||
var/atom/oldloc = loc
|
||||
var/area/old_area = get_area(oldloc)
|
||||
oldloc.Exited(src, null)
|
||||
if(old_area)
|
||||
old_area.Exited(src, null)
|
||||
loc = null
|
||||
|
||||
/mob/living/forceMove(atom/destination)
|
||||
stop_pulling()
|
||||
@@ -261,9 +281,10 @@
|
||||
if(has_buckled_mobs())
|
||||
unbuckle_all_mobs(force=1)
|
||||
. = ..()
|
||||
if(client)
|
||||
reset_perspective(destination)
|
||||
update_canmove() //if the mob was asleep inside a container and then got forceMoved out we need to make them fall.
|
||||
if(.)
|
||||
if(client)
|
||||
reset_perspective(destination)
|
||||
update_canmove() //if the mob was asleep inside a container and then got forceMoved out we need to make them fall.
|
||||
|
||||
/mob/living/brain/forceMove(atom/destination)
|
||||
if(container)
|
||||
|
||||
@@ -203,9 +203,9 @@
|
||||
var/mob/living/silicon/robot/R
|
||||
switch(borg_to_spawn)
|
||||
if("Medical")
|
||||
R = new /mob/living/silicon/robot/syndicate/medical(T)
|
||||
R = new /mob/living/silicon/robot/modules/syndicate/medical(T)
|
||||
else
|
||||
R = new /mob/living/silicon/robot/syndicate(T) //Assault borg by default
|
||||
R = new /mob/living/silicon/robot/modules/syndicate(T) //Assault borg by default
|
||||
|
||||
var/brainfirstname = pick(GLOB.first_names_male)
|
||||
if(prob(50))
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
if(!placed)
|
||||
if(manualplace_min_time && world.time >= manualplace_min_time)
|
||||
to_chat(src, "<b><span class='big'><font color=\"#EE4000\">You may now place your blob core.</font></span></b>")
|
||||
to_chat(src, "<span class='big'><font color=\"#EE4000\">You will automatically place your blob core in [round((autoplace_max_time - world.time)/600, 0.5)] minutes.</font></span>")
|
||||
to_chat(src, "<span class='big'><font color=\"#EE4000\">You will automatically place your blob core in [DisplayTimeText(autoplace_max_time - world.time)].</font></span>")
|
||||
manualplace_min_time = 0
|
||||
if(autoplace_max_time && world.time >= autoplace_max_time)
|
||||
place_blob_core(base_point_rate, 1)
|
||||
|
||||
@@ -365,5 +365,5 @@
|
||||
to_chat(src, "<b>Shortcuts:</b> Click = Expand Blob <b>|</b> Middle Mouse Click = Rally Spores <b>|</b> Ctrl Click = Create Shield Blob <b>|</b> Alt Click = Remove Blob")
|
||||
to_chat(src, "Attempting to talk will send a message to all other overminds, allowing you to coordinate with them.")
|
||||
if(!placed && autoplace_max_time <= world.time)
|
||||
to_chat(src, "<span class='big'><font color=\"#EE4000\">You will automatically place your blob core in [round((autoplace_max_time - world.time)/600, 0.5)] minutes.</font></span>")
|
||||
to_chat(src, "<span class='big'><font color=\"#EE4000\">You will automatically place your blob core in [DisplayTimeText(autoplace_max_time - world.time)].</font></span>")
|
||||
to_chat(src, "<span class='big'><font color=\"#EE4000\">You [manualplace_min_time ? "will be able to":"can"] manually place your blob core by pressing the Place Blob Core button in the bottom right corner of the screen.</font></span>")
|
||||
|
||||
@@ -8,12 +8,9 @@ Imprisoned within a massive construct known as the Celestial Derelict - or Reebe
|
||||
Ratvar, unable to act in the mortal plane, seeks to return and forms covenants with mortals in order to bolster his influence.
|
||||
Due to his mechanical nature, Ratvar is also capable of influencing silicon-based lifeforms, unlike Nar-Sie, who can only influence natural life.
|
||||
|
||||
This is a team-based gamemode, and the team's objective is shared by all cultists. It can include summoning Ratvar, escaping on the shuttle, or converting the AI and its cyborgs.
|
||||
This is a team-based gamemode, and the team's objective is shared by all cultists. Their goal is to defend an object called the Ark on a separate z-level.
|
||||
|
||||
The clockwork version of an arcane tome is the clockwork slab.
|
||||
While it can perform certain actions, it consumes a resource called components.
|
||||
Components, which are fallen fragments of Ratvar's body as he rusts in Reebe, are powerful and have various effects.
|
||||
Game-wise, clockwork slabs will generate components over time, with more powerful components being slower.
|
||||
|
||||
This file's folder contains:
|
||||
clock_cult.dm: Core gamemode files.
|
||||
@@ -36,8 +33,8 @@ Credit where due:
|
||||
2. SkowronX from /vg/ for MANY of the assets
|
||||
3. FuryMcFlurry from /vg/ for many of the assets
|
||||
4. PJB3005 from /vg/ for the failed continuation PR
|
||||
5. Xhuis from /tg/ for coding the basic gamemode as it is today
|
||||
6. ChangelingRain from /tg/ for maintaining the gamemode for months after its release
|
||||
5. Xhuis from /tg/ for coding the first iteration of the mode, and the new, reworked version
|
||||
6. ChangelingRain from /tg/ for maintaining the gamemode for months after its release prior to its rework
|
||||
|
||||
*/
|
||||
|
||||
@@ -88,7 +85,7 @@ Credit where due:
|
||||
|
||||
/datum/game_mode
|
||||
var/list/servants_of_ratvar = list() //The Enlightened servants of Ratvar
|
||||
var/clockwork_explanation = "Construct a Gateway to the Celestial Derelict and free Ratvar." //The description of the current objective
|
||||
var/clockwork_explanation = "Defend the Ark of the Clockwork Justiciar and free Ratvar." //The description of the current objective
|
||||
|
||||
/datum/game_mode/clockwork_cult
|
||||
name = "clockwork cult"
|
||||
@@ -103,30 +100,34 @@ Credit where due:
|
||||
restricted_jobs = list("Chaplain", "Captain")
|
||||
announce_span = "brass"
|
||||
announce_text = "Servants of Ratvar are trying to summon the Justiciar!\n\
|
||||
<span class='brass'>Servants</span>: Take over the station and summon Ratvar.\n\
|
||||
<span class='brass'>Servants</span>: Construct defenses to protect the Ark. Sabotage the station!\n\
|
||||
<span class='notice'>Crew</span>: Stop the servants before they can summon the Clockwork Justiciar."
|
||||
var/servants_to_serve = list()
|
||||
var/roundstart_player_count
|
||||
var/ark_time //In minutes, how long the Ark waits before activation; this is equal to 30 + (number of players / 5) (max 40 mins.)
|
||||
|
||||
/datum/game_mode/clockwork_cult/pre_setup()
|
||||
if(config.protect_roles_from_antagonist)
|
||||
restricted_jobs += protected_jobs
|
||||
if(config.protect_assistant_from_antagonist)
|
||||
restricted_jobs += "Assistant"
|
||||
var/starter_servants = 3 //Guaranteed three servants
|
||||
var/starter_servants = 4 //Guaranteed four servants
|
||||
var/number_players = num_players()
|
||||
roundstart_player_count = number_players
|
||||
if(number_players > 30) //plus one servant for every additional 15 players
|
||||
if(number_players > 30) //plus one servant for every additional 10 players above 30
|
||||
number_players -= 30
|
||||
starter_servants += round(number_players/15)
|
||||
starter_servants += round(number_players / 10)
|
||||
starter_servants = min(starter_servants, 8) //max 8 servants (that sould only happen with a ton of players)
|
||||
while(starter_servants)
|
||||
var/datum/mind/servant = pick(antag_candidates)
|
||||
servants_to_serve += servant
|
||||
antag_candidates -= servant
|
||||
modePlayer += servant
|
||||
servant.assigned_role = "Servant of Ratvar"
|
||||
servant.special_role = "Servant of Ratvar"
|
||||
servant.restricted_roles = restricted_jobs
|
||||
starter_servants--
|
||||
ark_time = 30 + round((roundstart_player_count / 5)) //In minutes, how long the Ark will wait before activation
|
||||
ark_time = min(ark_time, 35) //35 minute maximum for the activation timer
|
||||
return 1
|
||||
|
||||
/datum/game_mode/clockwork_cult/post_setup()
|
||||
@@ -134,26 +135,35 @@ Credit where due:
|
||||
var/datum/mind/servant = S
|
||||
log_game("[servant.key] was made an initial servant of Ratvar")
|
||||
var/mob/living/L = servant.current
|
||||
var/turf/T = pick(GLOB.servant_spawns)
|
||||
L.forceMove(T)
|
||||
GLOB.servant_spawns -= T
|
||||
greet_servant(L)
|
||||
equip_servant(L)
|
||||
add_servant_of_ratvar(L, TRUE)
|
||||
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar //that's a mouthful
|
||||
G.initial_activation_delay = ark_time * 60
|
||||
G.seconds_until_activation = ark_time * 60 //60 seconds in a minute * number of minutes
|
||||
..()
|
||||
return 1
|
||||
|
||||
/datum/game_mode/clockwork_cult/proc/greet_servant(mob/M) //Description of their role
|
||||
if(!M)
|
||||
return 0
|
||||
var/greeting_text = "<br><b><span class='large_brass'>You are a servant of Ratvar, the Clockwork Justiciar.</span>\n\
|
||||
Rusting eternally in the Celestial Derelict, Ratvar has formed a covenant of mortals, with you as one of its members. As one of the Justiciar's servants, you are to work to the best of your \
|
||||
ability to assist in completion of His agenda. You may not know the specifics of how to do so, but luckily you have a vessel to help you learn.</b>"
|
||||
to_chat(M, greeting_text)
|
||||
to_chat(M, "<span class='bold large_brass'>You are a servant of Ratvar, the Clockwork Justiciar!</span>")
|
||||
to_chat(M, "<span class='brass'>You have approximately <b>[ark_time]</b> minutes until the Ark activates.</span>")
|
||||
to_chat(M, "<span class='brass'>Unlock <b>Script</b> scripture by converting a new servant.</span>")
|
||||
to_chat(M, "<span class='brass'><b>Application</b> scripture will be unlocked halfway until the Ark's activation.</span>")
|
||||
M.playsound_local(get_turf(M), 'sound/ambience/antag/clockcultalr.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
return 1
|
||||
|
||||
/datum/game_mode/proc/equip_servant(mob/living/L) //Grants a clockwork slab to the mob, with one of each component
|
||||
if(!L || !istype(L))
|
||||
/datum/game_mode/proc/equip_servant(mob/living/M) //Grants a clockwork slab to the mob, with one of each component
|
||||
if(!M || !ishuman(M))
|
||||
return FALSE
|
||||
var/obj/item/clockwork/slab/starter/S = new/obj/item/clockwork/slab/starter(null) //start it off in null
|
||||
var/mob/living/carbon/human/L = M
|
||||
L.set_species(/datum/species/human)
|
||||
L.equipOutfit(/datum/outfit/servant_of_ratvar)
|
||||
var/obj/item/clockwork/slab/S = new
|
||||
var/slot = "At your feet"
|
||||
var/list/slots = list("In your left pocket" = slot_l_store, "In your right pocket" = slot_r_store, "In your backpack" = slot_in_backpack, "On your belt" = slot_belt)
|
||||
if(ishuman(L))
|
||||
@@ -165,26 +175,24 @@ Credit where due:
|
||||
if(!S.forceMove(get_turf(L)))
|
||||
qdel(S)
|
||||
if(S && !QDELETED(S))
|
||||
to_chat(L, "<b>[slot] is a link to the halls of Reebe and your master. You may use it to perform many tasks, but also become oriented with the workings of Ratvar and how to best complete your \
|
||||
tasks. This clockwork slab will be instrumental in your triumph. Remember: you can speak discreetly with your fellow servants by using the <span class='brass'>Hierophant Network</span> action button, \
|
||||
and you can find a concise tutorial by using the slab in-hand and selecting Recollection.</b>")
|
||||
to_chat(L, "<i>Alternatively, check out the wiki page at </i><b>https://tgstation13.org/wiki/Clockwork_Cult</b><i>, which contains additional information.</i>")
|
||||
to_chat(L, "<span class='bold large_brass'>There is a paper in your backpack! Read it!</span>")
|
||||
to_chat(L, "<span class='alloy'>[slot] is a <b>clockwork slab</b>, a multipurpose tool used to construct machines and invoke ancient words of power. If this is your first time \
|
||||
as a servant, you can find a concise tutorial in the Recollection category of its interface.</span>")
|
||||
to_chat(L, "<span class='alloy italics'>If you want more information, you can find a wiki link here!</span> https://tgstation13.org/wiki/Clockwork_Cult")
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/game_mode/clockwork_cult/proc/check_clockwork_victory()
|
||||
if(GLOB.clockwork_gateway_activated)
|
||||
SSticker.news_report = CLOCK_PROSELYTIZATION //failure, technically, but we have the station
|
||||
if(GLOB.ratvar_awakens)
|
||||
SSticker.news_report = CLOCK_SUMMON
|
||||
return TRUE
|
||||
if(GLOB.clockwork_gateway_activated || SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
|
||||
SSticker.news_report = CLOCK_SUMMON
|
||||
return TRUE
|
||||
else
|
||||
SSticker.news_report = CULT_FAILURE
|
||||
return FALSE
|
||||
|
||||
/datum/game_mode/clockwork_cult/declare_completion()
|
||||
..()
|
||||
return 0 //Doesn't end until the round does
|
||||
return //Doesn't end until the round does
|
||||
|
||||
/datum/game_mode/clockwork_cult/generate_report()
|
||||
return "We have lost contact with multiple stations in your sector. They have gone dark and do not respond to all transmissions, although they appear intact and the crew's life \
|
||||
@@ -198,21 +206,12 @@ Credit where due:
|
||||
if(istype(SSticker.mode, /datum/game_mode/clockwork_cult)) //Possibly hacky?
|
||||
var/datum/game_mode/clockwork_cult/C = SSticker.mode
|
||||
if(C.check_clockwork_victory())
|
||||
text += "<span class='large_brass'><b>Ratvar's servants have succeeded in fulfilling His goals!</b></span>"
|
||||
text += "<span class='large_brass'><b>Ratvar's servants defended the Ark until its activation!</b></span>"
|
||||
SSticker.mode_result = "win - servants completed their objective (summon ratvar)"
|
||||
else
|
||||
var/half_victory = FALSE
|
||||
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = locate() in GLOB.all_clockwork_objects
|
||||
if(G)
|
||||
half_victory = TRUE
|
||||
if(half_victory)
|
||||
text += "<span class='large_brass'><b>The crew escaped before Ratvar could rise, but the gateway \
|
||||
was successfully constructed!</b></span>"
|
||||
SSticker.mode_result = "halfwin - servants constructed the gateway but their objective was not completed (summon ratvar)"
|
||||
else
|
||||
text += "<span class='userdanger'>Ratvar's servants have failed!</span>"
|
||||
SSticker.mode_result = "loss - servants failed their objective (summon ratvar)"
|
||||
text += "<br><b>The servants' objective was:</b> <br>[CLOCKCULT_OBJECTIVE]"
|
||||
text += "<span class='userdanger'>The Ark was destroyed! Ratvar will rust away for all eternity!</span>"
|
||||
SSticker.mode_result = "loss - servants failed their objective (summon ratvar)"
|
||||
text += "<br><b>The servants' objective was:</b> [CLOCKCULT_OBJECTIVE]."
|
||||
text += "<br>Ratvar's servants had <b>[GLOB.clockwork_caches]</b> Tinkerer's Caches."
|
||||
text += "<br><b>Construction Value(CV)</b> was: <b>[GLOB.clockwork_construction_value]</b>"
|
||||
for(var/i in SSticker.scripture_states)
|
||||
@@ -233,3 +232,66 @@ Credit where due:
|
||||
var/datum/atom_hud/antag/A = GLOB.huds[ANTAG_HUD_CLOCKWORK]
|
||||
A.leave_hud(M.current)
|
||||
set_antag_hud(M.current, null)
|
||||
|
||||
|
||||
|
||||
//Servant of Ratvar outfit
|
||||
/datum/outfit/servant_of_ratvar
|
||||
uniform = /obj/item/clothing/under/chameleon/ratvar
|
||||
shoes = /obj/item/clothing/shoes/workboots
|
||||
back = /obj/item/storage/backpack
|
||||
ears = /obj/item/device/radio/headset
|
||||
gloves = /obj/item/clothing/gloves/color/yellow
|
||||
belt = /obj/item/storage/belt/utility/servant
|
||||
backpack_contents = list(/obj/item/storage/box/engineer = 1, \
|
||||
/obj/item/clockwork/replica_fabricator = 1, /obj/item/stack/tile/brass/fifty = 1, /obj/item/paper/servant_primer = 1)
|
||||
id = /obj/item/card/id
|
||||
|
||||
/datum/outfit/servant_of_ratvar/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
var/obj/item/card/id/W = H.wear_id
|
||||
W.assignment = "Assistant"
|
||||
W.access += ACCESS_MAINT_TUNNELS
|
||||
W.registered_name = H.real_name
|
||||
W.update_label()
|
||||
|
||||
/obj/item/paper/servant_primer
|
||||
name = "The Ark And You: A Primer On Servitude"
|
||||
color = "#DAAA18"
|
||||
info = "<b>DON'T PANIC.</b><br><br>\
|
||||
Here's a quick primer on what you should know here.\
|
||||
<ol>\
|
||||
<li>You're in a place called Reebe right now. The crew can't get here normally.</li>\
|
||||
<li>In the north is your base camp, with supplies, consoles, and the Ark. In the south is an inaccessible area that the crew can walk between \
|
||||
once they arrive (more on that later.) Everything between that space is an open area.</li>\
|
||||
<li>Your job as a servant is to build fortifications and defenses to protect the Ark and your base once the Ark activates. You can do this \
|
||||
however you like, but work with your allies and coordinate your efforts.</li>\
|
||||
<li>Once the Ark activates, the station will be alerted. Portals to Reebe will open up in nearly every room. When they take these portals, \
|
||||
the crewmembers will arrive in the area that you can't access, but can get through it freely - whereas you can't. Treat this as the \"spawn\" of the \
|
||||
crew and defend it accordingly.</li>\
|
||||
</ol>\
|
||||
<hr>\
|
||||
Here is the layout of Reebe, from left to right:\
|
||||
<ul>\
|
||||
<li><b>Dressing Room:</b> Contains clothing, a dresser, and a mirror. There are spare slabs and absconders here.</li>\
|
||||
<li><b>Listening Station:</b> Contains intercoms, a telecomms relay, and a list of frequencies.</li>\
|
||||
<li><b>Ark Chamber:</b> Houses the Ark.</li>\
|
||||
<li><b>Observation Room:</b> Contains five camera observers. These can be used to watch the station through its cameras, as well as to teleport down \
|
||||
to most areas. To do this, use the Warp action while hovering over the tile you want to warp to.</li>\
|
||||
<li><b>Infirmary:</b> Contains sleepers and basic medical supplies for superficial wounds. The sleepers can consume Vitality to heal any occupants. \
|
||||
This room is generally more useful during the preparation phase; when defending the Ark, scripture is more useful.</li>\
|
||||
</ul>\
|
||||
<hr>\
|
||||
<h2>Things that have changed:</h2>\
|
||||
<ul>\
|
||||
<li><b><i>Scripture no longer requires components, and instead uses power.</i></b></li>\
|
||||
<li>Added a <b>5-minute grace period</b> for the crew to prepare for the assault when the Ark activates.</li>\
|
||||
<li>Script and Application scriptures can now be unlocked with enough power.</li>\
|
||||
<li><b>Added the Hateful Manacles scripture</b>, which handcuffs targets!</li>\
|
||||
</ul>\
|
||||
<hr>\
|
||||
<b>Good luck!</b>"
|
||||
|
||||
/obj/item/paper/servant_primer/examine(mob/user)
|
||||
if(!is_servant_of_ratvar(user) && !isobserver(user))
|
||||
to_chat(user, "<span class='danger'>You can't understand any of the words on [src].</span>")
|
||||
..()
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
//These spawn across the station when the Ark activates. Anyone can walk through one to teleport to Reebe.
|
||||
/obj/effect/clockwork/city_of_cogs_rift
|
||||
name = "celestial rift"
|
||||
desc = "A stable bluespace rip. You're not sure it where leads."
|
||||
clockwork_desc = "A one-way rift to the City of Cogs. Because it's linked to the Ark, it can't be closed."
|
||||
icon_state = "city_of_cogs_rift"
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
density = TRUE
|
||||
light_range = 2
|
||||
light_power = 3
|
||||
light_color = "#6A4D2F"
|
||||
|
||||
/obj/effect/clockwork/city_of_cogs_rift/Initialize()
|
||||
. = ..()
|
||||
visible_message("<span class='warning'>The air above [loc] shimmers and pops as a [name] forms there!</span>")
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(M.z == z)
|
||||
if(get_dist(src, M) >= 7)
|
||||
M.playsound_local(src, 'sound/magic/blink.ogg', 10, FALSE, falloff = 10)
|
||||
else
|
||||
M.playsound_local(src, 'sound/magic/blink.ogg', 50, FALSE)
|
||||
|
||||
/obj/effect/clockwork/city_of_cogs_rift/Destroy()
|
||||
visible_message("<span class='warning'>[src] cracks as it destabilizes and breaks apart!</span>")
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/city_of_cogs_rift/attackby(obj/item/I, mob/living/user, params)
|
||||
if(istype(I, /obj/item/nullrod))
|
||||
to_chat(user, "<span class='warning'>Your [I.name] seems to have no effect on [src]!</span>")
|
||||
return
|
||||
. = ..()
|
||||
|
||||
/obj/effect/clockwork/city_of_cogs_rift/attack_hand(atom/movable/AM)
|
||||
beckon(AM)
|
||||
|
||||
/obj/effect/clockwork/city_of_cogs_rift/CollidedWith(atom/movable/AM)
|
||||
if(!QDELETED(AM))
|
||||
beckon(AM)
|
||||
|
||||
/obj/effect/clockwork/city_of_cogs_rift/proc/beckon(atom/movable/AM)
|
||||
AM.visible_message("<span class='danger'>[AM] passes through [src]!</span>", ignore_mob = AM)
|
||||
AM.forceMove(pick(!is_servant_of_ratvar(AM) ? GLOB.city_of_cogs_spawns : GLOB.servant_spawns))
|
||||
AM.visible_message("<span class='danger'>[AM] materializes from the air!</span>", \
|
||||
"<span class='boldannounce'>You pass through [src] and appear [is_servant_of_ratvar(AM) ? "back at the City of Cogs" : "somewhere unfamiliar. Looks like it was a one-way trip.."].</span>")
|
||||
do_sparks(5, TRUE, src)
|
||||
do_sparks(5, TRUE, AM)
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
L.overlay_fullscreen("flash", /obj/screen/fullscreen/flash/static)
|
||||
L.clear_fullscreen("flash", 5)
|
||||
@@ -11,21 +11,11 @@
|
||||
var/stat_affected = CONSCIOUS
|
||||
var/sigil_name = "Sigil"
|
||||
var/resist_string = "glows blinding white" //string for when a null rod blocks its effects, "glows [resist_string]"
|
||||
var/list/component_refund = list()
|
||||
|
||||
/obj/effect/clockwork/sigil/attackby(obj/item/I, mob/living/user, params)
|
||||
if(is_servant_of_ratvar(user))
|
||||
if(istype(I, /obj/item/clockwork/slab))
|
||||
user.visible_message("<span class='warning'>[user] starts to dispel [src]...</span>", "<span class='danger'>You start to dispel [src]...</span>")
|
||||
if(do_after(user, 20, target = src))
|
||||
user.visible_message("<span class='warning'>[user] dispels [src]!</span>", "<span class='danger'>You dispel [src]!</span>")
|
||||
for(var/i in component_refund)
|
||||
if(component_refund[i])
|
||||
for(var/r in 1 to component_refund[i])
|
||||
generate_cache_component(i, src)
|
||||
qdel(src)
|
||||
return 1
|
||||
else if(I.force)
|
||||
if(I.force)
|
||||
if(is_servant_of_ratvar(user) && user.a_intent != INTENT_HARM)
|
||||
return ..()
|
||||
user.visible_message("<span class='warning'>[user] scatters [src] with [I]!</span>", "<span class='danger'>You scatter [src] with [I]!</span>")
|
||||
qdel(src)
|
||||
return 1
|
||||
@@ -35,7 +25,9 @@
|
||||
return //you can't tk stomp sigils, but you can hit them with something
|
||||
|
||||
/obj/effect/clockwork/sigil/attack_hand(mob/user)
|
||||
if(iscarbon(user) && !user.stat && !is_servant_of_ratvar(user))
|
||||
if(iscarbon(user) && !user.stat)
|
||||
if(is_servant_of_ratvar(user) && user.a_intent != INTENT_HARM)
|
||||
return ..()
|
||||
user.visible_message("<span class='warning'>[user] stamps out [src]!</span>", "<span class='danger'>You stomp on [src], scattering it into thousands of particles.</span>")
|
||||
qdel(src)
|
||||
return 1
|
||||
@@ -75,7 +67,6 @@
|
||||
light_power = 1
|
||||
light_color = "#FAE48C"
|
||||
sigil_name = "Sigil of Transgression"
|
||||
component_refund = list(HIEROPHANT_ANSIBLE = 1)
|
||||
|
||||
/obj/effect/clockwork/sigil/transgression/sigil_effects(mob/living/L)
|
||||
var/target_flashed = L.flash_act()
|
||||
@@ -85,10 +76,11 @@
|
||||
if(iscultist(L))
|
||||
to_chat(L, "<span class='heavy_brass'>\"Watch your step, wretch.\"</span>")
|
||||
L.adjustBruteLoss(10)
|
||||
L.Knockdown(140, FALSE)
|
||||
L.Knockdown(80, FALSE)
|
||||
L.visible_message("<span class='warning'>[src] appears around [L] in a burst of light!</span>", \
|
||||
"<span class='userdanger'>[target_flashed ? "An unseen force":"The glowing sigil around you"] holds you in place!</span>")
|
||||
L.Stun(100)
|
||||
L.Stun(40)
|
||||
L.apply_status_effect(STATUS_EFFECT_BELLIGERENT)
|
||||
new /obj/effect/temp_visual/ratvar/sigil/transgression(get_turf(src))
|
||||
qdel(src)
|
||||
|
||||
@@ -107,18 +99,23 @@
|
||||
light_color = "#FAE48C"
|
||||
stat_affected = UNCONSCIOUS
|
||||
resist_string = "glows faintly yellow"
|
||||
sigil_name = "Sigil of Submission"
|
||||
component_refund = list(GEIS_CAPACITOR = 1)
|
||||
var/convert_time = 80
|
||||
var/delete_on_finish = TRUE
|
||||
sigil_name = "Sigil of Submission"
|
||||
var/glow_type = /obj/effect/temp_visual/ratvar/sigil/submission
|
||||
|
||||
/obj/effect/clockwork/sigil/submission/sigil_effects(mob/living/L)
|
||||
if(istype(L.buckled, /obj/structure/destructible/clockwork/geis_binding))
|
||||
if(is_servant_of_ratvar(L.pulledby))
|
||||
L.pulledby.stop_pulling()
|
||||
if(is_servant_of_ratvar(L.buckled.pulledby))
|
||||
L.buckled.pulledby.stop_pulling()
|
||||
var/turf/T = get_turf(src)
|
||||
var/has_sigil = FALSE
|
||||
var/has_servant = FALSE
|
||||
if(locate(/obj/effect/clockwork/sigil/transgression) in T)
|
||||
has_sigil = TRUE
|
||||
for(var/mob/living/M in range(3, src))
|
||||
if(is_servant_of_ratvar(M) && !M.stat)
|
||||
has_servant = TRUE
|
||||
if(!has_sigil && !has_servant)
|
||||
visible_message("<span class='danger'>[src] strains into a gentle violet color, but quietly fades...</span>")
|
||||
return
|
||||
L.visible_message("<span class='warning'>[src] begins to glow a piercing magenta!</span>", "<span class='sevtug'>You feel something start to invade your mind...</span>")
|
||||
var/oldcolor = color
|
||||
animate(src, color = "#AF0AAF", time = convert_time, flags = ANIMATION_END_NOW)
|
||||
@@ -127,10 +124,10 @@
|
||||
glow = new glow_type(get_turf(src))
|
||||
animate(glow, alpha = 255, time = convert_time)
|
||||
var/I = 0
|
||||
while(I < convert_time && !QDELETED(L) && get_turf(L) == get_turf(src))
|
||||
while(I < convert_time && get_turf(L) == get_turf(src))
|
||||
I++
|
||||
sleep(1)
|
||||
if(QDELETED(L) || get_turf(L) != get_turf(src))
|
||||
if(get_turf(L) != get_turf(src))
|
||||
if(glow)
|
||||
qdel(glow)
|
||||
animate(src, color = oldcolor, time = 20, flags = ANIMATION_END_NOW)
|
||||
@@ -139,6 +136,9 @@
|
||||
return
|
||||
if(is_eligible_servant(L))
|
||||
to_chat(L, "<span class='heavy_brass'>\"You belong to me now.\"</span>")
|
||||
if(!GLOB.application_scripture_unlocked)
|
||||
GLOB.application_scripture_unlocked = TRUE
|
||||
hierophant_message("<span class='large_brass bold'>With the conversion of a new servant the Ark's power grows. Application scriptures are now available.</span>")
|
||||
if(add_servant_of_ratvar(L))
|
||||
L.log_message("<font color=#BE8700>Conversion was done with a [sigil_name].</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
L.Knockdown(50) //Completely defenseless for five seconds - mainly to give them time to read over the information they've just been presented with
|
||||
@@ -160,29 +160,26 @@
|
||||
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
|
||||
|
||||
|
||||
//Sigil of Transmission: Stores power for clockwork machinery, serving as a battery.
|
||||
//Sigil of Transmission: Serves as an access point for powered structures.
|
||||
/obj/effect/clockwork/sigil/transmission
|
||||
name = "suspicious sigil"
|
||||
desc = "A glowing orange sigil. The air around it feels staticky."
|
||||
clockwork_desc = "A sigil that serves as power generation and a battery for clockwork structures."
|
||||
clockwork_desc = "A sigil that serves as power generation and a battery for clockwork structures, linked to all other sigils of its type."
|
||||
icon_state = "sigiltransmission"
|
||||
alpha = 50
|
||||
color = "#EC8A2D"
|
||||
light_color = "#EC8A2D"
|
||||
resist_string = "glows faintly"
|
||||
sigil_name = "Sigil of Transmission"
|
||||
component_refund = list(HIEROPHANT_ANSIBLE = 1)
|
||||
affects_servants = TRUE
|
||||
var/power_charge = 0 //starts with no power
|
||||
var/drain_range = 14
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/Initialize()
|
||||
. = ..()
|
||||
update_glow()
|
||||
update_icon()
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/ex_act(severity)
|
||||
if(severity == 3)
|
||||
modify_charge(-500)
|
||||
adjust_clockwork_power(500) //Light explosions charge the network!
|
||||
visible_message("<span class='warning'>[src] flares a brilliant orange!</span>")
|
||||
else
|
||||
..()
|
||||
@@ -193,70 +190,26 @@
|
||||
var/structure_number = 0
|
||||
for(var/obj/structure/destructible/clockwork/powered/P in range(SIGIL_ACCESS_RANGE, src))
|
||||
structure_number++
|
||||
to_chat(user, "<span class='[power_charge ? "brass":"alloy"]'>It is storing <b>[GLOB.ratvar_awakens ? "INFINITE</b>":"[DisplayPower(power_charge)]</b> of"] power, \
|
||||
and <b>[structure_number]</b> Clockwork Structure[structure_number == 1 ? " is":"s are"] in range.</span>")
|
||||
to_chat(user, "<span class='brass'>While active, it will gradually drain power from nearby electronics. It is currently [isprocessing ? "active":"disabled"].</span>")
|
||||
to_chat(user, "<span class='[get_clockwork_power() ? "brass":"alloy"]'>It is storing <b>[DisplayPower(get_clockwork_power())]</b> of shared power, \
|
||||
and <b>[structure_number]</b> clockwork structure[structure_number == 1 ? " is":"s are"] in range.</span>")
|
||||
if(iscyborg(user))
|
||||
to_chat(user, "<span class='brass'>You can recharge from the [sigil_name] by crossing it.</span>")
|
||||
else if(!GLOB.ratvar_awakens)
|
||||
to_chat(user, "<span class='brass'>Hitting the [sigil_name] with brass sheets will convert them to power at a rate of <b>1</b> brass sheet to <b>[DisplayPower(POWER_FLOOR)]</b> power.</span>")
|
||||
if(!GLOB.ratvar_awakens)
|
||||
to_chat(user, "<span class='brass'>You can recharge Replica Fabricators from the [sigil_name].</span>")
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/attackby(obj/item/I, mob/living/user, params)
|
||||
if(is_servant_of_ratvar(user) && istype(I, /obj/item/stack/tile/brass) && !GLOB.ratvar_awakens)
|
||||
var/obj/item/stack/tile/brass/B = I
|
||||
user.visible_message("<span class='warning'>[user] places [B] on [src], causing it to disintegrate into glowing orange energy!</span>", \
|
||||
"<span class='brass'>You charge the [sigil_name] with [B], providing it with <b>[DisplayPower(B.amount * POWER_FLOOR)]</b> of power.</span>")
|
||||
modify_charge(-(B.amount * POWER_FLOOR))
|
||||
playsound(src, 'sound/effects/light_flicker.ogg', (B.amount * POWER_FLOOR) * 0.01, 1)
|
||||
qdel(B)
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/attack_ai(mob/user)
|
||||
if(is_servant_of_ratvar(user))
|
||||
attack_hand(user)
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/attack_hand(mob/user)
|
||||
if(is_servant_of_ratvar(user))
|
||||
visible_message("<span class='notice'>[user] [isprocessing ? "de":""]activates [src].</span>", "<span class='brass'>You [isprocessing ? "de":""]activate the [sigil_name].</span>")
|
||||
if(isprocessing)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
else
|
||||
START_PROCESSING(SSobj, src)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/sigil_effects(mob/living/L)
|
||||
if(is_servant_of_ratvar(L))
|
||||
if(iscyborg(L))
|
||||
charge_cyborg(L)
|
||||
else if(power_charge)
|
||||
else if(get_clockwork_power())
|
||||
to_chat(L, "<span class='brass'>You feel a slight, static shock.</span>")
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/process()
|
||||
var/power_drained = 0
|
||||
|
||||
for(var/t in spiral_range_turfs(drain_range, src))
|
||||
var/turf/T = t
|
||||
for(var/M in T)
|
||||
var/atom/movable/A = M
|
||||
power_drained += A.power_drain(TRUE)
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
modify_charge(-Floor(power_drained, MIN_CLOCKCULT_POWER))
|
||||
new /obj/effect/temp_visual/ratvar/sigil/transmission(loc, 1 + (power_drained * 0.0035))
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/proc/charge_cyborg(mob/living/silicon/robot/cyborg)
|
||||
if(!cyborg_checks(cyborg))
|
||||
return
|
||||
to_chat(cyborg, "<span class='brass'>You start to charge from the [sigil_name]...</span>")
|
||||
if(!do_after(cyborg, 50, target = src, extra_checks = CALLBACK(src, .proc/cyborg_checks, cyborg, TRUE)))
|
||||
return
|
||||
var/giving_power = min(Floor(cyborg.cell.maxcharge - cyborg.cell.charge, MIN_CLOCKCULT_POWER), power_charge) //give the borg either all our power or their missing power floored to MIN_CLOCKCULT_POWER
|
||||
if(modify_charge(giving_power))
|
||||
var/giving_power = min(Floor(cyborg.cell.maxcharge - cyborg.cell.charge, MIN_CLOCKCULT_POWER), get_clockwork_power()) //give the borg either all our power or their missing power floored to MIN_CLOCKCULT_POWER
|
||||
if(adjust_clockwork_power(-giving_power))
|
||||
cyborg.visible_message("<span class='warning'>[cyborg] glows a brilliant orange!</span>")
|
||||
var/previous_color = cyborg.color
|
||||
cyborg.color = list("#EC8A2D", "#EC8A2D", "#EC8A2D", rgb(0,0,0))
|
||||
@@ -269,9 +222,9 @@
|
||||
if(!silent)
|
||||
to_chat(cyborg, "<span class='warning'>You have no cell!</span>")
|
||||
return FALSE
|
||||
if(!power_charge)
|
||||
if(!get_clockwork_power())
|
||||
if(!silent)
|
||||
to_chat(cyborg, "<span class='warning'>The [sigil_name] has no stored power!</span>")
|
||||
to_chat(cyborg, "<span class='warning'>There is no power available across sigils!</span>")
|
||||
return FALSE
|
||||
if(cyborg.cell.charge > cyborg.cell.maxcharge - MIN_CLOCKCULT_POWER)
|
||||
if(!silent)
|
||||
@@ -283,25 +236,15 @@
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/proc/modify_charge(amount)
|
||||
if(GLOB.ratvar_awakens)
|
||||
update_glow()
|
||||
return TRUE
|
||||
if(power_charge - amount < 0)
|
||||
return FALSE
|
||||
power_charge -= amount
|
||||
update_glow()
|
||||
return TRUE
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/proc/update_glow()
|
||||
/obj/effect/clockwork/sigil/transmission/update_icon()
|
||||
if(GLOB.ratvar_awakens)
|
||||
alpha = 255
|
||||
else
|
||||
alpha = min(initial(alpha) + power_charge*0.02, 255)
|
||||
var/power_charge = get_clockwork_power()
|
||||
alpha = min(initial(alpha) + power_charge * 0.02, 255)
|
||||
if(!power_charge)
|
||||
set_light(0)
|
||||
else
|
||||
set_light(max(alpha*0.02, 1.4), max(alpha*0.01, 0.1))
|
||||
set_light(max(alpha * 0.02, 1.4), max(alpha * 0.01, 0.1))
|
||||
|
||||
//Vitality Matrix: Drains health from non-servants to heal or even revive servants.
|
||||
/obj/effect/clockwork/sigil/vitality
|
||||
@@ -316,7 +259,6 @@
|
||||
stat_affected = DEAD
|
||||
resist_string = "glows shimmering yellow"
|
||||
sigil_name = "Vitality Matrix"
|
||||
component_refund = list(VANGUARD_COGWHEEL = 1)
|
||||
var/revive_cost = 150
|
||||
var/sigil_active = FALSE
|
||||
var/animation_number = 3 //each cycle increments this by 1, at 4 it produces an animation and resets
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
//Marks the point at which "no man's land" begins on Reebe. Servants can't pass beyond this point in any way.
|
||||
/obj/effect/clockwork/servant_blocker
|
||||
name = "glowing arrow"
|
||||
desc = "A faintly glowing image of an arrow on the ground. Convenient!"
|
||||
icon_state = "servant_blocker"
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
density = TRUE
|
||||
|
||||
/obj/effect/clockwork/servant_blocker/Destroy(force)
|
||||
if(!force)
|
||||
return
|
||||
. = ..()
|
||||
|
||||
/obj/effect/clockwork/servant_blocker/CanPass(atom/movable/M, turf/target)
|
||||
var/list/target_contents = M.GetAllContents() + M
|
||||
for(var/mob/living/L in target_contents)
|
||||
if(is_servant_of_ratvar(L) && get_dir(M, src) != dir) //Unless we're on the side the arrow is pointing directly away from, no-go
|
||||
to_chat(L, "<span class='danger'>The space beyond here can't be accessed by you or other servants.</span>")
|
||||
return
|
||||
return TRUE
|
||||
@@ -207,7 +207,7 @@
|
||||
time_duration = round(time_duration * (2 * efficiency), 1)
|
||||
CO.active = TRUE //you'd be active in a second but you should update immediately
|
||||
invoker.visible_message("<span class='warning'>The air in front of [invoker] ripples before suddenly tearing open!</span>", \
|
||||
"<span class='brass'>With a word, you rip open a [two_way ? "two-way":"one-way"] rift to [input_target_key]. It will last for [time_duration / 10] seconds and has [gateway_uses] use[gateway_uses > 1 ? "s" : ""].</span>")
|
||||
"<span class='brass'>With a word, you rip open a [two_way ? "two-way":"one-way"] rift to [input_target_key]. It will last for [DisplayTimeText(time_duration)] and has [gateway_uses] use[gateway_uses > 1 ? "s" : ""].</span>")
|
||||
var/obj/effect/clockwork/spatial_gateway/S1 = new(issrcobelisk ? get_turf(src) : get_step(get_turf(invoker), invoker.dir))
|
||||
var/obj/effect/clockwork/spatial_gateway/S2 = new(istargetobelisk ? get_turf(target) : get_step(get_turf(target), target.dir))
|
||||
|
||||
|
||||
@@ -1,93 +1,3 @@
|
||||
//generates a component in the global component cache, either random based on lowest or a specific component
|
||||
/proc/generate_cache_component(specific_component_id, atom/A)
|
||||
if(!specific_component_id)
|
||||
specific_component_id = get_weighted_component_id()
|
||||
GLOB.clockwork_component_cache[specific_component_id]++
|
||||
if(A)
|
||||
var/component_animation_type = get_component_animation_type(specific_component_id)
|
||||
new component_animation_type(get_turf(A))
|
||||
update_slab_info()
|
||||
return specific_component_id
|
||||
|
||||
//returns a chosen component id based on the lowest amount of that component in the global cache, the global cache plus the slab if there are caches, or the slab if there are no caches.
|
||||
/proc/get_weighted_component_id(obj/item/clockwork/slab/storage_slab)
|
||||
. = list()
|
||||
if(storage_slab)
|
||||
if(GLOB.clockwork_caches)
|
||||
for(var/i in GLOB.clockwork_component_cache)
|
||||
.[i] = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*(GLOB.clockwork_component_cache[i] + storage_slab.stored_components[i]), 1)
|
||||
else
|
||||
for(var/i in GLOB.clockwork_component_cache)
|
||||
.[i] = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*storage_slab.stored_components[i], 1)
|
||||
else
|
||||
for(var/i in GLOB.clockwork_component_cache)
|
||||
.[i] = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*GLOB.clockwork_component_cache[i], 1)
|
||||
for(var/obj/structure/destructible/clockwork/massive/celestial_gateway/G in GLOB.all_clockwork_objects)
|
||||
if(G.still_needs_components())
|
||||
for(var/i in G.required_components)
|
||||
if(!G.required_components[i])
|
||||
. -= i
|
||||
break
|
||||
. = pickweight(.)
|
||||
|
||||
//returns a component name from a component id
|
||||
/proc/get_component_name(id)
|
||||
switch(id)
|
||||
if(BELLIGERENT_EYE)
|
||||
return "Belligerent Eye"
|
||||
if(VANGUARD_COGWHEEL)
|
||||
return "Vanguard Cogwheel"
|
||||
if(GEIS_CAPACITOR)
|
||||
return "Geis Capacitor"
|
||||
if(REPLICANT_ALLOY)
|
||||
return "Replicant Alloy"
|
||||
if(HIEROPHANT_ANSIBLE)
|
||||
return "Hierophant Ansible"
|
||||
else
|
||||
return null
|
||||
|
||||
//returns a component acronym from a component id
|
||||
/proc/get_component_acronym(id)
|
||||
switch(id)
|
||||
if(BELLIGERENT_EYE)
|
||||
return "BE"
|
||||
if(VANGUARD_COGWHEEL)
|
||||
return "VC"
|
||||
if(GEIS_CAPACITOR)
|
||||
return "GC"
|
||||
if(REPLICANT_ALLOY)
|
||||
return "RA"
|
||||
if(HIEROPHANT_ANSIBLE)
|
||||
return "HA"
|
||||
else
|
||||
return null
|
||||
|
||||
//returns a component icon from a component id
|
||||
/proc/get_component_icon(id)
|
||||
var/static/list/tgui_component_icons = list(
|
||||
BELLIGERENT_EYE = icon2base64(icon('icons/obj/tgui_components.dmi', BELLIGERENT_EYE)),
|
||||
VANGUARD_COGWHEEL = icon2base64(icon('icons/obj/tgui_components.dmi', VANGUARD_COGWHEEL)),
|
||||
GEIS_CAPACITOR = icon2base64(icon('icons/obj/tgui_components.dmi', GEIS_CAPACITOR)),
|
||||
REPLICANT_ALLOY = icon2base64(icon('icons/obj/tgui_components.dmi', REPLICANT_ALLOY)),
|
||||
HIEROPHANT_ANSIBLE = icon2base64(icon('icons/obj/tgui_components.dmi', HIEROPHANT_ANSIBLE)))
|
||||
return "<img style='width:14px; height:14px' src='data:image/png;base64,[tgui_component_icons[id]]'/>"
|
||||
|
||||
//returns a component id from a component name
|
||||
/proc/get_component_id(name)
|
||||
switch(name)
|
||||
if("Belligerent Eye")
|
||||
return BELLIGERENT_EYE
|
||||
if("Vanguard Cogwheel")
|
||||
return VANGUARD_COGWHEEL
|
||||
if("Geis Capacitor")
|
||||
return GEIS_CAPACITOR
|
||||
if("Replicant Alloy")
|
||||
return REPLICANT_ALLOY
|
||||
if("Hierophant Ansible")
|
||||
return HIEROPHANT_ANSIBLE
|
||||
else
|
||||
return null
|
||||
|
||||
//returns a component spanclass from a component id
|
||||
/proc/get_component_span(id)
|
||||
switch(id)
|
||||
@@ -129,35 +39,3 @@
|
||||
return "#DAAA18"
|
||||
else
|
||||
return "#BE8700"
|
||||
|
||||
//returns a type for a floating component animation from a component id
|
||||
/proc/get_component_animation_type(id)
|
||||
switch(id)
|
||||
if(BELLIGERENT_EYE)
|
||||
return /obj/effect/temp_visual/ratvar/component
|
||||
if(VANGUARD_COGWHEEL)
|
||||
return /obj/effect/temp_visual/ratvar/component/cogwheel
|
||||
if(GEIS_CAPACITOR)
|
||||
return /obj/effect/temp_visual/ratvar/component/capacitor
|
||||
if(REPLICANT_ALLOY)
|
||||
return /obj/effect/temp_visual/ratvar/component/alloy
|
||||
if(HIEROPHANT_ANSIBLE)
|
||||
return /obj/effect/temp_visual/ratvar/component/ansible
|
||||
else
|
||||
return null
|
||||
|
||||
//returns a type for a component from a component id
|
||||
/proc/get_component_type(id)
|
||||
switch(id)
|
||||
if(BELLIGERENT_EYE)
|
||||
return /obj/item/clockwork/component/belligerent_eye
|
||||
if(VANGUARD_COGWHEEL)
|
||||
return /obj/item/clockwork/component/vanguard_cogwheel
|
||||
if(GEIS_CAPACITOR)
|
||||
return /obj/item/clockwork/component/geis_capacitor
|
||||
if(REPLICANT_ALLOY)
|
||||
return /obj/item/clockwork/component/replicant_alloy
|
||||
if(HIEROPHANT_ANSIBLE)
|
||||
return /obj/item/clockwork/component/hierophant_ansible
|
||||
else
|
||||
return null
|
||||
@@ -9,7 +9,7 @@
|
||||
return FALSE
|
||||
|
||||
/atom/proc/consume_visual(obj/item/clockwork/replica_fabricator/fabricator, power_amount)
|
||||
if(fabricator.can_use_power(power_amount))
|
||||
if(get_clockwork_power(power_amount))
|
||||
var/obj/effect/temp_visual/ratvar/beam/itemconsume/B = new /obj/effect/temp_visual/ratvar/beam/itemconsume(get_turf(src))
|
||||
B.pixel_x = pixel_x
|
||||
B.pixel_y = pixel_y
|
||||
@@ -240,7 +240,7 @@
|
||||
extra_checks = CALLBACK(fabricator, /obj/item/clockwork/replica_fabricator.proc/fabricator_repair_checks, repair_values, src, user, TRUE)))
|
||||
break
|
||||
obj_integrity = Clamp(obj_integrity + repair_values["healing_for_cycle"], 0, max_integrity)
|
||||
fabricator.modify_stored_power(-repair_values["power_required"])
|
||||
adjust_clockwork_power(-repair_values["power_required"])
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
|
||||
if(fabricator)
|
||||
@@ -249,28 +249,6 @@
|
||||
user.visible_message("<span class='notice'>[user]'s [fabricator.name] stops covering [src] with glowing orange energy.</span>", \
|
||||
"<span class='alloy'>You finish repairing [src]. It is now at <b>[obj_integrity]/[max_integrity]</b> integrity.</span>")
|
||||
|
||||
//Hitting a sigil of transmission will try to charge from it.
|
||||
/obj/effect/clockwork/sigil/transmission/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
. = TRUE
|
||||
var/list/charge_values = list()
|
||||
if(!fabricator.sigil_charge_checks(charge_values, src, user))
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user]'s [fabricator.name] starts draining glowing orange energy from [src]...</span>", \
|
||||
"<span class='alloy'>You start recharging your [fabricator.name]...</span>")
|
||||
fabricator.recharging = src
|
||||
while(fabricator && user && src)
|
||||
if(!do_after(user, 10, target = src, extra_checks = CALLBACK(fabricator, /obj/item/clockwork/replica_fabricator.proc/sigil_charge_checks, charge_values, src, user, TRUE)))
|
||||
break
|
||||
modify_charge(charge_values["power_gain"])
|
||||
fabricator.modify_stored_power(charge_values["power_gain"])
|
||||
playsound(src, 'sound/effects/light_flicker.ogg', charge_values["power_gain"] * 0.1, 1)
|
||||
|
||||
if(fabricator)
|
||||
fabricator.recharging = null
|
||||
if(user)
|
||||
user.visible_message("<span class='notice'>[user]'s [fabricator.name] stops draining glowing orange energy from [src].</span>", \
|
||||
"<span class='alloy'>You finish recharging your [fabricator.name]. It now contains <b>[DisplayPower(fabricator.get_power())]/[DisplayPower(fabricator.get_max_power())]</b> power.</span>")
|
||||
|
||||
//Fabricator mob heal proc, to avoid as much copypaste as possible.
|
||||
/mob/living/proc/fabricator_heal(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator)
|
||||
var/list/repair_values = list()
|
||||
@@ -284,7 +262,7 @@
|
||||
extra_checks = CALLBACK(fabricator, /obj/item/clockwork/replica_fabricator.proc/fabricator_repair_checks, repair_values, src, user, TRUE)))
|
||||
break
|
||||
fabricator_heal_tick(repair_values["healing_for_cycle"])
|
||||
fabricator.modify_stored_power(-repair_values["power_required"])
|
||||
adjust_clockwork_power(-repair_values["power_required"])
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
|
||||
if(fabricator)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
/datum/action/innate/hierophant
|
||||
name = "Hierophant Network"
|
||||
desc = "Allows you to communicate with other Servants."
|
||||
icon_icon = 'icons/mob/actions/actions_clockcult.dmi'
|
||||
button_icon_state = "hierophant"
|
||||
background_icon_state = "bg_clock"
|
||||
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
|
||||
@@ -43,6 +44,7 @@
|
||||
var/input = stripped_input(usr, "Please enter a message to send to other servants.", "Hierophant Network", "")
|
||||
if(!input || !IsAvailable())
|
||||
return
|
||||
|
||||
if(ishuman(owner))
|
||||
clockwork_say(owner, "[text2ratvar("Servants, hear my words: [input]")]", TRUE)
|
||||
log_talk(owner,"CLOCK:[key_name(owner)] : [input]",LOGSAY)
|
||||
titled_hierophant_message(owner, input, span_for_name, span_for_message, title)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
//Helper procs for clockwork power, used by structures and items and that kind of jazz.
|
||||
|
||||
/proc/get_clockwork_power(amount) //If no amount is provided, returns the clockwork power; otherwise, returns if there's enough power for that amount.
|
||||
return amount ? GLOB.clockwork_power >= amount : GLOB.clockwork_power
|
||||
|
||||
/proc/adjust_clockwork_power(amount) //Adjusts the global clockwork power by this amount (min 0.)
|
||||
if(GLOB.ratvar_approaches)
|
||||
amount *= 0.75 //The herald's beacon reduces power costs by 25% across the board!
|
||||
GLOB.clockwork_power = GLOB.ratvar_awakens ? INFINITY : max(0, GLOB.clockwork_power + amount)
|
||||
for(var/obj/effect/clockwork/sigil/transmission/T in GLOB.all_clockwork_objects)
|
||||
T.update_icon()
|
||||
var/power_overwhelming = GLOB.clockwork_power
|
||||
if(power_overwhelming >= SCRIPT_UNLOCK_THRESHOLD && !GLOB.script_scripture_unlocked)
|
||||
GLOB.script_scripture_unlocked = TRUE
|
||||
hierophant_message("<span class='large_brass bold'>The Ark swells as a key power threshold is reached. Script scriptures are now available.</span>")
|
||||
if(power_overwhelming >= APPLICATION_UNLOCK_THRESHOLD && !GLOB.application_scripture_unlocked)
|
||||
GLOB.application_scripture_unlocked = TRUE
|
||||
hierophant_message("<span class='large_brass bold'>The Ark surges as a key power threshold is reached. Application scriptures are now available.</span>")
|
||||
return TRUE
|
||||
|
||||
/proc/can_access_clockwork_power(atom/movable/access_point, amount) //Returns true if the access point has access to clockwork power (and optionally, a number of watts for it)
|
||||
if(amount && !get_clockwork_power(amount)) //No point in trying if we don't have the power anyway
|
||||
return
|
||||
var/list/possible_conduits = view(5, access_point)
|
||||
return locate(/obj/effect/clockwork/sigil/transmission) in possible_conduits || GLOB.ratvar_awakens
|
||||
@@ -1,39 +1,23 @@
|
||||
//returns a list of scriptures and if they're unlocked or not
|
||||
/proc/scripture_unlock_check()
|
||||
var/servants = 0
|
||||
var/unconverted_ai_exists = get_unconverted_ais()
|
||||
for(var/mob/living/M in GLOB.living_mob_list)
|
||||
if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M)))
|
||||
servants++
|
||||
. = list(SCRIPTURE_DRIVER = TRUE, SCRIPTURE_SCRIPT = FALSE, SCRIPTURE_APPLICATION = FALSE, SCRIPTURE_JUDGEMENT = FALSE)
|
||||
. = list(SCRIPTURE_DRIVER = TRUE, SCRIPTURE_SCRIPT = FALSE, SCRIPTURE_APPLICATION = FALSE)
|
||||
//Drivers: always unlocked
|
||||
.[SCRIPTURE_SCRIPT] = (SSticker.scripture_states[SCRIPTURE_SCRIPT] || \
|
||||
(servants >= SCRIPT_SERVANT_REQ && GLOB.clockwork_caches >= SCRIPT_CACHE_REQ))
|
||||
//Script: SCRIPT_SERVANT_REQ or more non-brain servants and SCRIPT_CACHE_REQ or more clockwork caches
|
||||
.[SCRIPTURE_APPLICATION] = (SSticker.scripture_states[SCRIPTURE_APPLICATION] || \
|
||||
(servants >= APPLICATION_SERVANT_REQ && GLOB.clockwork_caches >= APPLICATION_CACHE_REQ && GLOB.clockwork_construction_value >= APPLICATION_CV_REQ))
|
||||
|
||||
.[SCRIPTURE_SCRIPT] = GLOB.script_scripture_unlocked
|
||||
//Script: Convert a new servant using a sigil of submission.
|
||||
|
||||
.[SCRIPTURE_APPLICATION] = GLOB.application_scripture_unlocked
|
||||
//Application: APPLICATION_SERVANT_REQ or more non-brain servants, APPLICATION_CACHE_REQ or more clockwork caches, and at least APPLICATION_CV_REQ CV
|
||||
.[SCRIPTURE_JUDGEMENT] = (SSticker.scripture_states[SCRIPTURE_JUDGEMENT] || \
|
||||
(servants >= JUDGEMENT_SERVANT_REQ && GLOB.clockwork_caches >= JUDGEMENT_CACHE_REQ && GLOB.clockwork_construction_value >= JUDGEMENT_CV_REQ && !unconverted_ai_exists))
|
||||
//Judgement: JUDGEMENT_SERVANT_REQ or more non-brain servants, JUDGEMENT_CACHE_REQ or more clockwork caches, at least JUDGEMENT_CV_REQ CV, and there are no living, non-servant ais
|
||||
|
||||
//reports to servants when scripture is locked or unlocked
|
||||
/proc/scripture_unlock_alert(list/previous_states)
|
||||
. = scripture_unlock_check()
|
||||
for(var/i in .)
|
||||
if(.[i] != previous_states[i])
|
||||
hierophant_message("<span class='large_brass'><i>Hierophant Network:</i> <b>[i] Scripture has been [.[i] ? "un":""]locked.</b></span>") //maybe admins fucked with scripture states?
|
||||
update_slab_info()
|
||||
|
||||
/proc/get_unconverted_ais()
|
||||
. = 0
|
||||
for(var/ai in GLOB.ai_list)
|
||||
var/mob/living/silicon/ai/AI = ai
|
||||
if(AI.deployed_shell && is_servant_of_ratvar(AI.deployed_shell))
|
||||
continue
|
||||
if(is_servant_of_ratvar(AI) || !isturf(AI.loc) || !(AI.z in GLOB.station_z_levels) || AI.stat == DEAD)
|
||||
continue
|
||||
.++
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(is_servant_of_ratvar(M) || isobserver(M))
|
||||
M.playsound_local(M, 'sound/magic/clockwork/scripture_tier_up.ogg', 50, FALSE, pressure_affected = FALSE)
|
||||
|
||||
/proc/update_slab_info(obj/item/clockwork/slab/set_slab)
|
||||
generate_all_scripture()
|
||||
|
||||
@@ -21,70 +21,58 @@
|
||||
remove_ranged_ability()
|
||||
return TRUE
|
||||
|
||||
//For the Geis scripture; binds a target to convert.
|
||||
/obj/effect/proc_holder/slab/geis
|
||||
ranged_mousepointer = 'icons/effects/geis_target.dmi'
|
||||
//For the Hateful Manacles scripture; applies replicant handcuffs to the target.
|
||||
/obj/effect/proc_holder/slab/hateful_manacles
|
||||
|
||||
/obj/effect/proc_holder/slab/geis/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
/obj/effect/proc_holder/slab/hateful_manacles/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
var/turf/T = ranged_ability_user.loc
|
||||
if(!isturf(T))
|
||||
return TRUE
|
||||
|
||||
var/target_is_binding = istype(target, /obj/structure/destructible/clockwork/geis_binding)
|
||||
if(iscarbon(target) && target.Adjacent(ranged_ability_user))
|
||||
var/mob/living/carbon/L = target
|
||||
if(is_servant_of_ratvar(L))
|
||||
to_chat(ranged_ability_user, "<span class='neovgre'>\"They're a servant.\"</span>")
|
||||
return TRUE
|
||||
else if(L.stat)
|
||||
to_chat(ranged_ability_user, "<span class='neovgre'>\"There is use in shackling the dead, but for examples.\"</span>")
|
||||
return TRUE
|
||||
else if(L.handcuffed)
|
||||
to_chat(ranged_ability_user, "<span class='neovgre'>\"They are already helpless, no?\"</span>")
|
||||
return TRUE
|
||||
|
||||
if((target_is_binding || isliving(target)) && ranged_ability_user.Adjacent(target))
|
||||
if(target_is_binding)
|
||||
var/obj/structure/destructible/clockwork/geis_binding/GB = target
|
||||
GB.repair_and_interrupt()
|
||||
for(var/m in GB.buckled_mobs)
|
||||
if(m)
|
||||
add_logs(ranged_ability_user, m, "rebound with Geis")
|
||||
successful = TRUE
|
||||
playsound(loc, 'sound/weapons/handcuffs.ogg', 30, TRUE)
|
||||
ranged_ability_user.visible_message("<span class='danger'>[ranged_ability_user] begins forming manacles around [L]'s wrists!</span>", \
|
||||
"<span class='neovgre_small'>You begin shaping replicant alloy into manacles around [L]'s wrists...</span>")
|
||||
to_chat(L, "<span class='userdanger'>[ranged_ability_user] begins forming manacles around your wrists!</span>")
|
||||
if(do_mob(ranged_ability_user, L, 30))
|
||||
if(!L.handcuffed)
|
||||
L.handcuffed = new/obj/item/restraints/handcuffs/clockwork(L)
|
||||
L.update_handcuffed()
|
||||
to_chat(ranged_ability_user, "<span class='neovgre_small'>You shackle [L].</span>")
|
||||
add_logs(ranged_ability_user, L, "handcuffed")
|
||||
else
|
||||
var/mob/living/L = target
|
||||
if(L.null_rod_check())
|
||||
to_chat(ranged_ability_user, "<span class='sevtug'>\"A void weapon? Really, you expect me to be able to do anything?\"</span>")
|
||||
return TRUE
|
||||
if(is_servant_of_ratvar(L))
|
||||
if(L != ranged_ability_user)
|
||||
to_chat(ranged_ability_user, "<span class='sevtug'>\"[L.p_they(TRUE)] already serve[L.p_s()] Ratvar. [text2ratvar("Perhaps [ranged_ability_user.p_theyre()] into bondage?")]\"</span>")
|
||||
return TRUE
|
||||
if(L.stat == DEAD)
|
||||
to_chat(ranged_ability_user, "<span class='sevtug'>\"[L.p_theyre(TRUE)] dead, idiot.\"</span>")
|
||||
return TRUE
|
||||
to_chat(ranged_ability_user, "<span class='warning'>You fail to shackle [L].</span>")
|
||||
|
||||
if(istype(L.buckled, /obj/structure/destructible/clockwork/geis_binding)) //if they're already bound, just stun them
|
||||
var/obj/structure/destructible/clockwork/geis_binding/GB = L.buckled
|
||||
GB.repair_and_interrupt()
|
||||
add_logs(ranged_ability_user, L, "rebound with Geis")
|
||||
successful = TRUE
|
||||
else
|
||||
clockwork_say(ranged_ability_user, text2ratvar("Be bound, heathen!"))
|
||||
add_logs(ranged_ability_user, L, "bound with Geis")
|
||||
playsound(target, 'sound/magic/blink.ogg', 50, TRUE, -4, frequency = 0.5)
|
||||
if(slab.speed_multiplier >= 0.5) //excuse my debug...
|
||||
ranged_ability_user.notransform = TRUE
|
||||
addtimer(CALLBACK(src, .proc/reset_user_notransform, ranged_ability_user), 4) //stop us moving for a little bit so we don't break the binding immediately
|
||||
if(L.buckled)
|
||||
L.buckled.unbuckle_mob(target, TRUE)
|
||||
var/obj/structure/destructible/clockwork/geis_binding/binding = new(get_turf(target))
|
||||
binding.setDir(target.dir)
|
||||
binding.buckle_mob(target, TRUE)
|
||||
ranged_ability_user.start_pulling(binding)
|
||||
ranged_ability_user.apply_status_effect(STATUS_EFFECT_GEISTRACKER, binding)
|
||||
successful = TRUE
|
||||
successful = TRUE
|
||||
|
||||
remove_ranged_ability()
|
||||
else
|
||||
..()
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/slab/geis/proc/reset_user_notransform(mob/living/user)
|
||||
if(user)
|
||||
user.notransform = FALSE
|
||||
/obj/item/restraints/handcuffs/clockwork
|
||||
name = "replicant manacles"
|
||||
desc = "Cold, heavy manacles made out of some strange black metal."
|
||||
origin_tech = "materials=2;magnets=5"
|
||||
flags_1 = DROPDEL_1
|
||||
|
||||
/obj/item/restraints/handcuffs/clockwork/dropped(mob/user)
|
||||
user.visible_message("<span class='danger'>[user]'s [name] come apart at the seams!</span>", \
|
||||
"<span class='userdanger'>Your [name] break apart as they're removed!</span>")
|
||||
. = ..()
|
||||
|
||||
//For the Sentinel's Compromise scripture; heals a target servant.
|
||||
/obj/effect/proc_holder/slab/compromise
|
||||
@@ -140,12 +128,83 @@
|
||||
playsound(targetturf, 'sound/magic/staff_healing.ogg', 50, 1)
|
||||
|
||||
if(has_holy_water)
|
||||
L.reagents.del_reagent("holywater")
|
||||
L.reagents.remove_reagent("holywater", 1000)
|
||||
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
|
||||
//For the Kindle scripture; stuns and mutes a target non-servant.
|
||||
/obj/effect/proc_holder/slab/kindle
|
||||
ranged_mousepointer = 'icons/effects/volt_target.dmi'
|
||||
|
||||
/obj/effect/proc_holder/slab/kindle/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
var/turf/T = ranged_ability_user.loc
|
||||
if(!isturf(T))
|
||||
return TRUE
|
||||
|
||||
if(target in view(7, get_turf(ranged_ability_user)))
|
||||
|
||||
successful = TRUE
|
||||
|
||||
var/turf/U = get_turf(target)
|
||||
to_chat(ranged_ability_user, "<span class='brass'>You release the light of Ratvar!</span>")
|
||||
clockwork_say(ranged_ability_user, text2ratvar("Purge all untruths and honor Engine!"))
|
||||
add_logs(ranged_ability_user, U, "fired at with Kindle")
|
||||
playsound(ranged_ability_user, 'sound/magic/blink.ogg', 50, TRUE, frequency = 0.5)
|
||||
var/obj/item/projectile/kindle/A = new(T)
|
||||
A.original = target
|
||||
A.starting = T
|
||||
A.current = T
|
||||
A.yo = U.y - T.y
|
||||
A.xo = U.x - T.x
|
||||
A.fire()
|
||||
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/item/projectile/kindle
|
||||
name = "kindled flame"
|
||||
icon_state = "pulse0"
|
||||
nodamage = TRUE
|
||||
damage = 0 //We're just here for the stunning!
|
||||
damage_type = BURN
|
||||
flag = "bomb"
|
||||
range = 3
|
||||
log_override = TRUE
|
||||
|
||||
/obj/item/projectile/kindle/Destroy()
|
||||
visible_message("<span class='warning'>[src] flickers out!</span>")
|
||||
. = ..()
|
||||
|
||||
/obj/item/projectile/kindle/on_hit(atom/target, blocked = FALSE)
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(is_servant_of_ratvar(L) || L.stat || L.has_status_effect(STATUS_EFFECT_KINDLE))
|
||||
return
|
||||
var/obj/O = L.null_rod_check()
|
||||
playsound(L, 'sound/magic/fireball.ogg', 50, TRUE, frequency = 1.25)
|
||||
if(O)
|
||||
L.visible_message("<span class='warning'>[L]'s eyes flare with dim light as they stumble!</span>", \
|
||||
"<span class='userdanger'>Your [O] glows white-hot against you as it absorbs some sort of power!</span>")
|
||||
L.adjustFireLoss(5)
|
||||
L.Stun(40)
|
||||
playsound(L, 'sound/weapons/sear.ogg', 50, TRUE)
|
||||
else
|
||||
L.visible_message("<span class='warning'>[L]'s eyes blaze with brilliant light!</span>", \
|
||||
"<span class='userdanger'>Your vision suddenly screams with white-hot light!</span>")
|
||||
L.Knockdown(15)
|
||||
L.apply_status_effect(STATUS_EFFECT_KINDLE)
|
||||
L.flash_act(1, 1)
|
||||
if(iscultist(L))
|
||||
L.adjustFireLoss(15)
|
||||
..()
|
||||
|
||||
|
||||
//For the cyborg Linked Vanguard scripture, grants you and a nearby ally Vanguard
|
||||
/obj/effect/proc_holder/slab/vanguard
|
||||
ranged_mousepointer = 'icons/effects/vanguard_target.dmi'
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
//This is the innate action for "binding" and calling weapons to yourself. These weapons can appear and disappear at will.
|
||||
//You can invoke a cooldown period by calling "weapon_reset(cooldown in deciseconds)." By default, this only applies to dismissing weapons.
|
||||
/datum/action/innate/call_weapon
|
||||
name = "Call Weapon"
|
||||
desc = "This definitely shouldn't exist."
|
||||
icon_icon = 'icons/mob/actions/actions_clockcult.dmi'
|
||||
button_icon_state = "ratvarian_spear"
|
||||
background_icon_state = "bg_clock"
|
||||
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
|
||||
buttontooltipstyle = "clockcult"
|
||||
var/cooldown = 0
|
||||
var/obj/item/clockwork/weapon/weapon_type //The type of weapon to create
|
||||
var/obj/item/clockwork/weapon/weapon
|
||||
|
||||
/datum/action/innate/call_weapon/IsAvailable()
|
||||
if(!is_servant_of_ratvar(owner))
|
||||
qdel(src)
|
||||
return
|
||||
if(cooldown > world.time)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/call_weapon/Activate()
|
||||
if(!owner.get_empty_held_indexes())
|
||||
to_chat(usr, "<span class='warning'>You need an empty hand to call forth your [initial(weapon_type.name)]!</span>")
|
||||
return
|
||||
if(weapon)
|
||||
if(weapon.loc == owner)
|
||||
owner.visible_message("<span class='danger'>[owner]'s [weapon.name] flickers and disappears!</span>")
|
||||
to_chat(owner, "<span class='brass'>You dismiss [weapon].</span>")
|
||||
owner.drop_item()
|
||||
QDEL_NULL(weapon)
|
||||
weapon_reset(RATVARIAN_SPEAR_COOLDOWN * 0.5)
|
||||
return
|
||||
else
|
||||
weapon.visible_message("<span class='warning'>[weapon] suddenly flickers and disappears!</span>")
|
||||
owner.visible_message("<span class='danger'>A [weapon.name] suddenly flickers into [owner]'s hands!</span>", "<span class='brass'>You recall [weapon] to you.</span>")
|
||||
else
|
||||
weapon = new weapon_type (get_turf(usr), src)
|
||||
owner.visible_message("<span class='warning'>A [weapon.name] materializes in [owner]'s hands!</span>", "<span class='brass'>You call forth your [weapon.name]!</span>")
|
||||
weapon.forceMove(get_turf(owner))
|
||||
owner.put_in_hands(weapon)
|
||||
owner.update_action_buttons_icon()
|
||||
return TRUE
|
||||
|
||||
/datum/action/innate/call_weapon/proc/weapon_reset(cooldown_time)
|
||||
cooldown = world.time + cooldown_time
|
||||
addtimer(CALLBACK(owner, /mob.proc/update_action_buttons_icon), cooldown_time)
|
||||
owner.update_action_buttons_icon()
|
||||
QDEL_NULL(weapon)
|
||||
@@ -1,13 +1,10 @@
|
||||
//Ratvarian spear: A relatively fragile spear from the Celestial Derelict. Deals extreme damage to silicons and enemy cultists, but doesn't last long when summoned.
|
||||
/obj/item/clockwork/ratvarian_spear
|
||||
/obj/item/clockwork/weapon/ratvarian_spear
|
||||
name = "ratvarian spear"
|
||||
desc = "A razor-sharp spear made of brass. It thrums with barely-contained energy."
|
||||
clockwork_desc = "A powerful spear of Ratvarian making. It's more effective against enemy cultists and silicons."
|
||||
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 = 25
|
||||
armour_penetration = 10
|
||||
@@ -16,42 +13,27 @@
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
var/bonus_burn = 5
|
||||
var/timerid
|
||||
|
||||
/obj/item/clockwork/ratvarian_spear/Destroy()
|
||||
deltimer(timerid)
|
||||
return ..()
|
||||
|
||||
/obj/item/clockwork/ratvarian_spear/ratvar_act()
|
||||
/obj/item/clockwork/weapon/ratvarian_spear/ratvar_act()
|
||||
if(GLOB.ratvar_awakens) //If Ratvar is alive, the spear is extremely powerful
|
||||
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 = 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!
|
||||
..()
|
||||
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)
|
||||
/obj/item/clockwork/weapon/ratvarian_spear/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
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)
|
||||
/obj/item/clockwork/weapon/ratvarian_spear/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
. = ..()
|
||||
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
|
||||
@@ -63,7 +45,7 @@
|
||||
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)
|
||||
/obj/item/clockwork/weapon/ratvarian_spear/throw_impact(atom/target)
|
||||
var/turf/T = get_turf(target)
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
@@ -83,11 +65,12 @@
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/clockwork/ratvarian_spear/proc/break_spear(turf/T)
|
||||
/obj/item/clockwork/weapon/ratvarian_spear/proc/break_spear(turf/T)
|
||||
if(src)
|
||||
if(!T)
|
||||
T = get_turf(src)
|
||||
if(T) //make sure we're not in null or something
|
||||
T.visible_message("<span class='warning'>[src] [pick("cracks in two and fades away", "snaps in two and dematerializes")]!</span>")
|
||||
new /obj/effect/temp_visual/ratvar/spearbreak(T)
|
||||
qdel(src)
|
||||
action.weapon_reset(RATVARIAN_SPEAR_COOLDOWN)
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
icon_state = "clockwork_helmet"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
flags_inv = HIDEEARS|HIDEHAIR|HIDEFACE
|
||||
armor = list(melee = 50, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
|
||||
/obj/item/clothing/head/helmet/clockwork/Initialize()
|
||||
. = ..()
|
||||
@@ -23,8 +24,13 @@
|
||||
flags_1 |= STOPSPRESSUREDMAGE_1
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else if(GLOB.ratvar_approaches)
|
||||
armor = list(melee = 70, bullet = 80, laser = -15, energy = 25, bomb = 70, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
flags_1 |= STOPSPRESSUREDMAGE_1
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else
|
||||
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
armor = list(melee = 60, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
flags_1 &= ~STOPSPRESSUREDMAGE_1
|
||||
max_heat_protection_temperature = initial(max_heat_protection_temperature)
|
||||
min_cold_protection_temperature = initial(min_cold_protection_temperature)
|
||||
@@ -61,7 +67,7 @@
|
||||
cold_protection = CHEST|GROIN|LEGS
|
||||
heat_protection = CHEST|GROIN|LEGS
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
armor = list(melee = 60, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
allowed = list(/obj/item/clockwork, /obj/item/clothing/glasses/wraith_spectacles, /obj/item/clothing/glasses/judicial_visor, /obj/item/device/mmi/posibrain/soul_vessel)
|
||||
|
||||
/obj/item/clothing/suit/armor/clockwork/Initialize()
|
||||
@@ -79,8 +85,13 @@
|
||||
flags_1 |= STOPSPRESSUREDMAGE_1
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else if(GLOB.ratvar_approaches)
|
||||
armor = list(melee = 70, bullet = 80, laser = -15, energy = 25, bomb = 70, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
flags_1 |= STOPSPRESSUREDMAGE_1
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else
|
||||
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
armor = list(melee = 60, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
flags_1 &= ~STOPSPRESSUREDMAGE_1
|
||||
max_heat_protection_temperature = initial(max_heat_protection_temperature)
|
||||
min_cold_protection_temperature = initial(min_cold_protection_temperature)
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
/obj/item/clockwork/slab //Clockwork slab: The most important tool in Ratvar's arsenal. Allows scripture recital, tutorials, and generates components.
|
||||
name = "clockwork slab"
|
||||
desc = "A strange metal tablet. A clock in the center turns around and around."
|
||||
clockwork_desc = "A link between you and the Celestial Derelict. It produces components, contains information, and is your most vital tool as a Servant.\n\
|
||||
Use the <span class='brass'>Hierophant Network</span> action button to discreetly talk with other Servants.\n\
|
||||
Clockwork slabs will only make components if held or if inside an item held by a human, and when making a component will prevent all other slabs held from making components.\n\
|
||||
clockwork_desc = "A link between you and the Celestial Derelict. It contains information, recites scripture, and is your most vital tool as a Servant.\n\
|
||||
Hitting a slab, a Servant with a slab, or a cache will <b>transfer</b> this slab's components into the target, the target's slab, or the global cache, respectively."
|
||||
icon_state = "dread_ipad"
|
||||
lefthand_file = 'icons/mob/inhands/antag/clockwork_lefthand.dmi'
|
||||
@@ -11,30 +9,21 @@
|
||||
var/inhand_overlay //If applicable, this overlay will be applied to the slab's inhand
|
||||
slot_flags = SLOT_BELT
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
var/list/stored_components = list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 0, HIEROPHANT_ANSIBLE = 0)
|
||||
var/busy //If the slab is currently being used by something
|
||||
var/production_time = 0
|
||||
var/target_component_id //the target component ID to create, if any
|
||||
var/no_cost = FALSE //If the slab is admin-only and needs no components and has no scripture locks
|
||||
var/speed_multiplier = 1 //multiples how fast this slab recites scripture
|
||||
var/produces_components = TRUE //if it produces components at all
|
||||
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, /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/list/quickbound = list(/datum/clockwork_scripture/abscond, \
|
||||
/datum/clockwork_scripture/ranged_ability/kindle, /datum/clockwork_scripture/ranged_ability/hateful_manacles) //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)
|
||||
|
||||
/obj/item/clockwork/slab/starter
|
||||
stored_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 1, GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 1)
|
||||
|
||||
/obj/item/clockwork/slab/internal //an internal motor for mobs running scripture
|
||||
name = "scripture motor"
|
||||
quickbound = list()
|
||||
no_cost = TRUE
|
||||
produces_components = FALSE
|
||||
|
||||
/obj/item/clockwork/slab/debug
|
||||
speed_multiplier = 0
|
||||
@@ -49,33 +38,33 @@
|
||||
clockwork_desc = "A divine link to the Celestial Derelict, allowing for limited recital of scripture.\n\
|
||||
Hitting a slab, a Servant with a slab, or a cache will <b>transfer</b> this slab's components into the target, the target's slab, or the global cache, respectively."
|
||||
quickbound = list(/datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/ranged_ability/linked_vanguard, \
|
||||
/datum/clockwork_scripture/create_object/tinkerers_cache)
|
||||
/datum/clockwork_scripture/create_object/stargazer)
|
||||
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 //two scriptures, plus a fabricator
|
||||
quickbound = list(/datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/sigil_of_transmission)
|
||||
quickbound = list(/datum/clockwork_scripture/abscond, /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)
|
||||
quickbound = list(/datum/clockwork_scripture/abscond, /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)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/security //twoscriptures, plus a spear
|
||||
quickbound = list(/datum/clockwork_scripture/channeled/belligerent, /datum/clockwork_scripture/ranged_ability/judicial_marker)
|
||||
quickbound = list(/datum/clockwork_scripture/abscond, /datum/clockwork_scripture/ranged_ability/hateful_manacles, /datum/clockwork_scripture/ranged_ability/judicial_marker)
|
||||
|
||||
/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)
|
||||
quickbound = list(/datum/clockwork_scripture/abscond, /datum/clockwork_scripture/ranged_ability/hateful_manacles, /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, \
|
||||
/datum/clockwork_scripture/create_object/ocular_warden, /datum/clockwork_scripture/create_object/mania_motor, /datum/clockwork_scripture/create_object/tinkerers_daemon)
|
||||
quickbound = list(/datum/clockwork_scripture/abscond, /datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/sigil_of_transgression, \
|
||||
/datum/clockwork_scripture/create_object/ocular_warden, /datum/clockwork_scripture/create_object/mania_motor, /datum/clockwork_scripture/create_object/stargazer)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/service //five scriptures, plus xray vision
|
||||
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)
|
||||
quickbound = list(/datum/clockwork_scripture/abscond, /datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/stargazer, \
|
||||
/datum/clockwork_scripture/spatial_gateway, /datum/clockwork_scripture/create_object/clockwork_obelisk)
|
||||
|
||||
/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)
|
||||
quickbound = list(/datum/clockwork_scripture/abscond, /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)
|
||||
@@ -92,7 +81,9 @@
|
||||
. = ..()
|
||||
update_slab_info(src)
|
||||
START_PROCESSING(SSobj, src)
|
||||
production_time = world.time + SLAB_PRODUCTION_TIME
|
||||
if(GLOB.ratvar_approaches)
|
||||
name = "supercharged [name]"
|
||||
speed_multiplier = max(0.1, speed_multiplier - 0.25)
|
||||
|
||||
/obj/item/clockwork/slab/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
@@ -115,35 +106,12 @@
|
||||
if(user && !(src in user.held_items) && slab_ability && slab_ability.ranged_ability_user) //if we happen to check and we AREN'T in user's hands, remove whatever ability we have
|
||||
slab_ability.remove_ranged_ability()
|
||||
|
||||
//Component Generation
|
||||
//Power generation
|
||||
/obj/item/clockwork/slab/process()
|
||||
if(!produces_components)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return
|
||||
if(production_time > world.time)
|
||||
return
|
||||
var/servants = 0
|
||||
var/production_slowdown = 0
|
||||
for(var/mob/living/M in GLOB.living_mob_list)
|
||||
if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M)))
|
||||
servants++
|
||||
if(servants > SCRIPT_SERVANT_REQ)
|
||||
servants -= SCRIPT_SERVANT_REQ
|
||||
production_slowdown = min(SLAB_SERVANT_SLOWDOWN * servants, SLAB_SLOWDOWN_MAXIMUM) //SLAB_SERVANT_SLOWDOWN additional seconds for each servant above 5, up to SLAB_SLOWDOWN_MAXIMUM
|
||||
production_time = world.time + SLAB_PRODUCTION_TIME + production_slowdown
|
||||
var/mob/living/L
|
||||
L = get_atom_on_turf(src, /mob/living)
|
||||
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
|
||||
stored_components[component_to_generate]++
|
||||
update_slab_info(src)
|
||||
for(var/obj/item/clockwork/slab/S in L.GetAllContents()) //prevent slab abuse today
|
||||
if(S == src)
|
||||
continue
|
||||
S.production_time = production_time + 50 //set it to our next production plus five seconds, so that if you hold the same slabs, the same one will always generate
|
||||
to_chat(L, "<span class='warning'>Your slab cl[pick("ank", "ink", "unk", "ang")]s as it produces a </span><span class='[get_component_span(component_to_generate)]'>component</span><span class='warning'>.</span>")
|
||||
if(GLOB.ratvar_approaches && speed_multiplier == initial(speed_multiplier))
|
||||
name = "supercharged [name]"
|
||||
speed_multiplier = max(0.1, speed_multiplier - 0.25)
|
||||
adjust_clockwork_power(0.1) //Slabs serve as very weak power generators on their own (no, not enough to justify spamming them)
|
||||
|
||||
/obj/item/clockwork/slab/examine(mob/user)
|
||||
..()
|
||||
@@ -154,97 +122,14 @@
|
||||
continue
|
||||
var/datum/clockwork_scripture/quickbind_slot = quickbound[i]
|
||||
to_chat(user, "<b>Quickbind</b> button: <span class='[get_component_span(initial(quickbind_slot.primary_component))]'>[initial(quickbind_slot.name)]</span>.")
|
||||
if(GLOB.clockwork_caches) //show components on examine
|
||||
to_chat(user, "<b>Stored components (with global cache):</b>")
|
||||
for(var/i in stored_components)
|
||||
to_chat(user, "[get_component_icon(i)] <span class='[get_component_span(i)]_small'><i>[get_component_name(i)][i != REPLICANT_ALLOY ? "s":""]:</i> <b>[stored_components[i]]</b> \
|
||||
(<b>[stored_components[i] + GLOB.clockwork_component_cache[i]]</b>)</span>")
|
||||
else
|
||||
to_chat(user, "<b>Stored components:</b>")
|
||||
for(var/i in stored_components)
|
||||
to_chat(user, "[get_component_icon(i)] <span class='[get_component_span(i)]_small'><i>[get_component_name(i)][i != REPLICANT_ALLOY ? "s":""]:</i> <b>[stored_components[i]]</b></span>")
|
||||
|
||||
//Component Transferal
|
||||
/obj/item/clockwork/slab/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
if(is_servant_of_ratvar(user) && is_servant_of_ratvar(target))
|
||||
var/obj/item/clockwork/slab/targetslab
|
||||
var/highest_component_amount = 0
|
||||
for(var/obj/item/clockwork/slab/S in target.GetAllContents())
|
||||
if(!istype(S, /obj/item/clockwork/slab/internal))
|
||||
var/totalcomponents = 0
|
||||
for(var/i in S.stored_components)
|
||||
totalcomponents += S.stored_components[i]
|
||||
if(!targetslab || totalcomponents > highest_component_amount)
|
||||
highest_component_amount = totalcomponents
|
||||
targetslab = S
|
||||
if(targetslab)
|
||||
if(targetslab == src)
|
||||
to_chat(user, "<span class='heavy_brass'>\"You can't transfer components into your own slab, idiot.\"</span>")
|
||||
else
|
||||
for(var/i in stored_components)
|
||||
targetslab.stored_components[i] += stored_components[i]
|
||||
stored_components[i] = 0
|
||||
update_slab_info(targetslab)
|
||||
update_slab_info(src)
|
||||
user.visible_message("<span class='notice'>[user] empties [src] into [target]'s [targetslab.name].</span>", \
|
||||
"<span class='notice'>You transfer your slab's components into [target]'s [targetslab.name].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[target] has no slabs to transfer components to.</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/clockwork/slab/attackby(obj/item/I, mob/user, params)
|
||||
var/ratvarian = is_servant_of_ratvar(user)
|
||||
if(istype(I, /obj/item/clockwork/component) && ratvarian)
|
||||
var/obj/item/clockwork/component/C = I
|
||||
if(!C.component_id)
|
||||
return 0
|
||||
user.visible_message("<span class='notice'>[user] inserts [C] into [src].</span>", "<span class='notice'>You insert [C] into [src]\
|
||||
[GLOB.clockwork_caches ? ", where it is added to the global cache":""].</span>")
|
||||
if(GLOB.clockwork_caches)
|
||||
GLOB.clockwork_component_cache[C.component_id]++
|
||||
update_slab_info()
|
||||
else
|
||||
stored_components[C.component_id]++
|
||||
update_slab_info(src)
|
||||
user.drop_item()
|
||||
qdel(C)
|
||||
return 1
|
||||
else if(istype(I, /obj/item/clockwork/slab) && ratvarian)
|
||||
var/obj/item/clockwork/slab/S = I
|
||||
var/needs_update = FALSE
|
||||
for(var/i in stored_components)
|
||||
stored_components[i] += S.stored_components[i]
|
||||
S.stored_components[i] = 0
|
||||
if(S.stored_components[i])
|
||||
needs_update = TRUE
|
||||
if(needs_update)
|
||||
update_slab_info(src)
|
||||
update_slab_info(S)
|
||||
user.visible_message("<span class='notice'>[user] empties [src] into [S].</span>", "<span class='notice'>You transfer your slab's components into [S].</span>")
|
||||
else
|
||||
return ..()
|
||||
to_chat(user, "<b>Available Power:</b> <span class='bold brass'>[DisplayPower(get_clockwork_power())]</span>")
|
||||
|
||||
//Slab actions; Hierophant, Quickbind
|
||||
/obj/item/clockwork/slab/ui_action_click(mob/user, action)
|
||||
if(istype(action, /datum/action/item_action/clock/hierophant))
|
||||
show_hierophant(user)
|
||||
else if(istype(action, /datum/action/item_action/clock/quickbind))
|
||||
if(istype(action, /datum/action/item_action/clock/quickbind))
|
||||
var/datum/action/item_action/clock/quickbind/Q = action
|
||||
recite_scripture(quickbound[Q.scripture_index], user, FALSE)
|
||||
|
||||
/obj/item/clockwork/slab/proc/show_hierophant(mob/living/user)
|
||||
if(!user.can_speak_vocal())
|
||||
to_chat(user, "<span class='warning'>You cannot speak into the slab!</span>")
|
||||
return FALSE
|
||||
var/message = stripped_input(user, "Enter a message to send to your fellow Servants.", "Hierophant")
|
||||
if(!message || !user || !user.canUseTopic(src) || !user.can_speak_vocal())
|
||||
return FALSE
|
||||
clockwork_say(user, text2ratvar("Servants, hear my words: [html_decode(message)]"), TRUE)
|
||||
log_talk(user,"CLOCK:[key_name(user)] : [message]",LOGSAY)
|
||||
titled_hierophant_message(user, message)
|
||||
return TRUE
|
||||
|
||||
//Scripture Recital
|
||||
/obj/item/clockwork/slab/attack_self(mob/living/user)
|
||||
if(iscultist(user))
|
||||
@@ -310,34 +195,10 @@
|
||||
textlist += "HONOR RATVAR "
|
||||
textlist += "</b></font>"
|
||||
else
|
||||
var/servants = 0
|
||||
var/production_time = SLAB_PRODUCTION_TIME
|
||||
for(var/mob/living/M in GLOB.living_mob_list)
|
||||
if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M)))
|
||||
servants++
|
||||
if(servants > SCRIPT_SERVANT_REQ)
|
||||
servants -= SCRIPT_SERVANT_REQ
|
||||
production_time += min(SLAB_SERVANT_SLOWDOWN * servants, SLAB_SLOWDOWN_MAXIMUM)
|
||||
var/production_text_addon = ""
|
||||
if(production_time != SLAB_PRODUCTION_TIME+SLAB_SLOWDOWN_MAXIMUM)
|
||||
production_text_addon = ", which increases for each human or silicon Servant above <b>[SCRIPT_SERVANT_REQ]</b>"
|
||||
production_time = production_time/600
|
||||
var/list/production_text
|
||||
if(round(production_time))
|
||||
production_text = list("<b>[round(production_time)] minute\s")
|
||||
if(production_time != round(production_time))
|
||||
production_time -= round(production_time)
|
||||
production_time *= 60
|
||||
if(!LAZYLEN(production_text))
|
||||
production_text = list("<b>[round(production_time, 1)] second\s")
|
||||
else
|
||||
production_text += " and [round(production_time, 1)] second\s"
|
||||
production_text += "</b>"
|
||||
production_text += production_text_addon
|
||||
production_text = production_text.Join()
|
||||
|
||||
textlist = list("<font color=#BE8700 size=3><b><center>[text2ratvar("Purge all untruths and honor Engine.")]</center></b></font><br>\
|
||||
\
|
||||
<b><i>NOTICE:</b> This information is out of date. Read the Ark & You primer in your backpack or read the wiki page for current info.</i><br>\
|
||||
<hr><br>\
|
||||
These pages serve as the archives of Ratvar, the Clockwork Justiciar. This section of your slab has information on being as a Servant, advice for what to do next, and \
|
||||
pointers for serving the master well. You should recommended that you check this area for help if you get stuck or need guidance on what to do next.<br><br>\
|
||||
\
|
||||
@@ -402,11 +263,6 @@
|
||||
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-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>"
|
||||
@@ -431,42 +287,12 @@
|
||||
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
|
||||
var/production_time = SLAB_PRODUCTION_TIME
|
||||
for(var/mob/living/M in GLOB.living_mob_list)
|
||||
if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M)))
|
||||
servants++
|
||||
if(servants > SCRIPT_SERVANT_REQ)
|
||||
servants -= SCRIPT_SERVANT_REQ
|
||||
production_time += min(SLAB_SERVANT_SLOWDOWN * servants, SLAB_SLOWDOWN_MAXIMUM)
|
||||
var/production_text_addon = ""
|
||||
if(production_time != SLAB_PRODUCTION_TIME+SLAB_SLOWDOWN_MAXIMUM)
|
||||
production_text_addon = ", which increases for each human or silicon Servant above <b>[SCRIPT_SERVANT_REQ]</b>"
|
||||
production_time = production_time/600
|
||||
var/list/production_text
|
||||
if(round(production_time))
|
||||
production_text = list("<b>[round(production_time)] minute\s")
|
||||
if(production_time != round(production_time))
|
||||
production_time -= round(production_time)
|
||||
production_time *= 60
|
||||
if(!LAZYLEN(production_text))
|
||||
production_text = list("<b>[round(production_time, 1)] second\s")
|
||||
else
|
||||
production_text += " and [round(production_time, 1)] second\s"
|
||||
production_text += "</b>"
|
||||
production_text += production_text_addon
|
||||
production_text = production_text.Join()
|
||||
dat += "<font color=#BE8700 size=3>Components & Their Uses</font><br><br>"
|
||||
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>"
|
||||
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 \
|
||||
vanguard cogwheels as construction requirements, because it defends its allies by harming its enemies.<br><br>"
|
||||
dat += "Components' primary use is fueling <b>scripture</b> (covered in its own section), and they can be created through various ways. This clockwork slab, for instance, \
|
||||
will make a random component of every type - or a specific one, if you choose a target component from the interface - every <b>[production_text]</b>. This number will increase \
|
||||
will make a random component of every type - or a specific one, if you choose a target component from the interface - every <b>remove me already</b>. This number will increase \
|
||||
as the amount of Servants in the covenant increase; additionally, slabs can only produce components when held by a Servant, and holding more than one slab will cause both \
|
||||
of them to halt progress until one of them is removed from their person.<br><br>"
|
||||
dat += "Your slab has an internal storage of components, but it isn't meant to be the main one. Instead, there's a <b>global storage</b> of components that can be \
|
||||
@@ -487,7 +313,7 @@
|
||||
dat += "It should also be noted that some scripture cannot be recited alone. Especially with more powerful scripture, you may need multiple Servants to recite a piece of \
|
||||
scripture; both of you will need to stand still until the recital completes. <i>Only human and silicon Servants are valid for scripture recital!</i> Constructs cannot help \
|
||||
in reciting scripture.<br><br>"
|
||||
dat += "Finally, scripture is separated into four \"tiers\" based on power: Drivers, Scripts, Applications, and Judgement.[prob(1) ? " (The Revenant tier was removed a long time ago. \
|
||||
dat += "Finally, scripture is separated into three \"tiers\" based on power: Drivers, Scripts, and Applications.[prob(1) ? " (The Revenant tier was removed a long time ago. \
|
||||
Get with the times.)" : ""] You can view the requirements to unlock each tier in its scripture list. Once a tier is unlocked, it's unlocked permanently; the cult only needs to fill the \
|
||||
requirement for unlocking a tier once!<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
|
||||
@@ -551,7 +377,7 @@
|
||||
One of the cogscarabs must've misplaced this section, because the game wasn't able to find any info regarding it. Report this to the coders!"
|
||||
return "<br><br>[dat.Join()]<br><br>"
|
||||
|
||||
//Gets the quickbound scripture as a text block."
|
||||
//Gets the quickbound scripture as a text block.
|
||||
/obj/item/clockwork/slab/proc/get_recollection_quickbinds()
|
||||
var/list/dat = list()
|
||||
dat += "<font color=#BE8700 size=3>Quickbound Scripture</font><br>\
|
||||
@@ -568,24 +394,7 @@
|
||||
|
||||
/obj/item/clockwork/slab/ui_data(mob/user) //we display a lot of data via TGUI
|
||||
var/list/data = list()
|
||||
data["components"] = stored_components.Copy()
|
||||
var/list/temp_data = list("<font color=#B18B25>")
|
||||
for(var/i in data["components"]) //display the slab's components
|
||||
temp_data += "<font color=[get_component_color_bright(i)]>[get_component_icon(i)] <b>[data["components"][i]]</b></font>"
|
||||
if(i != HIEROPHANT_ANSIBLE)
|
||||
temp_data += " "
|
||||
else
|
||||
temp_data += " ("
|
||||
if(GLOB.clockwork_caches) //if we have caches, display what's in the global cache
|
||||
for(var/i in GLOB.clockwork_component_cache)
|
||||
temp_data += "<font color=[get_component_color_bright(i)]>[get_component_icon(i)] <b>[data["components"][i] + GLOB.clockwork_component_cache[i]]</b></font>"
|
||||
if(i != HIEROPHANT_ANSIBLE)
|
||||
temp_data += " "
|
||||
else
|
||||
temp_data += "<b>NONE</b>"
|
||||
temp_data += ")</font>"
|
||||
temp_data = temp_data.Join()
|
||||
data["components"] = temp_data
|
||||
data["power"] = "<b><font color=#B18B25>[DisplayPower(get_clockwork_power())]</b> power is available for scripture and other consumers.</font>"
|
||||
|
||||
switch(selected_scripture) //display info based on selected scripture tier
|
||||
if(SCRIPTURE_DRIVER)
|
||||
@@ -594,24 +403,15 @@
|
||||
if(SSticker.scripture_states[SCRIPTURE_SCRIPT])
|
||||
data["tier_info"] = "<font color=#B18B25><b>These scriptures are permenantly unlocked.</b></font>"
|
||||
else
|
||||
data["tier_info"] = "<font color=#B18B25><i>These scriptures require at least <b>[SCRIPT_SERVANT_REQ]</b> Servants and <b>[SCRIPT_CACHE_REQ]</b> Tinkerer's Cache.</i></font>"
|
||||
data["tier_info"] = "<font color=#B18B25><i>These scriptures will automatically unlock when the Ark is halfway ready or if [DisplayPower(SCRIPT_UNLOCK_THRESHOLD)] of power is reached.</i></font>"
|
||||
if(SCRIPTURE_APPLICATION)
|
||||
if(SSticker.scripture_states[SCRIPTURE_APPLICATION])
|
||||
data["tier_info"] = "<font color=#B18B25><b>These scriptures are permenantly unlocked.</b></font>"
|
||||
else
|
||||
data["tier_info"] = "<font color=#B18B25><i>These scriptures require at least <b>[APPLICATION_SERVANT_REQ]</b> Servants, <b>[APPLICATION_CACHE_REQ]</b> Tinkerer's Caches, and <b>[APPLICATION_CV_REQ]CV</b>.</i></font>"
|
||||
if(SCRIPTURE_JUDGEMENT)
|
||||
if(SSticker.scripture_states[SCRIPTURE_JUDGEMENT])
|
||||
data["tier_info"] = "<font color=#B18B25><b>This scripture is permenantly unlocked.</b></font>"
|
||||
else
|
||||
data["tier_info"] = "<font color=#B18B25><i>This scripture requires at least <b>[JUDGEMENT_SERVANT_REQ]</b> Servants, <b>[JUDGEMENT_CACHE_REQ]</b> Tinkerer's Caches, and <b>[JUDGEMENT_CV_REQ]CV</b>.<br>In addition, there may not be any active non-Servant AIs.</i></font>"
|
||||
data["tier_info"] = "<font color=#B18B25><i>Unlock these optional scriptures by converting another servant or if [DisplayPower(APPLICATION_UNLOCK_THRESHOLD)] of power is reached..</i></font>"
|
||||
|
||||
data["selected"] = selected_scripture
|
||||
|
||||
data["target_comp"] = "<font color=#B18B25>NONE</font>"
|
||||
if(target_component_id) //if we have a component to make, display that, too
|
||||
data["target_comp"] = "<font color=[get_component_color_bright(target_component_id)]>[get_component_icon(target_component_id)]</font>"
|
||||
|
||||
generate_all_scripture()
|
||||
|
||||
data["scripture"] = list()
|
||||
@@ -622,7 +422,7 @@
|
||||
var/list/temp_info = list("name" = "<font color=[scripture_color]><b>[S.name]</b></font>",
|
||||
"descname" = "<font color=[scripture_color]>([S.descname])</font>",
|
||||
"tip" = "[S.desc]\n[S.usage_tip]",
|
||||
"required" = list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 0, HIEROPHANT_ANSIBLE = 0),
|
||||
"required" = "([DisplayPower(S.power_cost)][S.special_power_text ? "+ [replacetext(S.special_power_text, "POWERCOST", "[DisplayPower(S.special_power_cost)]")]" : ""])",
|
||||
"type" = "[S.type]",
|
||||
"quickbind" = S.quickbind)
|
||||
var/found = quickbound.Find(S.type)
|
||||
@@ -630,20 +430,6 @@
|
||||
temp_info["bound"] = "<b>[found]</b>"
|
||||
if(S.invokers_required > 1)
|
||||
temp_info["invokers"] = "<font color=#B18B25>Invokers: <b>[S.invokers_required]</b></font>"
|
||||
var/costs_components = FALSE
|
||||
for(var/i in S.consumed_components)
|
||||
if(S.consumed_components[i])
|
||||
temp_info["required"][i] += S.consumed_components[i]
|
||||
costs_components = TRUE
|
||||
if(costs_components) //if we have a component cost, we'll need a : next to the recital button
|
||||
var/list/really_temp_data = list(": ")
|
||||
for(var/i in temp_info["required"])
|
||||
if(temp_info["required"][i])
|
||||
really_temp_data += "<font color=[get_component_color_bright(i)]>[get_component_icon(i)] <b>[temp_info["required"][i]]</b></font> "
|
||||
really_temp_data = really_temp_data.Join()
|
||||
temp_info["required"] = really_temp_data
|
||||
else //and if we don't, we won't.
|
||||
temp_info["required"] = ""
|
||||
data["scripture"] += list(temp_info)
|
||||
data["recollection"] = recollecting
|
||||
if(recollecting)
|
||||
@@ -669,16 +455,6 @@
|
||||
INVOKE_ASYNC(src, .proc/recite_scripture, text2path(params["category"]), usr, FALSE)
|
||||
if("select")
|
||||
selected_scripture = params["category"]
|
||||
if("component")
|
||||
var/list/components = list("Random Components")
|
||||
for(var/i in GLOB.clockwork_component_cache)
|
||||
var/cache_components = 0
|
||||
if(GLOB.clockwork_caches)
|
||||
cache_components = GLOB.clockwork_component_cache[i]
|
||||
components["[get_component_name(i)] [(cache_components + stored_components[i])]"] = i
|
||||
var/input_component = input("Choose a component type.", "Target Component") as null|anything in components
|
||||
if(input_component && !..())
|
||||
target_component_id = components[input_component]
|
||||
if("bind")
|
||||
var/datum/clockwork_scripture/path = text2path(params["category"]) //we need a path and not a string
|
||||
var/found_index = quickbound.Find(path)
|
||||
@@ -723,14 +499,7 @@
|
||||
Q.scripture_index = i
|
||||
var/datum/clockwork_scripture/quickbind_slot = GLOB.all_scripture[quickbound[i]]
|
||||
Q.name = "[quickbind_slot.name] ([Q.scripture_index])"
|
||||
var/list/temp_desc = list()
|
||||
for(var/c in quickbind_slot.consumed_components) //show how much the bound scripture costs
|
||||
if(quickbind_slot.consumed_components[c])
|
||||
temp_desc += "<font color=[get_component_color_bright(c)]>[get_component_icon(c)] <b>[quickbind_slot.consumed_components[c]]</b></font> "
|
||||
if(LAZYLEN(temp_desc))
|
||||
temp_desc += "<br>"
|
||||
temp_desc += "[quickbind_slot.quickbind_desc]"
|
||||
Q.desc = temp_desc.Join()
|
||||
Q.desc = quickbind_slot.quickbind_desc
|
||||
Q.button_icon_state = quickbind_slot.name
|
||||
Q.UpdateButtonIcon()
|
||||
if(isliving(loc))
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
//This is the base type for clockwork melee weapons.
|
||||
/obj/item/clockwork/weapon
|
||||
name = "clockwork weapon"
|
||||
desc = "Weaponized brass. Whould've thunk it?"
|
||||
clockwork_desc = "This shouldn't exist. Report it to a coder."
|
||||
icon = 'icons/obj/clockwork_objects.dmi'
|
||||
lefthand_file = 'icons/mob/inhands/antag/clockwork_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/clockwork_righthand.dmi'
|
||||
var/datum/action/innate/call_weapon/action //Some melee weapons use an action that lets you return and dismiss them
|
||||
|
||||
/obj/item/clockwork/weapon/Initialize(mapload, new_action)
|
||||
. = ..()
|
||||
if(new_action)
|
||||
action = new_action
|
||||
action.weapon = src
|
||||
@@ -0,0 +1,69 @@
|
||||
//Construct shells that can be activated by ghosts.
|
||||
/obj/item/clockwork/construct_chassis
|
||||
name = "construct chassis"
|
||||
desc = "A shell formed out of brass, presumably for housing machinery."
|
||||
clockwork_desc = "A construct chassis. It can be activated at any time by a willing ghost."
|
||||
var/construct_name = "basic construct"
|
||||
var/construct_desc = "<span class='alloy'>There is no construct for this chassis. Report this to a coder.</span>"
|
||||
icon_state = "anime_fragment"
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
var/creation_message = "<span class='brass'>The chassis shudders and hums to life!</span>"
|
||||
var/construct_type //The construct this shell will create
|
||||
|
||||
/obj/item/clockwork/construct_chassis/Initialize()
|
||||
. = ..()
|
||||
var/area/A = get_area(src)
|
||||
if(A && construct_type)
|
||||
notify_ghosts("A [construct_name] chassis has been created in [A.name]!", 'sound/magic/clockwork/fellowship_armory.ogg', source = src, action = NOTIFY_ORBIT, flashwindow = FALSE)
|
||||
GLOB.poi_list += src
|
||||
|
||||
/obj/item/clockwork/construct_chassis/Destroy()
|
||||
GLOB.poi_list -= src
|
||||
. = ..()
|
||||
|
||||
/obj/item/clockwork/construct_chassis/examine(mob/user)
|
||||
clockwork_desc = "[clockwork_desc]<br>[construct_desc]"
|
||||
..()
|
||||
clockwork_desc = initial(clockwork_desc)
|
||||
|
||||
/obj/item/clockwork/construct_chassis/attack_hand(mob/living/user)
|
||||
if(w_class >= WEIGHT_CLASS_HUGE)
|
||||
to_chat(user, "<span class='warning'>[src] is too cumbersome to carry! Drag it around instead!</span>")
|
||||
return
|
||||
. = ..()
|
||||
|
||||
/obj/item/clockwork/construct_chassis/attack_ghost(mob/user)
|
||||
if(alert(user, "Become a [construct_name]? You can no longer be cloned!", construct_name, "Yes", "Cancel") == "Cancel")
|
||||
return
|
||||
if(QDELETED(src))
|
||||
to_chat(user, "<span class='danger'>You were too late! Better luck next time.</span>")
|
||||
return
|
||||
visible_message(creation_message)
|
||||
var/mob/living/construct = new construct_type(get_turf(src))
|
||||
construct.key = user.key
|
||||
qdel(user)
|
||||
qdel(src)
|
||||
|
||||
|
||||
//Marauder armor, used to create clockwork marauders - sturdy frontline combatants that can deflect projectiles.
|
||||
/obj/item/clockwork/construct_chassis/clockwork_marauder
|
||||
name = "marauder armor"
|
||||
desc = "A pile of sleek and well-polished brass armor. A small red gemstone sits in its faceplate."
|
||||
icon_state = "marauder_armor"
|
||||
construct_name = "clockwork marauder"
|
||||
construct_desc = "<span class='neovgre_small'>It will become a <b>clockwork marauder,</b> a well-rounded frontline combatant.</span>"
|
||||
creation_message = "<span class='neovgre_small bold'>Crimson fire begins to rage in the armor as it rises into the air with its arnaments!</span>"
|
||||
construct_type = /mob/living/simple_animal/hostile/clockwork/marauder
|
||||
|
||||
|
||||
//Cogscarab shell, used to create cogcarabs - fragile but zippy little drones that build and maintain the base.
|
||||
/obj/item/clockwork/construct_chassis/cogscarab
|
||||
name = "cogscarab shell"
|
||||
desc = "A small, complex shell that resembles a repair drone, but much larger and made out of brass."
|
||||
icon_state = "cogscarab_shell"
|
||||
construct_name = "cogscarab"
|
||||
construct_desc = "<span class='alloy'>It will become a <b>cogscarab,</b> a small and fragile drone that builds, repairs, and maintains.</span>"
|
||||
creation_message = "<span class='alloy bold'>The cogscarab clicks and whirrs as it hops up and springs to life!</span>"
|
||||
construct_type = /mob/living/simple_animal/drone/cogscarab
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
@@ -0,0 +1,38 @@
|
||||
#define COG_MAX_SIPHON_THRESHOLD 0.25 //The cog will not siphon power if the APC's cell is at this % of power
|
||||
|
||||
//Can be used on an open APC to replace its guts with clockwork variants, and begin passively siphoning power from it
|
||||
/obj/item/clockwork/integration_cog
|
||||
name = "integration cog"
|
||||
desc = "A small cogwheel that fits in the palm of your hand."
|
||||
clockwork_desc = "A small cogwheel that can be inserted into an open APC to siphon power from it passively.<br>\
|
||||
<span class='brass'>It can be used on a locked APC to open its cover!</span><br>\
|
||||
<span class='brass'>Siphons <b>5 W</b> of power per second while in an APC.</span>"
|
||||
icon_state = "wall_gear"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
flags_1 = NOBLUDGEON_1
|
||||
var/obj/machinery/power/apc/apc
|
||||
|
||||
/obj/item/clockwork/integration_cog/Initialize()
|
||||
. = ..()
|
||||
transform *= 0.5 //little cog!
|
||||
|
||||
/obj/item/clockwork/integration_cog/Destroy()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
. = ..()
|
||||
|
||||
/obj/item/clockwork/integration_cog/process()
|
||||
if(!apc)
|
||||
if(istype(loc, /obj/machinery/power/apc))
|
||||
apc = loc
|
||||
else
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
else
|
||||
var/obj/item/stock_parts/cell/cell = apc.cell
|
||||
if(cell && (cell.charge / cell.maxcharge > COG_MAX_SIPHON_THRESHOLD))
|
||||
cell.use(1)
|
||||
adjust_clockwork_power(1) //Power is shared, so only do it once; this runs very quickly so it's about 1W/second
|
||||
if(prob(1))
|
||||
playsound(apc, 'sound/machines/clockcult/steam_whoosh.ogg', 10, TRUE)
|
||||
new/obj/effect/temp_visual/steam(get_turf(apc), pick(GLOB.cardinals))
|
||||
|
||||
#undef COG_MAX_SIPHON_THRESHOLD
|
||||
@@ -170,7 +170,7 @@
|
||||
if(!QDELETED(B))
|
||||
B.duration = world.time + 30
|
||||
C.Knockdown(5) //knocks down for half a second if affected
|
||||
sleep(16)
|
||||
sleep(!GLOB.ratvar_approaches ? 16 : 10)
|
||||
name = "judicial blast"
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
flick("judicial_explosion", src)
|
||||
|
||||
@@ -9,17 +9,9 @@
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
force = 5
|
||||
flags_1 = NOBLUDGEON_1
|
||||
var/stored_power = 0 //Requires power to function
|
||||
var/max_power = CLOCKCULT_POWER_UNIT * 10
|
||||
var/speed_multiplier = 1 //The speed ratio the fabricator operates at
|
||||
var/uses_power = TRUE
|
||||
var/repairing = null //what we're currently repairing, if anything
|
||||
var/obj/effect/clockwork/sigil/transmission/recharging = null //the sigil we're charging from, if any
|
||||
var/speed_multiplier = 1 //how fast this fabricator works
|
||||
var/charge_rate = MIN_CLOCKCULT_POWER //how much power we gain every two seconds
|
||||
var/charge_delay = 2 //how many proccess ticks remain before we can start to charge
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/preloaded
|
||||
stored_power = POWER_WALL_MINUS_FLOOR+POWER_WALL_TOTAL
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/scarab
|
||||
name = "scarab fabricator"
|
||||
@@ -27,7 +19,6 @@
|
||||
item_state = "nothing"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
speed_multiplier = 0.5
|
||||
charge_rate = MIN_CLOCKCULT_POWER * 2
|
||||
var/debug = FALSE
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/scarab/fabricate(atom/target, mob/living/user)
|
||||
@@ -42,75 +33,7 @@
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/cyborg
|
||||
name = "cyborg fabricator"
|
||||
clockwork_desc = "A cyborg's internal fabricator. It is capable of using the cyborg's power in addition to stored power."
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/cyborg/get_power() //returns power and cyborg's power
|
||||
var/mob/living/silicon/robot/R = get_atom_on_turf(src, /mob/living)
|
||||
var/borg_power = 0
|
||||
var/current_charge = 0
|
||||
if(istype(R) && R.cell)
|
||||
current_charge = R.cell.charge
|
||||
while(current_charge > MIN_CLOCKCULT_POWER)
|
||||
current_charge -= MIN_CLOCKCULT_POWER
|
||||
borg_power += MIN_CLOCKCULT_POWER
|
||||
return ..() + borg_power
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/cyborg/get_max_power()
|
||||
var/mob/living/silicon/robot/R = get_atom_on_turf(src, /mob/living)
|
||||
var/cell_maxcharge = 0
|
||||
if(istype(R) && R.cell)
|
||||
cell_maxcharge = R.cell.maxcharge
|
||||
return ..() + cell_maxcharge
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/cyborg/can_use_power(amount)
|
||||
if(amount != RATVAR_POWER_CHECK)
|
||||
var/mob/living/silicon/robot/R = get_atom_on_turf(src, /mob/living)
|
||||
var/current_charge = 0
|
||||
if(istype(R) && R.cell)
|
||||
current_charge = R.cell.charge
|
||||
while(amount > 0 && stored_power - amount < 0) //amount is greater than 0 and stored power minus the amount is still less than 0
|
||||
current_charge -= MIN_CLOCKCULT_POWER
|
||||
amount -= MIN_CLOCKCULT_POWER
|
||||
if(current_charge < 0)
|
||||
return FALSE
|
||||
. = ..()
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/cyborg/modify_stored_power(amount)
|
||||
var/mob/living/silicon/robot/R = get_atom_on_turf(src, /mob/living)
|
||||
if(istype(R) && R.cell && amount)
|
||||
if(amount < 0)
|
||||
while(amount < 0 && stored_power + amount < 0) //amount is less than 0 and stored alloy plus the amount is less than 0
|
||||
R.cell.use(MIN_CLOCKCULT_POWER)
|
||||
amount += MIN_CLOCKCULT_POWER
|
||||
else
|
||||
while(amount > 0 && R.cell.charge + MIN_CLOCKCULT_POWER < R.cell.maxcharge) //amount is greater than 0 and cell charge plus MIN_CLOCKCULT_POWER is less than maximum cell charge
|
||||
R.cell.give(MIN_CLOCKCULT_POWER)
|
||||
amount -= MIN_CLOCKCULT_POWER
|
||||
. = ..()
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/Initialize()
|
||||
. = ..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/process()
|
||||
if(!charge_rate)
|
||||
return
|
||||
var/mob/living/L = get_atom_on_turf(src, /mob/living)
|
||||
if(istype(L) && is_servant_of_ratvar(L))
|
||||
if(charge_delay)
|
||||
charge_delay--
|
||||
return
|
||||
modify_stored_power(charge_rate)
|
||||
for(var/obj/item/clockwork/replica_fabricator/S in L.GetAllContents()) //no multiple fabricators
|
||||
if(S == src)
|
||||
continue
|
||||
S.charge_delay = 2
|
||||
else
|
||||
charge_delay = 2
|
||||
clockwork_desc = "A cyborg's internal fabricator."
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/ratvar_act()
|
||||
if(GLOB.ratvar_awakens)
|
||||
@@ -129,45 +52,24 @@
|
||||
to_chat(user, "<span class='alloy'>It can consume floor tiles, rods, metal, and plasteel for power at rates of <b>2:[DisplayPower(POWER_ROD)]</b>, <b>1:[DisplayPower(POWER_ROD)]</b>, <b>1:[DisplayPower(POWER_METAL)]</b>, \
|
||||
and <b>1:[DisplayPower(POWER_PLASTEEL)]</b>, respectively.</span>")
|
||||
to_chat(user, "<span class='alloy'>It can also consume brass sheets for power at a rate of <b>1:[DisplayPower(POWER_FLOOR)]</b>.</span>")
|
||||
to_chat(user, "<span class='alloy'>It is storing <b>[DisplayPower(get_power())]/[DisplayPower(get_max_power())]</b> of power[charge_rate ? ", and is gaining <b>[DisplayPower(charge_rate*0.5)]</b> of power per second":""].</span>")
|
||||
to_chat(user, "<span class='alloy'>Use it in-hand to produce <b>5</b> brass sheets at a cost of <b>[DisplayPower(POWER_WALL_TOTAL)]</b> power.</span>")
|
||||
to_chat(user, "<span class='alloy'>It has access to <b>[DisplayPower(get_clockwork_power())]</b> of power.</span>")
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/attack_self(mob/living/user)
|
||||
if(is_servant_of_ratvar(user))
|
||||
if(uses_power)
|
||||
if(!can_use_power(POWER_WALL_TOTAL))
|
||||
if(!get_clockwork_power(POWER_WALL_TOTAL))
|
||||
to_chat(user, "<span class='warning'>[src] requires <b>[DisplayPower(POWER_WALL_TOTAL)]</b> of power to produce brass sheets!</span>")
|
||||
return
|
||||
modify_stored_power(-POWER_WALL_TOTAL)
|
||||
adjust_clockwork_power(-POWER_WALL_TOTAL)
|
||||
playsound(src, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
new/obj/item/stack/tile/brass(user.loc, 5)
|
||||
to_chat(user, "<span class='brass'>You use [stored_power ? "some":"all"] of [src]'s power to produce <b>5</b> brass sheets. It now stores <b>[DisplayPower(get_power())]/[DisplayPower(get_max_power())]</b> of power.</span>")
|
||||
to_chat(user, "<span class='brass'>You use [get_clockwork_power() ? "some":"all"] of [src]'s power to produce <b>5</b> brass sheets. It now has access to <b>[DisplayPower(get_clockwork_power())]</b> of power.</span>")
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/pre_attackby(atom/target, mob/living/user, params)
|
||||
if(!target || !user || !is_servant_of_ratvar(user) || istype(target, /obj/item/storage))
|
||||
return TRUE
|
||||
return fabricate(target, user)
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/proc/get_power()
|
||||
return stored_power
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/proc/get_max_power()
|
||||
return max_power
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/proc/modify_stored_power(amount)
|
||||
stored_power = Clamp(stored_power + amount, 0, max_power)
|
||||
return TRUE
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/proc/can_use_power(amount)
|
||||
if(amount == RATVAR_POWER_CHECK)
|
||||
if(GLOB.ratvar_awakens || !uses_power)
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
if(stored_power - amount < 0)
|
||||
return FALSE
|
||||
if(stored_power - amount > max_power)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
//A note here; return values are for if we CAN BE PUT ON A TABLE, not IF WE ARE SUCCESSFUL, unless no_table_check is TRUE
|
||||
@@ -178,10 +80,6 @@
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>You are currently repairing [repairing] with [src]!</span>")
|
||||
return FALSE
|
||||
if(recharging)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>You are currently recharging [src] from the [recharging.sigil_name]!</span>")
|
||||
return FALSE
|
||||
var/list/fabrication_values = target.fabrication_vals(user, src, silent) //relevant values for fabricating stuff, given as an associated list
|
||||
if(!islist(fabrication_values))
|
||||
if(fabrication_values != TRUE) //if we get true, fail, but don't send a message for whatever reason
|
||||
@@ -192,7 +90,7 @@
|
||||
if(!no_table_check)
|
||||
return TRUE
|
||||
return FALSE
|
||||
if(can_use_power(RATVAR_POWER_CHECK))
|
||||
if(get_clockwork_power(RATVAR_POWER_CHECK))
|
||||
fabrication_values["power_cost"] = 0
|
||||
|
||||
var/turf/Y = get_turf(user)
|
||||
@@ -252,7 +150,7 @@
|
||||
A.setDir(fabrication_values["spawn_dir"])
|
||||
if(!fabrication_values["no_target_deletion"]) //for some cases where fabrication_vals() modifies the object but doesn't want it deleted
|
||||
qdel(target)
|
||||
modify_stored_power(-fabrication_values["power_cost"])
|
||||
adjust_clockwork_power(-fabrication_values["power_cost"])
|
||||
if(no_table_check)
|
||||
return TRUE
|
||||
return FALSE
|
||||
@@ -265,25 +163,18 @@
|
||||
/obj/item/clockwork/replica_fabricator/proc/fabricate_checks(list/fabrication_values, atom/target, expected_type, mob/user, silent) //checked constantly while fabricating
|
||||
if(!islist(fabrication_values) || QDELETED(target) || QDELETED(user))
|
||||
return FALSE
|
||||
if(repairing || recharging)
|
||||
if(repairing)
|
||||
return FALSE
|
||||
if(target.type != expected_type)
|
||||
return FALSE
|
||||
if(can_use_power(RATVAR_POWER_CHECK))
|
||||
if(get_clockwork_power(RATVAR_POWER_CHECK))
|
||||
fabrication_values["power_cost"] = 0
|
||||
if(!can_use_power(fabrication_values["power_cost"]))
|
||||
if(stored_power - fabrication_values["power_cost"] < 0)
|
||||
if(!get_clockwork_power(fabrication_values["power_cost"]))
|
||||
if(get_clockwork_power() - fabrication_values["power_cost"] < 0)
|
||||
if(!silent)
|
||||
var/atom/A = fabrication_values["new_obj_type"]
|
||||
if(A)
|
||||
to_chat(user, "<span class='warning'>You need <b>[DisplayPower(fabrication_values["power_cost"])]</b> power to fabricate \a [initial(A.name)] from [target]!</span>")
|
||||
else if(stored_power - fabrication_values["power_cost"] > max_power)
|
||||
if(!silent)
|
||||
var/atom/A = fabrication_values["new_obj_type"]
|
||||
if(A)
|
||||
to_chat(user, "<span class='warning'>Your [name] contains too much power to fabricate \a [initial(A.name)] from [target]!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Your [name] contains too much power to consume [target]!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -321,26 +212,9 @@
|
||||
return FALSE
|
||||
repair_values["healing_for_cycle"] = min(repair_values["amount_to_heal"], FABRICATOR_REPAIR_PER_TICK) //modify the healing for this cycle
|
||||
repair_values["power_required"] = round(repair_values["healing_for_cycle"]*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER) //and get the power cost from that
|
||||
if(!can_use_power(RATVAR_POWER_CHECK) && !can_use_power(repair_values["power_required"]))
|
||||
if(!get_clockwork_power(RATVAR_POWER_CHECK) && !get_clockwork_power(repair_values["power_required"]))
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>You need at least <b>[DisplayPower(repair_values["power_required"])]</b> power to start repairin[target == user ? "g yourself" : "g [target]"], and at least \
|
||||
<b>[DisplayPower(repair_values["amount_to_heal"]*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)]</b> to fully repair [target == user ? "yourself" : "[target.p_them()]"]!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
//The sigil charge check proc.
|
||||
/obj/item/clockwork/replica_fabricator/proc/sigil_charge_checks(list/charge_values, obj/effect/clockwork/sigil/transmission/sigil, mob/user, silent)
|
||||
if(!islist(charge_values) || QDELETED(sigil) || QDELETED(user))
|
||||
return FALSE
|
||||
if(can_use_power(RATVAR_POWER_CHECK))
|
||||
return FALSE
|
||||
charge_values["power_gain"] = Clamp(sigil.power_charge, 0, POWER_WALL_MINUS_FLOOR)
|
||||
if(!charge_values["power_gain"])
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>The [sigil.sigil_name] contains no power!</span>")
|
||||
return FALSE
|
||||
if(stored_power + charge_values["power_gain"] > max_power)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>Your [name] contains too much power to charge from the [sigil.sigil_name]!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
autoping = FALSE
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
force_replace_ai_name = TRUE
|
||||
overrides_aicore_laws = TRUE
|
||||
|
||||
/obj/item/device/mmi/posibrain/soul_vessel/Initialize()
|
||||
. = ..()
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
return
|
||||
set_vision_vars(TRUE)
|
||||
if(is_servant_of_ratvar(user))
|
||||
to_chat(user, "<span class='heavy_brass'>As you put on the spectacles, all is revealed to you.[GLOB.ratvar_awakens ? "" : " Your eyes begin to itch - you cannot do this for long."]</span>")
|
||||
to_chat(user, "<span class='heavy_brass'>As you put on the spectacles, all is revealed to you.[GLOB.ratvar_awakens || GLOB.ratvar_approaches ? "" : " Your eyes begin to itch - you cannot do this for long."]</span>")
|
||||
var/datum/status_effect/wraith_spectacles/WS = user.has_status_effect(STATUS_EFFECT_WRAITHSPECS)
|
||||
if(WS)
|
||||
WS.apply_eye_damage(user)
|
||||
@@ -138,7 +138,7 @@
|
||||
var/mob/living/carbon/human/H = owner
|
||||
var/glasses_right = istype(H.glasses, /obj/item/clothing/glasses/wraith_spectacles)
|
||||
var/obj/item/clothing/glasses/wraith_spectacles/WS = H.glasses
|
||||
if(glasses_right && !WS.up && !GLOB.ratvar_awakens)
|
||||
if(glasses_right && !WS.up && !GLOB.ratvar_awakens && !GLOB.ratvar_approaches)
|
||||
apply_eye_damage(H)
|
||||
else
|
||||
if(GLOB.ratvar_awakens)
|
||||
@@ -148,15 +148,15 @@
|
||||
eye_damage_done = 0
|
||||
else if(prob(50) && eye_damage_done)
|
||||
H.adjust_eye_damage(-1)
|
||||
eye_damage_done--
|
||||
eye_damage_done = max(0, eye_damage_done - 1)
|
||||
if(!eye_damage_done)
|
||||
qdel(src)
|
||||
|
||||
/datum/status_effect/wraith_spectacles/proc/apply_eye_damage(mob/living/carbon/human/H)
|
||||
if(H.disabilities & BLIND)
|
||||
return
|
||||
H.adjust_eye_damage(1)
|
||||
eye_damage_done++
|
||||
H.adjust_eye_damage(0.5)
|
||||
eye_damage_done += 0.5
|
||||
if(eye_damage_done >= 20)
|
||||
H.adjust_blurriness(2)
|
||||
if(eye_damage_done >= nearsight_breakpoint)
|
||||
|
||||
@@ -20,6 +20,11 @@
|
||||
light_color = "#E42742"
|
||||
death_sound = 'sound/magic/clockwork/anima_fragment_death.ogg'
|
||||
var/playstyle_string = "<span class='heavy_brass'>You are a bug, yell at whoever spawned you!</span>"
|
||||
var/empower_string = "<span class='heavy_brass'>You have nothing to empower, yell at the coders!</span>" //Shown to the mob when the herald beacon activates
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/Initialize()
|
||||
. = ..()
|
||||
update_values()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/get_spans()
|
||||
return ..() | SPAN_ROBOT
|
||||
@@ -28,6 +33,8 @@
|
||||
..()
|
||||
add_servant_of_ratvar(src, TRUE)
|
||||
to_chat(src, playstyle_string)
|
||||
if(GLOB.ratvar_approaches)
|
||||
to_chat(src, empower_string)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/ratvar_act()
|
||||
fully_heal(TRUE)
|
||||
@@ -50,3 +57,5 @@
|
||||
msg += "*---------*</span>"
|
||||
|
||||
to_chat(user, msg)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/proc/update_values() //This is called by certain things to check GLOB.ratvar_awakens and GLOB.ratvar_approaches
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
//Clockwork marauder: Slow but with high damage, resides inside of a servant. Created via the Memory Allocation scripture.
|
||||
//Clockwork marauder: A well-rounded frontline construct. Only one can exist for every two human servants.
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder
|
||||
name = "clockwork marauder"
|
||||
desc = "A stalwart apparition of a soldier, blazing with crimson flames. It's armed with a gladius and shield."
|
||||
desc = "The stalwart apparition of a soldier, blazing with crimson flames. It's armed with a gladius and shield."
|
||||
icon_state = "clockwork_marauder"
|
||||
health = 300
|
||||
maxHealth = 300
|
||||
speed = 1
|
||||
health = 150
|
||||
maxHealth = 150
|
||||
force_threshold = 8
|
||||
speed = 0
|
||||
obj_damage = 40
|
||||
melee_damage_lower = 12
|
||||
melee_damage_upper = 12
|
||||
@@ -14,145 +15,40 @@
|
||||
weather_immunities = list("lava")
|
||||
movement_type = FLYING
|
||||
loot = list(/obj/item/clockwork/component/geis_capacitor/fallen_armor)
|
||||
var/true_name = "Meme Master 69" //Required to call forth the marauder
|
||||
var/global/list/possible_true_names = list("Servant", "Warden", "Serf", "Page", "Usher", "Knave", "Vassal", "Escort")
|
||||
var/mob/living/host //The mob that the marauder is living inside of
|
||||
var/recovering = FALSE //If the marauder is recovering from recalling
|
||||
var/blockchance = 17 //chance to block attacks entirely
|
||||
var/counterchance = 30 //chance to counterattack after blocking
|
||||
var/static/list/damage_heal_order = list(OXY, BURN, BRUTE, TOX) //we heal our host's damage in this order
|
||||
light_range = 2
|
||||
light_power = 1.1
|
||||
playstyle_string = "<span class='sevtug'>You are a clockwork marauder</span><b>, a living extension of Sevtug's will. As a marauder, you are somewhat slow, but may block attacks, \
|
||||
and have a chance to also counter blocked melee attacks for extra damage, in addition to being immune to extreme temperatures and pressures. \
|
||||
Your primary goal is to serve the creature that you are now a part of. You can use <span class='sevtug_small'><i>:b</i></span> to communicate silently with your master, \
|
||||
but can only exit if your master calls your true name or if they are exceptionally damaged. \
|
||||
\n\n\
|
||||
Stay near your host to protect and heal them; being too far from your host will rapidly cause you massive damage. Recall to your host if you are too weak and believe you cannot continue \
|
||||
fighting safely. As a final note, you should probably avoid harming any fellow servants of Ratvar.</span>"
|
||||
playstyle_string = "<b><span class='neovgre'>You are a clockwork marauder,</span> a well-rounded frontline construct of Ratvar. Although you have no \
|
||||
unique abilities, you're a fearsome fighter in one-on-one combat, and your shield protects from projectiles!<br><br>Obey the Servants and do as they \
|
||||
tell you. Your primary goal is to defend the Ark from destruction; they are your allies in this, and should be protected from harm.</b>"
|
||||
empower_string = "<span class='neovgre'>The Anima Bulwark's power flows through you! Your weapon will strike harder, your armor is sturdier, and your shield is considerably more \
|
||||
likely to deflect shots.</span>"
|
||||
var/deflect_chance = 40 //Chance to deflect any given projectile (non-damaging energy projectiles are always deflected)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/Initialize()
|
||||
. = ..()
|
||||
true_name = pick(possible_true_names)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/Life()
|
||||
..()
|
||||
if(is_in_host())
|
||||
if(!is_servant_of_ratvar(host))
|
||||
emerge_from_host(FALSE, TRUE)
|
||||
unbind_from_host()
|
||||
return
|
||||
if(!GLOB.ratvar_awakens && host.stat == DEAD)
|
||||
death()
|
||||
return
|
||||
if(GLOB.ratvar_awakens)
|
||||
adjustHealth(-50)
|
||||
else
|
||||
adjustHealth(-10)
|
||||
if(!recovering)
|
||||
heal_host() //also heal our host if inside of them and we aren't recovering
|
||||
else if(health == maxHealth)
|
||||
to_chat(src, "<span class='userdanger'>Your strength has returned. You can once again come forward!</span>")
|
||||
to_chat(host, "<span class='userdanger'>Your marauder is now strong enough to come forward again!</span>")
|
||||
recovering = FALSE
|
||||
else
|
||||
if(GLOB.ratvar_awakens) //If Ratvar is alive, marauders don't need a host and are downright impossible to kill
|
||||
adjustHealth(-5)
|
||||
heal_host()
|
||||
else if(host)
|
||||
if(!is_servant_of_ratvar(host))
|
||||
unbind_from_host()
|
||||
return
|
||||
if(host.stat == DEAD)
|
||||
adjustHealth(50)
|
||||
to_chat(src, "<span class='userdanger'>Your host is dead!</span>")
|
||||
return
|
||||
if(z && host.z && z == host.z)
|
||||
switch(get_dist(get_turf(src), get_turf(host)))
|
||||
if(2)
|
||||
adjustHealth(-1)
|
||||
if(3)
|
||||
//EQUILIBRIUM
|
||||
if(4)
|
||||
adjustHealth(1)
|
||||
if(5)
|
||||
adjustHealth(3)
|
||||
if(6)
|
||||
adjustHealth(6)
|
||||
if(7)
|
||||
adjustHealth(9)
|
||||
if(8 to INFINITY)
|
||||
adjustHealth(15)
|
||||
to_chat(src, "<span class='userdanger'>You're too far from your host and rapidly taking damage!</span>")
|
||||
else //right next to or on top of host
|
||||
adjustHealth(-2)
|
||||
heal_host() //gradually heal host if nearby and host is very weak
|
||||
else //well then, you're not even in the same zlevel
|
||||
adjustHealth(15)
|
||||
to_chat(src, "<span class='userdanger'>You're too far from your host and rapidly taking damage!</span>")
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/update_values()
|
||||
if(GLOB.ratvar_awakens) //Massive attack damage bonuses and health increase, because Ratvar
|
||||
health = 300
|
||||
maxHealth = 300
|
||||
melee_damage_upper = 25
|
||||
melee_damage_lower = 25
|
||||
attacktext = "devastates"
|
||||
speed = -1
|
||||
obj_damage = 100
|
||||
else if(GLOB.ratvar_approaches) //Hefty health bonus and slight attack damage increase
|
||||
health = 200
|
||||
maxHealth = 200
|
||||
melee_damage_upper = 15
|
||||
melee_damage_lower = 15
|
||||
attacktext = "carves"
|
||||
obj_damage = 50
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/death(gibbed)
|
||||
emerge_from_host(FALSE, TRUE)
|
||||
unbind_from_host()
|
||||
visible_message("<span class='warning'>[src]'s equipment clatters lifelessly to the ground as the red flames within dissipate.</span>", \
|
||||
"<span class='userdanger'>Your equipment falls away. You feel a moment of confusion before your fragile form is annihilated.</span>")
|
||||
visible_message("<span class='danger'>[src]'s equipment clatters lifelessly to the ground as the red flames within dissipate.</span>", \
|
||||
"<span class='userdanger'>Dented and scratched, your armor falls away, and your fragile form breaks apart without its protection.</span>")
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
stat(null, "Current True Name: [true_name]")
|
||||
stat(null, "Host: [host ? host : "NONE"]")
|
||||
if(host)
|
||||
var/resulthealth = round((host.health / host.maxHealth) * 100, 0.5)
|
||||
if(iscarbon(host))
|
||||
resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)
|
||||
stat(null, "Host Health: [resulthealth]%")
|
||||
if(GLOB.ratvar_awakens)
|
||||
stat(null, "You are [recovering ? "un" : ""]able to deploy!")
|
||||
else
|
||||
if(resulthealth > MARAUDER_EMERGE_THRESHOLD)
|
||||
stat(null, "You are [recovering ? "unable to deploy" : "able to deploy on hearing your True Name"]!")
|
||||
else
|
||||
stat(null, "You are [recovering ? "unable to deploy" : "able to deploy to protect your host"]!")
|
||||
stat(null, "You do [melee_damage_upper] damage on melee attacks.")
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/Process_Spacemove(movement_dir = 0)
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/bind_to_host(mob/living/new_host)
|
||||
if(!new_host)
|
||||
return FALSE
|
||||
host = new_host
|
||||
var/datum/action/innate/summon_marauder/SM = new()
|
||||
SM.linked_marauder = src
|
||||
SM.Grant(host)
|
||||
var/datum/action/innate/linked_minds/LM = new()
|
||||
LM.linked_marauder = src
|
||||
LM.Grant(host)
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/unbind_from_host()
|
||||
if(host)
|
||||
for(var/datum/action/innate/summon_marauder/SM in host.actions)
|
||||
qdel(SM)
|
||||
for(var/datum/action/innate/linked_minds/LM in host.actions)
|
||||
qdel(LM)
|
||||
host = null
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//DAMAGE and FATIGUE
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/heal_host()
|
||||
if(!host)
|
||||
return
|
||||
var/resulthealth = round((host.health / host.maxHealth) * 100, 0.5)
|
||||
if(iscarbon(host))
|
||||
resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)
|
||||
if(GLOB.ratvar_awakens || resulthealth <= MARAUDER_EMERGE_THRESHOLD)
|
||||
new /obj/effect/temp_visual/heal(host.loc, "#AF0AAF")
|
||||
host.heal_ordered_damage(4, damage_heal_order)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
if(amount > 0)
|
||||
for(var/mob/living/L in view(2, src))
|
||||
@@ -161,269 +57,28 @@
|
||||
amount *= 4 //if a wielded null rod is nearby, it takes four times the health damage
|
||||
break
|
||||
. = ..()
|
||||
if(src && updating_health)
|
||||
update_health_hud()
|
||||
update_stats()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/update_health_hud()
|
||||
if(hud_used && hud_used.healths)
|
||||
if(istype(hud_used, /datum/hud/marauder))
|
||||
var/datum/hud/marauder/M = hud_used
|
||||
var/resulthealth
|
||||
if(host)
|
||||
if(iscarbon(host))
|
||||
resulthealth = "[round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)]%"
|
||||
else
|
||||
resulthealth = "[round((host.health / host.maxHealth) * 100, 0.5)]%"
|
||||
else
|
||||
resulthealth = "NONE"
|
||||
M.hosthealth.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#AF0AAF'>HOST<br>[resulthealth]</font></div>"
|
||||
hud_used.healths.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#AF0AAF'>[round((health / maxHealth) * 100, 0.5)]%</font>"
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/bullet_act(obj/item/projectile/P)
|
||||
if(deflect_projectile(P))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/update_stats()
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/deflect_projectile(obj/item/projectile/P)
|
||||
var/final_deflection_chance = deflect_chance
|
||||
var/energy_projectile = istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)
|
||||
if(P.nodamage || P.damage_type == STAMINA)
|
||||
final_deflection_chance = 100
|
||||
else if(!energy_projectile) //Flat 40% chance against energy projectiles; ballistic projectiles are 40% - (damage of projectile)%, min. 10%
|
||||
final_deflection_chance = max(10, deflect_chance - P.damage)
|
||||
if(GLOB.ratvar_awakens)
|
||||
speed = 0
|
||||
melee_damage_lower = 20
|
||||
melee_damage_upper = 20
|
||||
attacktext = "devastates"
|
||||
else
|
||||
var/healthpercent = (health/maxHealth) * 100
|
||||
switch(healthpercent)
|
||||
if(100 to 70) //Bonuses to speed and damage at high health
|
||||
speed = 0
|
||||
melee_damage_lower = 16
|
||||
melee_damage_upper = 16
|
||||
attacktext = "viciously slashes"
|
||||
if(70 to 40)
|
||||
speed = initial(speed)
|
||||
melee_damage_lower = initial(melee_damage_lower)
|
||||
melee_damage_upper = initial(melee_damage_upper)
|
||||
attacktext = initial(attacktext)
|
||||
if(40 to 30) //Damage decrease, but not speed
|
||||
speed = initial(speed)
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 10
|
||||
attacktext = "lightly slashes"
|
||||
if(30 to 20) //Speed decrease
|
||||
speed = 2
|
||||
melee_damage_lower = 8
|
||||
melee_damage_upper = 8
|
||||
attacktext = "lightly slashes"
|
||||
if(20 to 10) //Massive speed decrease and weak melee attacks
|
||||
speed = 3
|
||||
melee_damage_lower = 6
|
||||
melee_damage_upper = 6
|
||||
attacktext = "weakly slashes"
|
||||
if(10 to 0) //We are super weak and going to die
|
||||
speed = 4
|
||||
melee_damage_lower = 4
|
||||
melee_damage_upper = 4
|
||||
attacktext = "taps"
|
||||
|
||||
//ATTACKING, BLOCKING, and COUNTERING
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/AttackingTarget()
|
||||
if(is_in_host())
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/bullet_act(obj/item/projectile/Proj)
|
||||
if(blockOrCounter(null, Proj))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/hitby(atom/movable/AM, skipcatch, hitpush, blocked)
|
||||
if(blockOrCounter(null, AM))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/attack_animal(mob/living/simple_animal/M)
|
||||
if(istype(M, /mob/living/simple_animal/hostile/clockwork/marauder) || !blockOrCounter(M, M)) //we don't want infinite blockcounter loops if fighting another marauder
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/attack_paw(mob/living/carbon/monkey/M)
|
||||
if(!blockOrCounter(M, M))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/attack_alien(mob/living/carbon/alien/humanoid/M)
|
||||
if(!blockOrCounter(M, M))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/attack_slime(mob/living/simple_animal/slime/M)
|
||||
if(!blockOrCounter(M, M))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/attack_hand(mob/living/carbon/human/M)
|
||||
if(!blockOrCounter(M, M))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/nullrod) || !blockOrCounter(user, I))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/blockOrCounter(mob/target, atom/textobject)
|
||||
if(GLOB.ratvar_awakens) //if ratvar has woken, we block nearly everything at a very high chance
|
||||
blockchance = 90
|
||||
counterchance = 90
|
||||
if(prob(blockchance))
|
||||
final_deflection_chance = 100
|
||||
else if(GLOB.ratvar_approaches)
|
||||
final_deflection_chance = min(100, final_deflection_chance + 20) //20% bonus to deflection if the servants heralded Ratvar
|
||||
if(prob(final_deflection_chance))
|
||||
visible_message("<span class='danger'>[src] deflects [P] with their shield!</span>", \
|
||||
"<span class='danger'>You block [P] with your shield!</span>")
|
||||
if(energy_projectile)
|
||||
playsound(src, 'sound/weapons/effects/searwall.ogg', 50, TRUE)
|
||||
else
|
||||
playsound(src, "ricochet", 50, TRUE)
|
||||
. = TRUE
|
||||
if(target)
|
||||
target.do_attack_animation(src)
|
||||
target.changeNext_move(CLICK_CD_MELEE)
|
||||
blockchance = initial(blockchance)
|
||||
playsound(src, 'sound/magic/clockwork/fellowship_armory.ogg', 30, 1, 0, 1) //clang
|
||||
visible_message("<span class='boldannounce'>[src] blocks [target && isitem(textobject) ? "[target]'s [textobject.name]":"\the [textobject]"]!</span>", \
|
||||
"<span class='userdanger'>You block [target && isitem(textobject) ? "[target]'s [textobject.name]":"\the [textobject]"]!</span>")
|
||||
if(target && Adjacent(target))
|
||||
if(prob(counterchance))
|
||||
counterchance = initial(counterchance)
|
||||
var/previousattacktext = attacktext
|
||||
attacktext = "counters"
|
||||
UnarmedAttack(target)
|
||||
attacktext = previousattacktext
|
||||
else
|
||||
counterchance = min(counterchance + initial(counterchance), 100)
|
||||
else
|
||||
blockchance = min(blockchance + initial(blockchance), 100)
|
||||
if(GLOB.ratvar_awakens)
|
||||
blockchance = 90
|
||||
counterchance = 90
|
||||
|
||||
//COMMUNICATION and EMERGENCE
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/handle_inherent_channels(message, message_mode)
|
||||
if(host && (is_in_host() || message_mode == MODE_BINARY))
|
||||
marauder_comms(message)
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/marauder_comms(message)
|
||||
var/name_part = "<span class='sevtug'>[src] ([true_name])</span>"
|
||||
message = "<span class='sevtug_small'>\"[message]\"</span>" //Processed output
|
||||
to_chat(src, "[name_part]<span class='sevtug_small'>:</span> [message]")
|
||||
to_chat(host, "[name_part]<span class='sevtug_small'>:</span> [message]")
|
||||
for(var/M in GLOB.mob_list)
|
||||
if(isobserver(M))
|
||||
var/link = FOLLOW_LINK(M, src)
|
||||
to_chat(M, "[link] [name_part] <span class='sevtug_small'>(to</span> <span class='sevtug'>[findtextEx(host.name, host.real_name) ? "[host.name]" : "[host.real_name] (as [host.name])"]</span><span class='sevtug_small'>):</span> [message] ")
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/return_to_host()
|
||||
if(is_in_host())
|
||||
return FALSE
|
||||
if(!host)
|
||||
to_chat(src, "<span class='warning'>You don't have a host!</span>")
|
||||
return FALSE
|
||||
var/resulthealth = round((host.health / host.maxHealth) * 100, 0.5)
|
||||
if(iscarbon(host))
|
||||
resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)
|
||||
host.visible_message("<span class='warning'>[host]'s skin flashes crimson!</span>", "<span class='sevtug'>You feel [true_name]'s consciousness settle in your mind.</span>")
|
||||
visible_message("<span class='warning'>[src] suddenly disappears!</span>", "<span class='sevtug'>You return to [host].</span>")
|
||||
forceMove(host)
|
||||
if(resulthealth > MARAUDER_EMERGE_THRESHOLD && health != maxHealth)
|
||||
recovering = TRUE
|
||||
to_chat(src, "<span class='userdanger'>You have weakened and will need to recover before manifesting again!</span>")
|
||||
to_chat(host, "<span class='sevtug'>[true_name] has weakened and will need to recover before manifesting again!</span>")
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/try_emerge()
|
||||
if(!host)
|
||||
to_chat(src, "<span class='warning'>You don't have a host!</span>")
|
||||
return FALSE
|
||||
if(!GLOB.ratvar_awakens)
|
||||
var/resulthealth = round((host.health / host.maxHealth) * 100, 0.5)
|
||||
if(iscarbon(host))
|
||||
resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)
|
||||
if(host.stat != DEAD && resulthealth > MARAUDER_EMERGE_THRESHOLD) //if above 20 health, fails
|
||||
to_chat(src, "<span class='warning'>Your host must be at [MARAUDER_EMERGE_THRESHOLD]% or less health to emerge like this!</span>")
|
||||
return FALSE
|
||||
return emerge_from_host(FALSE)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/emerge_from_host(hostchosen, force) //Notice that this is a proc rather than a verb - marauders can NOT exit at will, but they CAN return
|
||||
if(!is_in_host())
|
||||
return FALSE
|
||||
if(!force && recovering)
|
||||
if(hostchosen)
|
||||
to_chat(host, "<span class='sevtug'>[true_name] is too weak to come forth!</span>")
|
||||
else
|
||||
to_chat(host, "<span class='sevtug'>[true_name] tries to emerge to protect you, but it's too weak!</span>")
|
||||
to_chat(src, "<span class='userdanger'>You try to come forth, but you're too weak!</span>")
|
||||
return FALSE
|
||||
if(!force)
|
||||
if(hostchosen) //marauder approved
|
||||
to_chat(host, "<span class='sevtug'>Your words echo with power as [true_name] emerges from your body!</span>")
|
||||
else
|
||||
to_chat(host, "<span class='sevtug'>[true_name] emerges from your body to protect you!</span>")
|
||||
forceMove(host.loc)
|
||||
visible_message("<span class='warning'>[host]'s skin glows red as [name] emerges from their body!</span>", "<span class='sevtug_small'>You exit the safety of [host]'s body!</span>")
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/get_alt_name()
|
||||
return " ([text2ratvar(true_name)])"
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/is_in_host() //Checks if the marauder is inside of their host
|
||||
return host && loc == host
|
||||
|
||||
//HOST ACTIONS
|
||||
|
||||
//Summon Marauder action: Calls forth or recalls your marauder
|
||||
/datum/action/innate/summon_marauder
|
||||
name = "Force Marauder to Emerge/Recall"
|
||||
desc = "Allows you to force your clockwork marauder to emerge or recall as required."
|
||||
button_icon_state = "clockwork_marauder"
|
||||
background_icon_state = "bg_clock"
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
buttontooltipstyle = "clockcult"
|
||||
var/mob/living/simple_animal/hostile/clockwork/marauder/linked_marauder
|
||||
var/static/list/defend_phrases = list("Defend me", "Come forth", "Assist me", "Protect me", "Give aid", "Help me")
|
||||
var/static/list/return_phrases = list("Return", "Return to me", "Your job is done", "You have served", "Come back", "Retreat")
|
||||
|
||||
/datum/action/innate/summon_marauder/IsAvailable()
|
||||
if(!linked_marauder)
|
||||
return FALSE
|
||||
if(isliving(owner))
|
||||
var/mob/living/L = owner
|
||||
if(!L.can_speak_vocal() || L.stat)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/summon_marauder/Activate()
|
||||
if(linked_marauder.is_in_host())
|
||||
clockwork_say(owner, text2ratvar("[pick(defend_phrases)], [linked_marauder.true_name]!"))
|
||||
linked_marauder.emerge_from_host(TRUE)
|
||||
else
|
||||
clockwork_say(owner, text2ratvar("[pick(return_phrases)], [linked_marauder.true_name]!"))
|
||||
linked_marauder.return_to_host()
|
||||
return TRUE
|
||||
|
||||
//Linked Minds action: talks to your marauder
|
||||
/datum/action/innate/linked_minds
|
||||
name = "Linked Minds"
|
||||
desc = "Allows you to silently communicate with your marauder."
|
||||
button_icon_state = "linked_minds"
|
||||
background_icon_state = "bg_clock"
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
buttontooltipstyle = "clockcult"
|
||||
var/mob/living/simple_animal/hostile/clockwork/marauder/linked_marauder
|
||||
|
||||
/datum/action/innate/linked_minds/IsAvailable()
|
||||
if(!linked_marauder)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/linked_minds/Activate()
|
||||
var/message = stripped_input(owner, "Enter a message to tell your marauder.", "Telepathy")
|
||||
if(!owner || !message)
|
||||
return FALSE
|
||||
if(!linked_marauder)
|
||||
to_chat(owner, "<span class='warning'>Your marauder seems to have been destroyed!</span>")
|
||||
return FALSE
|
||||
var/name_part = "<span class='sevtug'>Servant [findtextEx(owner.name, owner.real_name) ? "[owner.name]" : "[owner.real_name] (as [owner.name])"]</span>"
|
||||
message = "<span class='sevtug_small'>\"[message]\"</span>" //Processed output
|
||||
to_chat(owner, "[name_part]<span class='sevtug_small'>:</span> [message]")
|
||||
to_chat(linked_marauder, "[name_part]<span class='sevtug_small'>:</span> [message]")
|
||||
for(var/M in GLOB.mob_list)
|
||||
if(isobserver(M))
|
||||
var/link = FOLLOW_LINK(M, src)
|
||||
to_chat(M, "[link] [name_part] <span class='sevtug_small'>(to</span> <span class='sevtug'>[linked_marauder] ([linked_marauder.true_name])</span><span class='sevtug_small'>):</span> [message]")
|
||||
return TRUE
|
||||
|
||||
@@ -5,8 +5,6 @@ Pieces of scripture require certain follower counts, contruction value, and acti
|
||||
Drivers: Unlocked by default
|
||||
Scripts: 5 servants and a cache
|
||||
Applications: 8 servants, 3 caches, and 100 CV
|
||||
Revenant: 10 servants, 4 caches, and 200 CV
|
||||
Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or destroyed
|
||||
*/
|
||||
|
||||
/datum/clockwork_scripture
|
||||
@@ -15,7 +13,9 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or
|
||||
var/desc = "Ancient Ratvarian lore. This piece seems particularly mundane."
|
||||
var/list/invocations = list() //Spoken over time in the ancient language of Ratvar. See clock_unsorted.dm for more details on the language and how to make it.
|
||||
var/channel_time = 10 //In deciseconds, how long a ritual takes to chant
|
||||
var/list/consumed_components = list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 0, HIEROPHANT_ANSIBLE = 0) //Components consumed
|
||||
var/power_cost = 5 //In watts, how much a scripture takes to invoke
|
||||
var/special_power_text //If the scripture can use additional power to have a unique function, use this; put POWERCOST here to display the special power cost.
|
||||
var/special_power_cost //This should be a define in __DEFINES/clockcult.dm, such as ABSCOND_ABDUCTION_COST
|
||||
var/obj/item/clockwork/slab/slab //The parent clockwork slab
|
||||
var/mob/living/invoker //The slab's holder
|
||||
var/whispered = FALSE //If the invocation is whispered rather than spoken aloud
|
||||
@@ -29,11 +29,6 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or
|
||||
var/primary_component
|
||||
var/sort_priority = 1 //what position the scripture should have in a list of scripture. Should be based off of component costs/reqs, but you can't initial() lists.
|
||||
|
||||
//components the scripture used from a slab
|
||||
var/list/used_slab_components = list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 0, HIEROPHANT_ANSIBLE = 0)
|
||||
//components the scripture used from the global cache
|
||||
var/list/used_cache_components = list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 0, HIEROPHANT_ANSIBLE = 0)
|
||||
|
||||
//messages for offstation scripture recital, courtesy ratvar's generals(and neovgre)
|
||||
var/static/list/neovgre_penalty = list("Go to the station.", "Useless.", "Don't waste time.", "Pathetic.", "Wasteful.")
|
||||
var/static/list/inathneq_penalty = list("Child, this is too far out!", "The barrier isn't thin enough for for me to help!", "Please, go to the station so I can assist you.", \
|
||||
@@ -57,34 +52,14 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or
|
||||
if(slab.busy)
|
||||
to_chat(invoker, "<span class='warning'>[slab] refuses to work, displaying the message: \"[slab.busy]!\"</span>")
|
||||
return FALSE
|
||||
if(invoker.has_status_effect(STATUS_EFFECT_GEISTRACKER))
|
||||
to_chat(invoker, "<span class='warning'>[slab] refuses to work, displaying the message: \"Sustaining Geis!\"</span>")
|
||||
return FALSE
|
||||
slab.busy = "Invocation ([name]) in progress"
|
||||
if(GLOB.ratvar_awakens)
|
||||
channel_time *= 0.5 //if ratvar has awoken, half channel time and no cost
|
||||
else if(!slab.no_cost)
|
||||
for(var/i in consumed_components)
|
||||
if(consumed_components[i])
|
||||
for(var/j in 1 to consumed_components[i])
|
||||
if(slab.stored_components[i])
|
||||
slab.stored_components[i]--
|
||||
used_slab_components[i]++
|
||||
else
|
||||
GLOB.clockwork_component_cache[i]--
|
||||
used_cache_components[i]++
|
||||
update_slab_info()
|
||||
adjust_clockwork_power(-power_cost)
|
||||
channel_time *= slab.speed_multiplier
|
||||
if(!recital() || !check_special_requirements() || !scripture_effects()) //if we fail any of these, refund components used
|
||||
for(var/i in used_slab_components)
|
||||
if(used_slab_components[i])
|
||||
if(slab)
|
||||
slab.stored_components[i] += consumed_components[i]
|
||||
else //if we can't find a slab add to the global cache
|
||||
GLOB.clockwork_component_cache[i] += consumed_components[i]
|
||||
for(var/i in used_cache_components)
|
||||
if(used_cache_components[i])
|
||||
GLOB.clockwork_component_cache[i] += consumed_components[i]
|
||||
adjust_clockwork_power(power_cost)
|
||||
update_slab_info()
|
||||
else
|
||||
successful = TRUE
|
||||
@@ -92,6 +67,7 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or
|
||||
SSblackbox.add_details("clockcult_scripture_recited", name)
|
||||
if(slab)
|
||||
slab.busy = null
|
||||
post_recital()
|
||||
qdel(src)
|
||||
return successful
|
||||
|
||||
@@ -103,23 +79,13 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/proc/has_requirements() //if we have the components and invokers to do it
|
||||
/datum/clockwork_scripture/proc/has_requirements() //if we have the power and invokers to do it
|
||||
var/checked_penalty = FALSE
|
||||
if(!GLOB.ratvar_awakens && !slab.no_cost)
|
||||
checked_penalty = check_offstation_penalty()
|
||||
var/component_printout = "<span class='warning'>You lack the components to recite this piece of scripture!"
|
||||
var/failed = FALSE
|
||||
for(var/i in consumed_components)
|
||||
var/cache_components = GLOB.clockwork_caches ? GLOB.clockwork_component_cache[i] : 0
|
||||
var/total_components = slab.stored_components[i] + cache_components
|
||||
if(consumed_components[i] && total_components < consumed_components[i])
|
||||
component_printout += "\nYou have <span class='[get_component_span(i)]_small'><b>[total_components]/[consumed_components[i]]</b> \
|
||||
[get_component_name(i)][i != REPLICANT_ALLOY ? "s":""].</span>"
|
||||
failed = TRUE
|
||||
if(failed)
|
||||
component_printout += "</span>"
|
||||
to_chat(invoker, component_printout)
|
||||
return FALSE
|
||||
if(!get_clockwork_power(power_cost))
|
||||
to_chat(invoker, "<span class='warning'>There isn't enough power to recite this scripture! ([DisplayPower(get_clockwork_power())]/[DisplayPower(power_cost)])</span>")
|
||||
return
|
||||
if(multiple_invokers_used && !multiple_invokers_optional && !GLOB.ratvar_awakens && !slab.no_cost)
|
||||
var/nearby_servants = 0
|
||||
for(var/mob/living/L in range(1, get_turf(invoker)))
|
||||
@@ -158,13 +124,10 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or
|
||||
|
||||
/datum/clockwork_scripture/proc/check_offstation_penalty()
|
||||
var/turf/T = get_turf(invoker)
|
||||
if(!T || (!(T.z in GLOB.station_z_levels) && T.z != ZLEVEL_CENTCOM && T.z != ZLEVEL_MINING && T.z != ZLEVEL_LAVALAND))
|
||||
if(!T || (!(T.z in GLOB.station_z_levels) && T.z != ZLEVEL_CENTCOM && T.z != ZLEVEL_MINING && T.z != ZLEVEL_LAVALAND && T.z != ZLEVEL_CITYOFCOGS))
|
||||
channel_time *= 2
|
||||
for(var/i in consumed_components)
|
||||
if(consumed_components[i])
|
||||
consumed_components[i] *= 2
|
||||
power_cost *= 2
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/clockwork_scripture/proc/check_special_requirements() //Special requirements for scriptures, checked multiple times during invocation
|
||||
return TRUE
|
||||
@@ -185,6 +148,7 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or
|
||||
for(var/invocation in invocations)
|
||||
if(!do_after(invoker, channel_time / invocations.len, target = invoker, extra_checks = CALLBACK(src, .proc/check_special_requirements)))
|
||||
slab.busy = null
|
||||
scripture_fail()
|
||||
return FALSE
|
||||
if(multiple_invokers_used)
|
||||
for(var/mob/living/L in range(1, get_turf(invoker)))
|
||||
@@ -197,6 +161,11 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or
|
||||
/datum/clockwork_scripture/proc/scripture_effects() //The actual effects of the recital after its conclusion
|
||||
|
||||
|
||||
/datum/clockwork_scripture/proc/scripture_fail() //Called if the scripture fails to invoke.
|
||||
|
||||
|
||||
/datum/clockwork_scripture/proc/post_recital() //Called after the scripture is recited
|
||||
|
||||
//Channeled scripture begins instantly but runs constantly
|
||||
/datum/clockwork_scripture/channeled
|
||||
var/list/chant_invocations = list("AYY LMAO")
|
||||
@@ -228,6 +197,7 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or
|
||||
//Creates an object at the invoker's feet
|
||||
/datum/clockwork_scripture/create_object
|
||||
var/object_path = /obj/item/clockwork //The path of the object created
|
||||
var/put_object_in_hands = TRUE
|
||||
var/creator_message = "<span class='brass'>You create a meme.</span>" //Shown to the invoker
|
||||
var/observer_message
|
||||
var/one_per_tile = FALSE
|
||||
@@ -256,10 +226,51 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or
|
||||
to_chat(invoker, creator_message)
|
||||
var/obj/O = new object_path (get_turf(invoker))
|
||||
O.ratvar_act() //update the new object so it gets buffed if ratvar is alive
|
||||
if(isitem(O))
|
||||
if(isitem(O) && put_object_in_hands)
|
||||
invoker.put_in_hands(O)
|
||||
return TRUE
|
||||
|
||||
|
||||
//Used specifically to create construct shells.
|
||||
/datum/clockwork_scripture/create_object/construct
|
||||
put_object_in_hands = FALSE
|
||||
var/construct_type //The type of construct that the scripture is made to create, even if not directly
|
||||
var/construct_limit = 1 //How many constructs of this type can exist
|
||||
var/combat_construct = FALSE //If this construct is meant for fighting and shouldn't be at the base before the assault phase
|
||||
var/confirmed = FALSE //If we've confirmed that we want to make this construct outside of the station Z
|
||||
|
||||
/datum/clockwork_scripture/create_object/construct/check_special_requirements()
|
||||
update_construct_limit()
|
||||
var/constructs = get_constructs()
|
||||
if(constructs >= construct_limit)
|
||||
to_chat(invoker, "<span class='warning'>There are too many constructs of this type ([constructs])! You may only have [round(construct_limit)] at once.</span>")
|
||||
return
|
||||
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
|
||||
if(G && !G.active && combat_construct && invoker.z == ZLEVEL_CITYOFCOGS && !confirmed) //Putting marauders on the base during the prep phase is a bad idea mmkay
|
||||
if(alert(invoker, "This is a combat construct, and you cannot easily get it to the station. Are you sure you want to make one here?", "Construct Alert", "Yes", "Cancel") == "Cancel")
|
||||
return
|
||||
if(!is_servant_of_ratvar(invoker) || !invoker.canUseTopic(slab))
|
||||
return
|
||||
confirmed = TRUE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/create_object/construct/post_recital()
|
||||
creation_update()
|
||||
confirmed = FALSE
|
||||
|
||||
/datum/clockwork_scripture/create_object/construct/proc/get_constructs()
|
||||
var/constructs = 0
|
||||
for(var/V in GLOB.all_clockwork_mobs)
|
||||
if(istype(V, construct_type))
|
||||
constructs++
|
||||
for(var/V in GLOB.all_clockwork_objects)
|
||||
if(istype(V, object_path)) //nice try
|
||||
constructs++
|
||||
return constructs
|
||||
|
||||
/datum/clockwork_scripture/create_object/construct/proc/update_construct_limit() //Change this on a per-scripture basis, for dynamic limits
|
||||
|
||||
|
||||
//Uses a ranged slab ability, returning only when the ability no longer exists(ie, when interrupted) or finishes.
|
||||
/datum/clockwork_scripture/ranged_ability
|
||||
var/slab_overlay
|
||||
|
||||
@@ -2,173 +2,35 @@
|
||||
// APPLICATIONS //
|
||||
//////////////////
|
||||
|
||||
//Fellowship Armory: Arms the invoker and nearby servants with Ratvarian armor.
|
||||
/datum/clockwork_scripture/fellowship_armory
|
||||
descname = "Area Servant Armor"
|
||||
name = "Fellowship Armory"
|
||||
desc = "Equips the invoker and all visible Servants with Ratvarian armor. This armor provides high melee resistance but a weakness to lasers. \
|
||||
It grows faster to invoke with more adjacent Servants."
|
||||
invocations = list("Shield us...", "...with the...", "... fragments of Engine!")
|
||||
channel_time = 100
|
||||
consumed_components = list(VANGUARD_COGWHEEL = 4, REPLICANT_ALLOY = 2, HIEROPHANT_ANSIBLE = 2)
|
||||
usage_tip = "This scripture will replace all weaker armor worn by affected Servants."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
multiple_invokers_used = TRUE
|
||||
multiple_invokers_optional = TRUE
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 2
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Attempts to armor all nearby Servants with powerful Ratvarian armor."
|
||||
var/static/list/ratvarian_armor_typecache = typecacheof(list(
|
||||
/obj/item/clothing/suit/armor/clockwork,
|
||||
/obj/item/clothing/head/helmet/clockwork,
|
||||
/obj/item/clothing/gloves/clockwork,
|
||||
/obj/item/clothing/shoes/clockwork)) //don't replace this ever
|
||||
var/static/list/better_armor_typecache = typecacheof(list(
|
||||
/obj/item/clothing/suit/space,
|
||||
/obj/item/clothing/head/helmet/space,
|
||||
/obj/item/clothing/shoes/magboots)) //replace this only if ratvar is up
|
||||
|
||||
/datum/clockwork_scripture/fellowship_armory/run_scripture()
|
||||
for(var/mob/living/L in orange(1, invoker))
|
||||
if(can_recite_scripture(L))
|
||||
channel_time = max(channel_time - 10, 0)
|
||||
return ..()
|
||||
|
||||
/datum/clockwork_scripture/fellowship_armory/scripture_effects()
|
||||
var/affected = 0
|
||||
for(var/mob/living/L in view(7, get_turf(invoker)))
|
||||
if(L.stat == DEAD || !is_servant_of_ratvar(L))
|
||||
continue
|
||||
var/do_message = 0
|
||||
var/obj/item/I = L.get_item_by_slot(slot_wear_suit)
|
||||
if(remove_item_if_better(I, L))
|
||||
do_message += L.equip_to_slot_or_del(new/obj/item/clothing/suit/armor/clockwork(null), slot_wear_suit)
|
||||
I = L.get_item_by_slot(slot_head)
|
||||
if(remove_item_if_better(I, L))
|
||||
do_message += L.equip_to_slot_or_del(new/obj/item/clothing/head/helmet/clockwork(null), slot_head)
|
||||
I = L.get_item_by_slot(slot_gloves)
|
||||
if(remove_item_if_better(I, L))
|
||||
do_message += L.equip_to_slot_or_del(new/obj/item/clothing/gloves/clockwork(null), slot_gloves)
|
||||
I = L.get_item_by_slot(slot_shoes)
|
||||
if(remove_item_if_better(I, L))
|
||||
do_message += L.equip_to_slot_or_del(new/obj/item/clothing/shoes/clockwork(null), slot_shoes)
|
||||
if(do_message)
|
||||
L.visible_message("<span class='warning'>Strange armor appears on [L]!</span>", "<span class='heavy_brass'>A bright shimmer runs down your body, equipping you with Ratvarian armor.</span>")
|
||||
playsound(L, 'sound/magic/clockwork/fellowship_armory.ogg', 15*do_message, 1) //get sound loudness based on how much we equipped
|
||||
affected++
|
||||
return affected
|
||||
|
||||
/datum/clockwork_scripture/fellowship_armory/proc/remove_item_if_better(obj/item/I, mob/user)
|
||||
if(!I)
|
||||
return TRUE
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
return FALSE
|
||||
if(!GLOB.ratvar_awakens && is_type_in_typecache(I, better_armor_typecache))
|
||||
return FALSE
|
||||
return user.dropItemToGround(I)
|
||||
|
||||
//Memory Allocation: Finds a willing ghost and makes them into a clockwork marauders for the invoker.
|
||||
/datum/clockwork_scripture/memory_allocation
|
||||
descname = "Guardian"
|
||||
name = "Memory Allocation"
|
||||
desc = "Allocates part of your consciousness to a Clockwork Marauder, a vigilant fighter that lives within you, able to be \
|
||||
called forth by Speaking its True Name or if you become exceptionally low on health.<br>\
|
||||
If it remains close to you, you will gradually regain health up to a low amount, but it will die if it goes too far from you."
|
||||
invocations = list("Fright's will...", "...call forth...")
|
||||
channel_time = 100
|
||||
consumed_components = list(BELLIGERENT_EYE = 2, VANGUARD_COGWHEEL = 2, GEIS_CAPACITOR = 4)
|
||||
usage_tip = "Marauders are useful as personal bodyguards and frontline warriors."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 3
|
||||
|
||||
/datum/clockwork_scripture/memory_allocation/check_special_requirements()
|
||||
for(var/mob/living/simple_animal/hostile/clockwork/marauder/M in GLOB.all_clockwork_mobs)
|
||||
if(M.host == invoker)
|
||||
to_chat(invoker, "<span class='warning'>You can only house one marauder at a time!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/memory_allocation/scripture_effects()
|
||||
return create_marauder()
|
||||
|
||||
/datum/clockwork_scripture/memory_allocation/proc/create_marauder()
|
||||
invoker.visible_message("<span class='warning'>A purple tendril appears from [invoker]'s [slab.name] and impales itself in [invoker.p_their()] forehead!</span>", \
|
||||
"<span class='sevtug'>A tendril flies from [slab] into your forehead. You begin waiting while it painfully rearranges your thought pattern...</span>")
|
||||
invoker.notransform = TRUE //Vulnerable during the process
|
||||
slab.busy = "Thought Modification in progress"
|
||||
if(!do_after(invoker, 50, target = invoker))
|
||||
invoker.visible_message("<span class='warning'>The tendril, covered in blood, retracts from [invoker]'s head and back into the [slab.name]!</span>", \
|
||||
"<span class='userdanger'>Total agony overcomes you as the tendril is forced out early!</span>")
|
||||
invoker.notransform = FALSE
|
||||
invoker.Knockdown(100)
|
||||
invoker.apply_damage(10, BRUTE, "head")
|
||||
slab.busy = null
|
||||
return FALSE
|
||||
clockwork_say(invoker, text2ratvar("...the mind made..."))
|
||||
invoker.notransform = FALSE
|
||||
slab.busy = "Marauder Selection in progress"
|
||||
if(!check_special_requirements())
|
||||
return FALSE
|
||||
to_chat(invoker, "<span class='warning'>The tendril shivers slightly as it selects a marauder...</span>")
|
||||
var/list/marauder_candidates = pollGhostCandidates("Do you want to play as the clockwork marauder of [invoker.real_name]?", ROLE_SERVANT_OF_RATVAR, null, FALSE, 50, POLL_IGNORE_CLOCKWORK_MARAUDER)
|
||||
if(!check_special_requirements())
|
||||
return FALSE
|
||||
if(!marauder_candidates.len)
|
||||
invoker.visible_message("<span class='warning'>The tendril retracts from [invoker]'s head, sealing the entry wound as it does so!</span>", \
|
||||
"<span class='warning'>The tendril was unsuccessful! Perhaps you should try again another time.</span>")
|
||||
return FALSE
|
||||
clockwork_say(invoker, text2ratvar("...sword and shield!"))
|
||||
var/mob/dead/observer/theghost = pick(marauder_candidates)
|
||||
var/mob/living/simple_animal/hostile/clockwork/marauder/M = new(invoker)
|
||||
M.key = theghost.key
|
||||
M.bind_to_host(invoker)
|
||||
invoker.visible_message("<span class='warning'>The tendril retracts from [invoker]'s head, sealing the entry wound as it does so!</span>", \
|
||||
"<span class='sevtug'>[M.true_name], a clockwork marauder, has taken up residence in your mind. Communicate with it via the \"Linked Minds\" action button.</span>")
|
||||
return TRUE
|
||||
|
||||
|
||||
//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"
|
||||
name = "Sigil of Transmission"
|
||||
desc = "Places a sigil that can drain and will store energy to power clockwork structures."
|
||||
invocations = list("Divinity...", "...power our creations!")
|
||||
channel_time = 70
|
||||
consumed_components = list(VANGUARD_COGWHEEL = 2, GEIS_CAPACITOR = 2, HIEROPHANT_ANSIBLE = 4)
|
||||
whispered = TRUE
|
||||
object_path = /obj/effect/clockwork/sigil/transmission
|
||||
creator_message = "<span class='brass'>A sigil silently appears below you. It will automatically power clockwork structures near it and will drain power when activated.</span>"
|
||||
usage_tip = "Cyborgs can charge from this sigil by remaining over it for 5 seconds."
|
||||
//Clockwork Marauder: Creates a construct shell for a clockwork marauder, a well-rounded frontline fighter.
|
||||
/datum/clockwork_scripture/create_object/construct/clockwork_marauder
|
||||
descname = "Well-Rounded Combat Construct"
|
||||
name = "Clockwork Marauder"
|
||||
desc = "Creates a shell for a clockwork marauder, a balanced frontline construct."
|
||||
invocations = list("Arise, avatar of Arbiter!", "Defend the Ark with vengeful zeal.")
|
||||
channel_time = 50
|
||||
power_cost = 1000
|
||||
creator_message = "<span class='brass'>Your slab disgorges several chunks of replicant alloy that form into a suit of thrumming armor.</span>"
|
||||
usage_tip = "The marauder's shield can effectively deflect energy-based projectiles."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
one_per_tile = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 5
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 1
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Sigil of Transmission, which can drain and will store power for clockwork structures."
|
||||
quickbind_desc = "Creates a clockwork marauder, used for frontline combat."
|
||||
object_path = /obj/item/clockwork/construct_chassis/clockwork_marauder
|
||||
construct_type = /mob/living/simple_animal/hostile/clockwork/marauder
|
||||
combat_construct = TRUE
|
||||
|
||||
|
||||
//Prolonging Prism: Creates a prism that will delay the shuttle at a power cost
|
||||
/datum/clockwork_scripture/create_object/prolonging_prism
|
||||
descname = "Powered Structure, Delay Emergency Shuttles"
|
||||
name = "Prolonging Prism"
|
||||
desc = "Creates a mechanized prism which will delay the arrival of an emergency shuttle by 2 minutes at a massive power cost."
|
||||
invocations = list("May this prism...", "...grant us time to enact his will!")
|
||||
channel_time = 80
|
||||
consumed_components = list(VANGUARD_COGWHEEL = 5, GEIS_CAPACITOR = 2, REPLICANT_ALLOY = 2)
|
||||
object_path = /obj/structure/destructible/clockwork/powered/prolonging_prism
|
||||
creator_message = "<span class='brass'>You form a prolonging prism, which will delay the arrival of an emergency shuttle at a massive power cost.</span>"
|
||||
observer_message = "<span class='warning'>An onyx prism forms in midair and sprouts tendrils to support itself!</span>"
|
||||
invokers_required = 2
|
||||
multiple_invokers_used = TRUE
|
||||
usage_tip = "The power cost to delay a shuttle increases based on the number of times activated."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
one_per_tile = TRUE
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 7
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Prolonging Prism, which will delay the arrival of an emergency shuttle by 2 minutes at a massive power cost."
|
||||
/datum/clockwork_scripture/create_object/construct/clockwork_marauder/update_construct_limit()
|
||||
var/human_servants = 0
|
||||
for(var/V in SSticker.mode.servants_of_ratvar)
|
||||
var/datum/mind/M = V
|
||||
if(ishuman(M.current))
|
||||
human_servants++
|
||||
construct_limit = human_servants / 4 //1 per 4 human servants, and a maximum of 3 marauders
|
||||
construct_limit = Clamp(construct_limit, 1, 3)
|
||||
|
||||
/datum/clockwork_scripture/create_object/prolonging_prism/check_special_requirements()
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_IGNITING || SSshuttle.emergency.mode == SHUTTLE_STRANDED || SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
|
||||
@@ -188,7 +50,7 @@
|
||||
desc = "Creates a mania motor which causes minor damage and a variety of negative mental effects in nearby non-Servant humans, potentially up to and including conversion."
|
||||
invocations = list("May this transmitter...", "...break the will of all who oppose us!")
|
||||
channel_time = 80
|
||||
consumed_components = list(GEIS_CAPACITOR = 5, REPLICANT_ALLOY = 2, HIEROPHANT_ANSIBLE = 2)
|
||||
power_cost = 750
|
||||
object_path = /obj/structure/destructible/clockwork/powered/mania_motor
|
||||
creator_message = "<span class='brass'>You form a mania motor, which causes minor damage and negative mental effects in non-Servants.</span>"
|
||||
observer_message = "<span class='warning'>A two-pronged machine rises from the ground!</span>"
|
||||
@@ -198,31 +60,29 @@
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
one_per_tile = TRUE
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 8
|
||||
sort_priority = 2
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Mania Motor, which causes minor damage and negative mental effects in non-Servants."
|
||||
|
||||
|
||||
//Tinkerer's Daemon: Creates an efficient machine that rapidly produces components at a power cost.
|
||||
/datum/clockwork_scripture/create_object/tinkerers_daemon
|
||||
descname = "Powered Structure, Component Generator"
|
||||
name = "Tinkerer's Daemon"
|
||||
desc = "Creates a tinkerer's daemon which can rapidly collect components. It will only function if it has sufficient power, active daemons are outnumbered by Servants by a ratio of 5:1, \
|
||||
and there is at least one existing cache."
|
||||
invocations = list("May this generator...", "...collect Engine parts that yet hold greatness!")
|
||||
channel_time = 80
|
||||
consumed_components = list(BELLIGERENT_EYE = 2, GEIS_CAPACITOR = 2, REPLICANT_ALLOY = 5)
|
||||
object_path = /obj/structure/destructible/clockwork/powered/tinkerers_daemon
|
||||
creator_message = "<span class='brass'>You form a tinkerer's daemon which can rapidly collect components at a power cost.</span>"
|
||||
invokers_required = 2
|
||||
multiple_invokers_used = TRUE
|
||||
usage_tip = "Vital to your success!"
|
||||
//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"
|
||||
name = "Sigil of Transmission"
|
||||
desc = "Places a sigil that can drain and will store energy to power clockwork structures."
|
||||
invocations = list("Divinity...", "...power our creations!")
|
||||
channel_time = 70
|
||||
power_cost = 200
|
||||
whispered = TRUE
|
||||
object_path = /obj/effect/clockwork/sigil/transmission
|
||||
creator_message = "<span class='brass'>A sigil silently appears below you. It will automatically power clockwork structures near it and will drain power when activated.</span>"
|
||||
usage_tip = "Cyborgs can charge from this sigil by remaining over it for 5 seconds."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
one_per_tile = TRUE
|
||||
primary_component = REPLICANT_ALLOY
|
||||
sort_priority = 9
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 3
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Tinkerer's Daemon, which can rapidly collect components for power."
|
||||
quickbind_desc = "Creates a Sigil of Transmission, which can drain and will store power for clockwork structures."
|
||||
|
||||
|
||||
//Clockwork Obelisk: Creates a powerful obelisk that can be used to broadcast messages or open a gateway to any servant or clockwork obelisk at a power cost.
|
||||
@@ -232,7 +92,7 @@
|
||||
desc = "Creates a clockwork obelisk that can broadcast messages over the Hierophant Network or open a Spatial Gateway to any living Servant or clockwork obelisk."
|
||||
invocations = list("May this obelisk...", "...take us to all places!")
|
||||
channel_time = 80
|
||||
consumed_components = list(BELLIGERENT_EYE = 2, VANGUARD_COGWHEEL = 2, HIEROPHANT_ANSIBLE = 5)
|
||||
power_cost = 300
|
||||
object_path = /obj/structure/destructible/clockwork/powered/clockwork_obelisk
|
||||
creator_message = "<span class='brass'>You form a clockwork obelisk which can broadcast messages or produce Spatial Gateways.</span>"
|
||||
observer_message = "<span class='warning'>A brass obelisk appears hanging in midair!</span>"
|
||||
@@ -242,6 +102,6 @@
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
one_per_tile = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 10
|
||||
sort_priority = 4
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Clockwork Obelisk, which can send messages or open Spatial Gateways with power."
|
||||
|
||||
@@ -2,47 +2,47 @@
|
||||
// DRIVERS //
|
||||
/////////////
|
||||
|
||||
//Belligerent: Channeled for up to fifteen times over thirty seconds. Forces non-servants that can hear the chant to walk, doing minor damage. Nar-Sian cultists are burned.
|
||||
/datum/clockwork_scripture/channeled/belligerent
|
||||
descname = "Channeled, Area Slowdown"
|
||||
name = "Belligerent"
|
||||
desc = "Forces all nearby non-servants to walk rather than run, doing minor damage. Chanted every two seconds for up to thirty seconds."
|
||||
chant_invocations = list("Punish their blindness!", "Take time, make slow!")
|
||||
chant_amount = 15
|
||||
chant_interval = 20
|
||||
channel_time = 20
|
||||
usage_tip = "Useful for crowd control in a populated area and disrupting mass movement."
|
||||
//Hateful Manacles: Applies restraints from melee over several seconds. The restraints function like handcuffs and break on removal.
|
||||
/datum/clockwork_scripture/ranged_ability/hateful_manacles
|
||||
descname = "Handcuffs"
|
||||
name = "Hateful Manacles"
|
||||
desc = "Forms replicant manacles around a target's wrists that function like handcuffs."
|
||||
invocations = list("Shackle the heretic!", "Break them in body and spirit!")
|
||||
channel_time = 15
|
||||
power_cost = 25
|
||||
whispered = TRUE
|
||||
usage_tip = "The manacles are about as strong as zipties, and break when removed."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 1
|
||||
ranged_type = /obj/effect/proc_holder/slab/hateful_manacles
|
||||
slab_overlay = "hateful_manacles"
|
||||
ranged_message = "<span class='neovgre_small'><i>You charge the clockwork slab with divine energy.</i>\n\
|
||||
<b>Left-click a target within melee range to shackle!\n\
|
||||
Click your slab to cancel.</b></span>"
|
||||
timeout_time = 200
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Forces nearby non-Servants to walk, doing minor damage with each chant.<br><b>Maximum 15 chants.</b>"
|
||||
|
||||
/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
|
||||
quickbind_desc = "Applies handcuffs to a struck target."
|
||||
|
||||
|
||||
//Judicial Visor: Creates a judicial visor, which can smite an area.
|
||||
/datum/clockwork_scripture/create_object/judicial_visor
|
||||
descname = "Delayed Area Knockdown Glasses"
|
||||
name = "Judicial Visor"
|
||||
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)
|
||||
//Sigil of Transgression: Creates a sigil of transgression, which briefly stuns and applies Belligerent to the first non-servant to cross it.
|
||||
/datum/clockwork_scripture/create_object/sigil_of_transgression
|
||||
descname = "Trap, Stunning"
|
||||
name = "Sigil of Transgression"
|
||||
desc = "Wards a tile with a sigil, which will briefly stun the next non-Servant to cross it and apply Belligerent to them."
|
||||
invocations = list("Divinity, smite...", "...those who tresspass here!")
|
||||
channel_time = 50
|
||||
power_cost = 50
|
||||
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 a small area.</span>"
|
||||
usage_tip = "The visor has a thirty-second cooldown once used."
|
||||
object_path = /obj/effect/clockwork/sigil/transgression
|
||||
creator_message = "<span class='brass'>A sigil silently appears below you. The next non-Servant to cross it will be smitten.</span>"
|
||||
usage_tip = "The sigil does not silence its victim, and is generally used to soften potential converts or would-be invaders."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
space_allowed = TRUE
|
||||
one_per_tile = TRUE
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 2
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Judicial Visor, which can smite an area, applying Belligerent and briefly stunning."
|
||||
quickbind_desc = "Creates a Sigil of Transgression, which will briefly stun and slow the next non-Servant to cross it."
|
||||
|
||||
|
||||
//Vanguard: Provides twenty seconds of stun immunity. At the end of the twenty seconds, 25% of all stuns absorbed are applied to the invoker.
|
||||
@@ -53,6 +53,7 @@
|
||||
Excessive absorption will cause unconsciousness."
|
||||
invocations = list("Shield me...", "...from darkness!")
|
||||
channel_time = 30
|
||||
power_cost = 25
|
||||
usage_tip = "You cannot reactivate Vanguard while still shielded by it."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
@@ -84,7 +85,7 @@
|
||||
desc = "Charges your slab with healing power, allowing you to convert all of a target Servant's brute, burn, and oxygen damage to half as much toxin damage."
|
||||
invocations = list("Mend the wounds of...", "...my inferior flesh.")
|
||||
channel_time = 30
|
||||
consumed_components = list(VANGUARD_COGWHEEL = 1)
|
||||
power_cost = 100
|
||||
usage_tip = "The Compromise is very fast to invoke, and will remove holy water from the target Servant."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
@@ -98,38 +99,77 @@
|
||||
Click your slab to cancel.</b></span>"
|
||||
|
||||
|
||||
//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 and pull a struck heretic."
|
||||
invocations = list("Divinity, grant me strength...", "...to bind the heathen!")
|
||||
//Abscond: Used to return to Reebe.
|
||||
/datum/clockwork_scripture/abscond
|
||||
descname = "Return to Reebe"
|
||||
name = "Abscond"
|
||||
desc = "Yanks you through space, returning you to home base."
|
||||
invocations = list("As we bid farewell, and return to the stars...", "...we shall find our way home.")
|
||||
whispered = TRUE
|
||||
channel_time = 20
|
||||
usage_tip = "You CANNOT TAKE ANY NON-PULL ACTIONS while the target is bound, so Sigils of Submission should be placed before use."
|
||||
channel_time = 50
|
||||
power_cost = 5
|
||||
special_power_text = "POWERCOST to bring pulled creature"
|
||||
special_power_cost = ABSCOND_ABDUCTION_COST
|
||||
usage_tip = "This can't be used while on Reebe, for obvious reasons."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 5
|
||||
quickbind = TRUE
|
||||
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 bind!\n\
|
||||
Click your slab to cancel.</b></span>"
|
||||
timeout_time = 100
|
||||
quickbind_desc = "Returns you to Reebe."
|
||||
|
||||
/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)
|
||||
if(can_recite_scripture(M, TRUE))
|
||||
servants++
|
||||
if(servants > SCRIPT_SERVANT_REQ)
|
||||
whispered = FALSE
|
||||
servants -= SCRIPT_SERVANT_REQ
|
||||
channel_time = min(channel_time + servants*3, 50)
|
||||
return ..()
|
||||
/datum/clockwork_scripture/abscond/check_special_requirements()
|
||||
if(invoker.z == ZLEVEL_CITYOFCOGS)
|
||||
to_chat(invoker, "<span class='danger'>You're already at Reebe.</span>")
|
||||
return
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/abscond/recital()
|
||||
animate(invoker.client, color = "#AF0AAF", time = 50)
|
||||
. = ..()
|
||||
|
||||
/datum/clockwork_scripture/abscond/scripture_effects()
|
||||
var/take_pulling = invoker.pulling && isliving(invoker.pulling) && get_clockwork_power(ABSCOND_ABDUCTION_COST)
|
||||
var/turf/T = get_turf(pick(GLOB.servant_spawns))
|
||||
invoker.visible_message("<span class='warning'>[invoker] flickers and phases out of existence!</span>", \
|
||||
"<span class='bold sevtug_small'>You feel a dizzying sense of vertigo as you're yanked back to Reebe!</span>")
|
||||
T.visible_message("<span class='warning'>[invoker] flickers and phases into existence!</span>")
|
||||
playsound(invoker, 'sound/magic/magic_missile.ogg', 50, TRUE)
|
||||
playsound(T, 'sound/magic/magic_missile.ogg', 50, TRUE)
|
||||
do_sparks(5, TRUE, invoker)
|
||||
do_sparks(5, TRUE, T)
|
||||
if(take_pulling)
|
||||
adjust_clockwork_power(-special_power_cost)
|
||||
invoker.pulling.forceMove(T)
|
||||
invoker.forceMove(T)
|
||||
if(invoker.client)
|
||||
animate(invoker.client, color = initial(invoker.client.color), time = 25)
|
||||
|
||||
/datum/clockwork_scripture/abscond/scripture_fail()
|
||||
if(invoker && invoker.client)
|
||||
animate(invoker.client, color = initial(invoker.client.color), time = 10)
|
||||
|
||||
|
||||
//Kindle: Charges the slab with blazing energy. It can be released to stun and silence a target.
|
||||
/datum/clockwork_scripture/ranged_ability/kindle
|
||||
descname = "Short-Range Single-Target Stun"
|
||||
name = "Kindle"
|
||||
desc = "Charges your slab with divine energy, allowing you to overwhelm a target with Ratvar's light."
|
||||
invocations = list("Divinity, show them your light!")
|
||||
whispered = TRUE
|
||||
channel_time = 30
|
||||
power_cost = 125
|
||||
usage_tip = "The light can be used from up to two tiles away. Damage taken will GREATLY REDUCE the stun's duration."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 6
|
||||
slab_overlay = "volt"
|
||||
ranged_type = /obj/effect/proc_holder/slab/kindle
|
||||
ranged_message = "<span class='brass'><i>You charge the clockwork slab with divine energy.</i>\n\
|
||||
<b>Left-click a target within melee range to stun!\n\
|
||||
Click your slab to cancel.</b></span>"
|
||||
timeout_time = 150
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Stuns and mutes a target from a short range."
|
||||
|
||||
|
||||
//Sigil of Submission: Creates a sigil of submission, which converts one heretic above it after a delay.
|
||||
@@ -139,7 +179,7 @@
|
||||
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)
|
||||
power_cost = 125
|
||||
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>"
|
||||
@@ -159,6 +199,7 @@
|
||||
desc = "Creates a new clockwork slab."
|
||||
invocations = list("Metal, become greater!")
|
||||
channel_time = 10
|
||||
power_cost = 25
|
||||
whispered = TRUE
|
||||
object_path = /obj/item/clockwork/slab
|
||||
creator_message = "<span class='brass'>You copy a piece of replicant alloy and command it into a new slab.</span>"
|
||||
@@ -171,37 +212,44 @@
|
||||
quickbind_desc = "Creates a new Clockwork Slab."
|
||||
|
||||
|
||||
//Tinkerer's Cache: Creates a tinkerer's cache, allowing global component storage.
|
||||
/datum/clockwork_scripture/create_object/tinkerers_cache
|
||||
descname = "Necessary Structure, Shares Components"
|
||||
name = "Tinkerer's Cache"
|
||||
desc = "Forms a cache that can store an infinite amount of components. All caches are linked and will provide components to slabs. \
|
||||
Striking a cache with a slab will transfer that slab's components to the global cache."
|
||||
invocations = list("Constructing...", "...a cache!")
|
||||
//Stargazer: Creates a stargazer, a cheap power generator that utilizes starlight.
|
||||
/datum/clockwork_scripture/create_object/stargazer
|
||||
descname = "Necessary Structure, Generates Power From Starlight"
|
||||
name = "Stargazer"
|
||||
desc = "Forms a weak structure that generates power every second while within three tiles of starlight."
|
||||
invocations = list("Capture their inferior light for us!")
|
||||
channel_time = 50
|
||||
consumed_components = list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 0)
|
||||
object_path = /obj/structure/destructible/clockwork/cache
|
||||
creator_message = "<span class='brass'>You form a tinkerer's cache, which is capable of storing components, which will automatically be used by slabs.</span>"
|
||||
observer_message = "<span class='warning'>A hollow brass spire rises and begins to blaze!</span>"
|
||||
usage_tip = "Slabs will draw components from the global cache after the slab's own repositories, making caches extremely useful."
|
||||
power_cost = 50
|
||||
object_path = /obj/structure/destructible/clockwork/stargazer
|
||||
creator_message = "<span class='brass'>You form a stargazer, which will generate power near starlight.</span>"
|
||||
observer_message = "<span class='warning'>A large lantern-shaped machine forms!</span>"
|
||||
usage_tip = "For obvious reasons, make sure to place this near a window or somewhere else that can see space!"
|
||||
tier = SCRIPTURE_DRIVER
|
||||
one_per_tile = TRUE
|
||||
primary_component = REPLICANT_ALLOY
|
||||
sort_priority = 8
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Tinkerer's Cache, which stores components globally for slab access."
|
||||
var/static/prev_cost = 0
|
||||
quickbind_desc = "Creates a stargazer, which generates power when near starlight."
|
||||
|
||||
/datum/clockwork_scripture/create_object/tinkerers_cache/creation_update()
|
||||
var/cache_cost_increase = min(round(GLOB.clockwork_caches*0.4), 10)
|
||||
if(cache_cost_increase != prev_cost)
|
||||
prev_cost = cache_cost_increase
|
||||
consumed_components = list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 0)
|
||||
for(var/i in consumed_components)
|
||||
if(i != REPLICANT_ALLOY)
|
||||
consumed_components[i] += cache_cost_increase
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//Integration Cog: Creates an integration cog that can be inserted into APCs to passively siphon power.
|
||||
/datum/clockwork_scripture/create_object/integration_cog
|
||||
descname = "APC Power Siphoner"
|
||||
name = "Integration Cog"
|
||||
desc = "Fabricates an integration cog, which can be used on an open APC to replace its innards and passively siphon its power."
|
||||
invocations = list("Take that which sustains them!")
|
||||
channel_time = 10
|
||||
power_cost = 10
|
||||
whispered = TRUE
|
||||
object_path = /obj/item/clockwork/integration_cog
|
||||
creator_message = "<span class='brass'>You form an integration cog, which can be inserted into an open APC to passively siphon power.</span>"
|
||||
usage_tip = "Tampering isn't visible unless the APC is opened."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
space_allowed = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 9
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates an integration cog, which can be used to siphon power from an open APC."
|
||||
|
||||
|
||||
//Wraith Spectacles: Creates a pair of wraith spectacles, which grant xray vision but damage vision slowly.
|
||||
@@ -211,6 +259,7 @@
|
||||
desc = "Fabricates a pair of glasses which grant true sight but cause gradual vision loss."
|
||||
invocations = list("Show the truth of this world to me!")
|
||||
channel_time = 10
|
||||
power_cost = 50
|
||||
whispered = TRUE
|
||||
object_path = /obj/item/clothing/glasses/wraith_spectacles
|
||||
creator_message = "<span class='brass'>You form a pair of wraith spectacles, which grant true sight but cause gradual vision loss.</span>"
|
||||
@@ -218,26 +267,6 @@
|
||||
tier = SCRIPTURE_DRIVER
|
||||
space_allowed = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 9
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a pair of Wraith Spectacles, which grant true sight but cause gradual vision loss."
|
||||
|
||||
|
||||
//Sigil of Transgression: Creates a sigil of transgression, which stuns the first nonservant to cross it.
|
||||
/datum/clockwork_scripture/create_object/sigil_of_transgression
|
||||
descname = "Trap, Stunning"
|
||||
name = "Sigil of Transgression"
|
||||
desc = "Wards a tile with a sigil, which will stun the next non-Servant to cross it."
|
||||
invocations = list("Divinity, smite...", "...those who tresspass here!")
|
||||
channel_time = 50
|
||||
consumed_components = list(HIEROPHANT_ANSIBLE = 1)
|
||||
whispered = TRUE
|
||||
object_path = /obj/effect/clockwork/sigil/transgression
|
||||
creator_message = "<span class='brass'>A sigil silently appears below you. The next non-Servant to cross it will be stunned.</span>"
|
||||
usage_tip = "The sigil, while fairly powerful in its stun, does not induce muteness in its victim."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
one_per_tile = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 10
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Sigil of Transgression, which will stun the next non-Servant to cross it."
|
||||
quickbind_desc = "Creates a pair of Wraith Spectacles, which grant true sight but cause gradual vision loss."
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
///////////////
|
||||
// JUDGEMENT //
|
||||
///////////////
|
||||
|
||||
//Ark of the Clockwork Justiciar: Creates a Gateway to the Celestial Derelict, summoning ratvar.
|
||||
/datum/clockwork_scripture/create_object/ark_of_the_clockwork_justiciar
|
||||
descname = "Structure, Win Condition"
|
||||
name = "Ark of the Clockwork Justiciar"
|
||||
desc = "Tears apart a rift in spacetime to Reebe, the Celestial Derelict, using a massive amount of components.\n\
|
||||
This gateway will, after some time, call forth Ratvar from his exile and massively empower all scriptures and tools."
|
||||
invocations = list("ARMORER! FRIGHT! AMPERAGE! VANGUARD! I CALL UPON YOU!!", \
|
||||
"THE TIME HAS COME FOR OUR MASTER TO BREAK THE CHAINS OF EXILE!!", \
|
||||
"LEND US YOUR AID! ENGINE COMES!!")
|
||||
channel_time = 150
|
||||
consumed_components = list(BELLIGERENT_EYE = ARK_SUMMON_COST, VANGUARD_COGWHEEL = ARK_SUMMON_COST, GEIS_CAPACITOR = ARK_SUMMON_COST, REPLICANT_ALLOY = ARK_SUMMON_COST, HIEROPHANT_ANSIBLE = ARK_SUMMON_COST)
|
||||
invokers_required = 6
|
||||
multiple_invokers_used = TRUE
|
||||
object_path = /obj/structure/destructible/clockwork/massive/celestial_gateway
|
||||
creator_message = null
|
||||
usage_tip = "The gateway is completely vulnerable to attack during its five-minute duration. It will periodically give indication of its general position to everyone on the station \
|
||||
as well as being loud enough to be heard throughout the entire sector. Defend it with your life!"
|
||||
tier = SCRIPTURE_JUDGEMENT
|
||||
sort_priority = 1
|
||||
|
||||
/datum/clockwork_scripture/create_object/ark_of_the_clockwork_justiciar/check_special_requirements()
|
||||
if(!slab.no_cost)
|
||||
if(GLOB.ratvar_awakens)
|
||||
to_chat(invoker, "<span class='big_brass'>\"I am already here, idiot.\"</span>")
|
||||
return FALSE
|
||||
for(var/obj/structure/destructible/clockwork/massive/celestial_gateway/G in GLOB.all_clockwork_objects)
|
||||
var/area/gate_area = get_area(G)
|
||||
to_chat(invoker, "<span class='userdanger'>There is already an Ark at [gate_area.map_name]!</span>")
|
||||
return FALSE
|
||||
var/area/A = get_area(invoker)
|
||||
var/turf/T = get_turf(invoker)
|
||||
if(!T || !(T.z in GLOB.station_z_levels) || istype(A, /area/shuttle) || !A.blob_allowed)
|
||||
to_chat(invoker, "<span class='warning'>You must be on the station to activate the Ark!</span>")
|
||||
return FALSE
|
||||
if(GLOB.clockwork_gateway_activated)
|
||||
to_chat(invoker, "<span class='warning'>Ratvar's recent banishment renders him too weak to be wrung forth from Reebe!</span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
@@ -7,9 +7,9 @@
|
||||
descname = "Structure, Turret"
|
||||
name = "Ocular Warden"
|
||||
desc = "Forms an automatic short-range turret which will automatically attack nearby unrestrained non-Servants that can see it."
|
||||
invocations = list("Guardians...", "...of the Engine...", "...defend us!")
|
||||
channel_time = 120
|
||||
consumed_components = list(BELLIGERENT_EYE = 2, REPLICANT_ALLOY = 1)
|
||||
invocations = list("Guardians of Engine...", "...judge those who would harm us!")
|
||||
channel_time = 100
|
||||
power_cost = 250
|
||||
object_path = /obj/structure/destructible/clockwork/ocular_warden
|
||||
creator_message = "<span class='brass'>You form an ocular warden, which will automatically attack nearby unrestrained non-Servants that can see it.</span>"
|
||||
observer_message = "<span class='warning'>A brass eye takes shape and slowly rises into the air, its red iris glaring!</span>"
|
||||
@@ -29,15 +29,35 @@
|
||||
return ..()
|
||||
|
||||
|
||||
//Judicial Visor: Creates a judicial visor, which can smite an area.
|
||||
/datum/clockwork_scripture/create_object/judicial_visor
|
||||
descname = "Delayed Area Knockdown Glasses"
|
||||
name = "Judicial Visor"
|
||||
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
|
||||
power_cost = 400
|
||||
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 a small area.</span>"
|
||||
usage_tip = "The visor has a thirty-second cooldown once used."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
space_allowed = TRUE
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 2
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Judicial Visor, which can smite an area, applying Belligerent and briefly stunning."
|
||||
|
||||
|
||||
//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, 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!")
|
||||
invocations = list("Divinity, siphon their essence...", "...for this shell to consume.")
|
||||
channel_time = 60
|
||||
consumed_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 2)
|
||||
power_cost = 1000
|
||||
whispered = TRUE
|
||||
object_path = /obj/effect/clockwork/sigil/vitality
|
||||
creator_message = "<span class='brass'>A vitality matrix appears below you. It will drain life from non-Servants and heal Servants that cross it.</span>"
|
||||
@@ -58,7 +78,7 @@
|
||||
chant_invocations = list("Mend our dents!", "Heal our scratches!", "Repair our gears!")
|
||||
chant_amount = 10
|
||||
chant_interval = 20
|
||||
consumed_components = list(VANGUARD_COGWHEEL = 2, REPLICANT_ALLOY = 1)
|
||||
power_cost = 1000
|
||||
usage_tip = "This is a very effective way to rapidly reinforce a base after an attack."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
@@ -169,76 +189,115 @@
|
||||
desc = "Forms a device that, when used on certain objects, replaces them with their Ratvarian equivalents. It requires power to function."
|
||||
invocations = list("With this device...", "...his presence shall be made known.")
|
||||
channel_time = 20
|
||||
consumed_components = list(GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 2)
|
||||
power_cost = 250
|
||||
whispered = TRUE
|
||||
object_path = /obj/item/clockwork/replica_fabricator/preloaded
|
||||
object_path = /obj/item/clockwork/replica_fabricator
|
||||
creator_message = "<span class='brass'>You form a replica fabricator.</span>"
|
||||
usage_tip = "Clockwork Walls cause nearby Tinkerer's Caches to generate components passively, making this a vital tool. Clockwork Floors heal toxin damage in Servants standing on them."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
space_allowed = TRUE
|
||||
primary_component = REPLICANT_ALLOY
|
||||
sort_priority = 7
|
||||
sort_priority = 5
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Replica Fabricator, which can convert various objects to Ratvarian variants."
|
||||
|
||||
|
||||
//Function Call: Grants the invoker the ability to call forth a Ratvarian spear that deals significant damage to silicons.
|
||||
/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 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!")
|
||||
//Clockwork Arnaments: Grants the invoker the ability to call forth a Ratvarian spear and clockwork armor.
|
||||
/datum/clockwork_scripture/clockwork_arnaments
|
||||
descname = "Summonable Armor and Weapons"
|
||||
name = "Clockwork Arnaments"
|
||||
desc = "Allows the invoker to summon clockwork armor and a Ratvarian spear at will. The spear's attacks will generate Vitality, used for healing."
|
||||
invocations = list("Grant me arnaments...", "...from the forge of Armorer!")
|
||||
channel_time = 20
|
||||
consumed_components = list(REPLICANT_ALLOY = 2, HIEROPHANT_ANSIBLE = 1)
|
||||
power_cost = 250
|
||||
whispered = TRUE
|
||||
usage_tip = "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. You will need to wait for 30 seconds before resummoning it."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = REPLICANT_ALLOY
|
||||
sort_priority = 8
|
||||
sort_priority = 6
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Permanently binds clockwork armor and a Ratvarian spear to you."
|
||||
|
||||
/datum/clockwork_scripture/function_call/check_special_requirements()
|
||||
for(var/datum/action/innate/function_call/F in invoker.actions)
|
||||
/datum/clockwork_scripture/clockwork_arnaments/check_special_requirements()
|
||||
for(var/datum/action/innate/clockwork_arnaments/F in invoker.actions)
|
||||
to_chat(invoker, "<span class='warning'>You have already bound a Ratvarian spear to yourself!</span>")
|
||||
return FALSE
|
||||
return invoker.can_hold_items()
|
||||
|
||||
/datum/clockwork_scripture/function_call/scripture_effects()
|
||||
/datum/clockwork_scripture/clockwork_arnaments/scripture_effects()
|
||||
invoker.visible_message("<span class='warning'>A shimmer of yellow light infuses [invoker]!</span>", \
|
||||
"<span class='brass'>You bind a Ratvarian spear to yourself. Use the \"Function Call\" action button to call it forth.</span>")
|
||||
var/datum/action/innate/function_call/F = new()
|
||||
F.Grant(invoker)
|
||||
"<span class='brass'>You bind clockwork equipment to yourself. Use Clockwork Arnaments and Call Spear to summon them.</span>")
|
||||
var/datum/action/innate/call_weapon/ratvarian_spear/S = new()
|
||||
S.Grant(invoker)
|
||||
var/datum/action/innate/clockwork_arnaments/A = new()
|
||||
A.Grant(invoker)
|
||||
return TRUE
|
||||
|
||||
//Function Call action: Calls forth a Ratvarian spear once every 3 minutes.
|
||||
/datum/action/innate/function_call
|
||||
name = "Function Call"
|
||||
desc = "Allows you to summon a Ratvarian spear to fight enemies."
|
||||
button_icon_state = "ratvarian_spear"
|
||||
//Clockwork Arnaments: Equips a set of clockwork armor. Three-minute cooldown.
|
||||
/datum/action/innate/clockwork_arnaments
|
||||
name = "Clockwork Arnaments"
|
||||
desc = "Outfits you in a full set of Ratvarian armor."
|
||||
icon_icon = 'icons/mob/actions/actions_clockcult.dmi'
|
||||
button_icon_state = "clockwork_armor"
|
||||
background_icon_state = "bg_clock"
|
||||
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
|
||||
buttontooltipstyle = "clockcult"
|
||||
var/cooldown = 0
|
||||
var/base_cooldown = RATVARIAN_SPEAR_DURATION
|
||||
var/static/list/ratvarian_armor_typecache = typecacheof(list(
|
||||
/obj/item/clothing/suit/armor/clockwork,
|
||||
/obj/item/clothing/head/helmet/clockwork,
|
||||
/obj/item/clothing/gloves/clockwork,
|
||||
/obj/item/clothing/shoes/clockwork)) //don't replace this ever
|
||||
var/static/list/better_armor_typecache = typecacheof(list(
|
||||
/obj/item/clothing/suit/space,
|
||||
/obj/item/clothing/head/helmet/space,
|
||||
/obj/item/clothing/shoes/magboots)) //replace this only if ratvar is up
|
||||
|
||||
/datum/action/innate/function_call/IsAvailable()
|
||||
if(!is_servant_of_ratvar(owner) || cooldown > world.time)
|
||||
return FALSE
|
||||
/datum/action/innate/clockwork_arnaments/IsAvailable()
|
||||
if(!is_servant_of_ratvar(owner))
|
||||
qdel(src)
|
||||
return
|
||||
if(cooldown > world.time)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/function_call/Activate()
|
||||
if(!owner.get_empty_held_indexes())
|
||||
to_chat(usr, "<span class='warning'>You need an empty hand to call forth your spear!</span>")
|
||||
return FALSE
|
||||
owner.visible_message("<span class='warning'>A strange spear materializes in [owner]'s hands!</span>", "<span class='brass'>You call forth your spear!</span>")
|
||||
var/obj/item/clockwork/ratvarian_spear/R = new(get_turf(usr))
|
||||
owner.put_in_hands(R)
|
||||
if(!GLOB.ratvar_awakens)
|
||||
to_chat(owner, "<span class='warning'>Your spear begins to break down in this plane of existence. You can't use it for long!</span>")
|
||||
cooldown = base_cooldown + world.time
|
||||
/datum/action/innate/clockwork_arnaments/Activate()
|
||||
var/do_message = 0
|
||||
var/obj/item/I = owner.get_item_by_slot(slot_wear_suit)
|
||||
if(remove_item_if_better(I, owner))
|
||||
do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/suit/armor/clockwork(null), slot_wear_suit)
|
||||
I = owner.get_item_by_slot(slot_head)
|
||||
if(remove_item_if_better(I, owner))
|
||||
do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/head/helmet/clockwork(null), slot_head)
|
||||
I = owner.get_item_by_slot(slot_gloves)
|
||||
if(remove_item_if_better(I, owner))
|
||||
do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/gloves/clockwork(null), slot_gloves)
|
||||
I = owner.get_item_by_slot(slot_shoes)
|
||||
if(remove_item_if_better(I, owner))
|
||||
do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/shoes/clockwork(null), slot_shoes)
|
||||
if(do_message)
|
||||
owner.visible_message("<span class='warning'>Strange armor appears on [owner]!</span>", "<span class='heavy_brass'>A bright shimmer runs down your body, equipping you with Ratvarian armor.</span>")
|
||||
playsound(owner, 'sound/magic/clockwork/fellowship_armory.ogg', 15 * do_message, TRUE) //get sound loudness based on how much we equipped
|
||||
cooldown = CLOCKWORK_ARMOR_COOLDOWN + world.time
|
||||
owner.update_action_buttons_icon()
|
||||
addtimer(CALLBACK(owner, /mob.proc/update_action_buttons_icon), base_cooldown)
|
||||
addtimer(CALLBACK(owner, /mob.proc/update_action_buttons_icon), CLOCKWORK_ARMOR_COOLDOWN)
|
||||
return TRUE
|
||||
|
||||
/datum/action/innate/clockwork_arnaments/proc/remove_item_if_better(obj/item/I, mob/user)
|
||||
if(!I)
|
||||
return TRUE
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
return FALSE
|
||||
if(!GLOB.ratvar_awakens && is_type_in_typecache(I, better_armor_typecache))
|
||||
return FALSE
|
||||
return user.dropItemToGround(I)
|
||||
|
||||
//Call Spear: Calls forth a powerful Ratvarian spear.
|
||||
/datum/action/innate/call_weapon/ratvarian_spear
|
||||
name = "Call Spear"
|
||||
desc = "Calls a Ratvarian spear into your hands to fight your enemies."
|
||||
weapon_type = /obj/item/clockwork/weapon/ratvarian_spear
|
||||
|
||||
|
||||
//Spatial Gateway: Allows the invoker to teleport themselves and any nearby allies to a conscious servant or clockwork obelisk.
|
||||
/datum/clockwork_scripture/spatial_gateway
|
||||
@@ -248,7 +307,7 @@
|
||||
Each servant assisting in the invocation adds one additional use and four additional seconds to the gateway's uses and duration."
|
||||
invocations = list("Spatial Gateway...", "...activate!")
|
||||
channel_time = 80
|
||||
consumed_components = list(VANGUARD_COGWHEEL = 1, HIEROPHANT_ANSIBLE = 2)
|
||||
power_cost = 400
|
||||
multiple_invokers_used = TRUE
|
||||
multiple_invokers_optional = TRUE
|
||||
usage_tip = "This gateway is strictly one-way and will only allow things through the invoker's portal."
|
||||
@@ -285,3 +344,4 @@
|
||||
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)
|
||||
|
||||
|
||||
@@ -77,14 +77,10 @@
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/proc/get_efficiency_mod(increasing)
|
||||
/obj/structure/destructible/clockwork/proc/get_efficiency_mod()
|
||||
if(GLOB.ratvar_awakens)
|
||||
if(increasing)
|
||||
return 0.5
|
||||
return 2
|
||||
. = max(sqrt(obj_integrity/max(max_integrity, 1)), 0.5)
|
||||
if(increasing)
|
||||
. *= min(max_integrity/max(obj_integrity, 1), 4)
|
||||
. = round(., 0.01)
|
||||
|
||||
/obj/structure/destructible/clockwork/attack_ai(mob/user)
|
||||
@@ -116,7 +112,7 @@
|
||||
else
|
||||
icon_state = unanchored_icon
|
||||
if(do_damage)
|
||||
playsound(src, break_sound, 10 * get_efficiency_mod(TRUE), 1)
|
||||
playsound(src, break_sound, 10 * (40 * (1 - get_efficiency_mod())), 1)
|
||||
take_damage(round(max_integrity * 0.25, 1), BRUTE)
|
||||
to_chat(user, "<span class='warning'>As you unsecure [src] from the floor, you see cracks appear in its surface!</span>")
|
||||
|
||||
@@ -158,10 +154,10 @@
|
||||
/obj/structure/destructible/clockwork/powered/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
var/powered = total_accessable_power()
|
||||
var/sigil_number = LAZYLEN(check_apc_and_sigils())
|
||||
to_chat(user, "<span class='[powered ? "brass":"alloy"]'>It has access to <b>[powered == INFINITY ? "INFINITE</b>":"[DisplayPower(powered)]</b> of"] power, \
|
||||
and <b>[sigil_number]</b> Sigil[sigil_number == 1 ? "":"s"] of Transmission [sigil_number == 1 ? "is":"are"] in range.</span>")
|
||||
if(!can_access_clockwork_power(src))
|
||||
to_chat(user, "<span class='alloy'>It has no access to the power network! Create a sigil of transmission nearby.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='brass'>It has access to <b>[DisplayPower(get_clockwork_power())]</b> of power.</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/Destroy()
|
||||
SSfastprocess.processing -= src
|
||||
@@ -169,7 +165,7 @@
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/process()
|
||||
var/powered = total_accessable_power()
|
||||
var/powered = can_access_clockwork_power(src)
|
||||
return powered == PROCESS_KILL ? 25 : powered //make sure we don't accidentally return the arbitrary PROCESS_KILL define
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/can_be_unfasten_wrench(mob/user, silent)
|
||||
@@ -210,102 +206,12 @@
|
||||
if(forced_disable(TRUE))
|
||||
new /obj/effect/temp_visual/emp(loc)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/total_accessable_power() //how much power we have and can use
|
||||
if(!needs_power || GLOB.ratvar_awakens)
|
||||
return INFINITY //oh yeah we've got power why'd you ask
|
||||
|
||||
var/power = 0
|
||||
power += accessable_apc_power()
|
||||
power += accessable_sigil_power()
|
||||
return power
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/accessable_apc_power()
|
||||
var/power = 0
|
||||
var/area/A = get_area(src)
|
||||
var/area/targetAPCA
|
||||
for(var/obj/machinery/power/apc/APC in GLOB.apcs_list)
|
||||
var/area/APCA = get_area(APC)
|
||||
if(APCA == A)
|
||||
target_apc = APC
|
||||
if(target_apc)
|
||||
targetAPCA = get_area(target_apc)
|
||||
if(targetAPCA != A)
|
||||
target_apc = null
|
||||
else if(target_apc.cell)
|
||||
var/apccharge = target_apc.cell.charge
|
||||
if(apccharge >= MIN_CLOCKCULT_POWER)
|
||||
power += apccharge
|
||||
return power
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/accessable_sigil_power()
|
||||
var/power = 0
|
||||
for(var/obj/effect/clockwork/sigil/transmission/T in range(SIGIL_ACCESS_RANGE, src))
|
||||
power += T.power_charge
|
||||
return power
|
||||
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/try_use_power(amount) //try to use an amount of power
|
||||
if(!needs_power || GLOB.ratvar_awakens)
|
||||
return 1
|
||||
if(amount <= 0)
|
||||
return FALSE
|
||||
var/power = total_accessable_power()
|
||||
if(!power || power < amount)
|
||||
return FALSE
|
||||
if(!needs_power || GLOB.ratvar_awakens || !amount)
|
||||
return TRUE
|
||||
if(!can_access_clockwork_power(src, amount))
|
||||
return
|
||||
return use_power(amount)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/use_power(amount) //we've made sure we had power, so now we use it
|
||||
var/sigilpower = accessable_sigil_power()
|
||||
var/list/sigils_in_range = list()
|
||||
for(var/obj/effect/clockwork/sigil/transmission/T in range(SIGIL_ACCESS_RANGE, src))
|
||||
sigils_in_range += T
|
||||
while(sigilpower && amount >= MIN_CLOCKCULT_POWER)
|
||||
for(var/S in sigils_in_range)
|
||||
var/obj/effect/clockwork/sigil/transmission/T = S
|
||||
if(amount >= MIN_CLOCKCULT_POWER && T.modify_charge(MIN_CLOCKCULT_POWER))
|
||||
sigilpower -= MIN_CLOCKCULT_POWER
|
||||
amount -= MIN_CLOCKCULT_POWER
|
||||
var/apcpower = accessable_apc_power()
|
||||
while(apcpower >= MIN_CLOCKCULT_POWER && amount >= MIN_CLOCKCULT_POWER)
|
||||
if(target_apc.cell.use(MIN_CLOCKCULT_POWER))
|
||||
apcpower -= MIN_CLOCKCULT_POWER
|
||||
amount -= MIN_CLOCKCULT_POWER
|
||||
target_apc.charging = 1
|
||||
target_apc.chargemode = TRUE
|
||||
target_apc.update()
|
||||
target_apc.update_icon()
|
||||
target_apc.updateUsrDialog()
|
||||
else
|
||||
apcpower = 0
|
||||
if(amount)
|
||||
return FALSE
|
||||
else
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/return_power(amount) //returns a given amount of power to all nearby sigils or if there are no sigils, to the APC
|
||||
if(amount <= 0)
|
||||
return FALSE
|
||||
var/list/sigils_in_range = check_apc_and_sigils()
|
||||
if(!istype(sigils_in_range))
|
||||
return FALSE
|
||||
if(sigils_in_range.len)
|
||||
while(amount >= MIN_CLOCKCULT_POWER)
|
||||
for(var/S in sigils_in_range)
|
||||
var/obj/effect/clockwork/sigil/transmission/T = S
|
||||
if(amount >= MIN_CLOCKCULT_POWER && T.modify_charge(-MIN_CLOCKCULT_POWER))
|
||||
amount -= MIN_CLOCKCULT_POWER
|
||||
if(target_apc && target_apc.cell && target_apc.cell.give(amount))
|
||||
target_apc.charging = 1
|
||||
target_apc.chargemode = TRUE
|
||||
target_apc.update()
|
||||
target_apc.update_icon()
|
||||
target_apc.updateUsrDialog()
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/check_apc_and_sigils() //checks for sigils and an APC, returning FALSE if it finds neither, and a list of sigils otherwise
|
||||
. = list()
|
||||
for(var/obj/effect/clockwork/sigil/transmission/T in range(SIGIL_ACCESS_RANGE, src))
|
||||
. += T
|
||||
var/list/L = .
|
||||
if(!L.len && (!target_apc || !target_apc.cell))
|
||||
return FALSE
|
||||
return adjust_clockwork_power(-amount)
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
#define ARK_GRACE_PERIOD 300 //In seconds, how long the crew has before the Ark truly "begins"
|
||||
|
||||
//The gateway to Reebe, from which Ratvar emerges.
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway
|
||||
name = "ark of the Clockwork Justicar"
|
||||
desc = "A massive, thrumming rip in spacetime."
|
||||
clockwork_desc = "A portal to the Celestial Derelict. Massive and intimidating, it is the only thing that can both transport Ratvar and withstand the massive amount of energy he emits."
|
||||
name = "\improper Ark of the Clockwork Justicar"
|
||||
desc = "A massive, hulking amalgamation of parts. It seems to be maintaining a very unstable bluespace anomaly."
|
||||
clockwork_desc = "Nezbere's magnum opus: a hulking clockwork machine capable of combining bluespace and steam power to summon Ratvar. Once activated, \
|
||||
its instability will cause one-way bluespace rifts to open across the station to the City of Cogs, so be prepared to defend it at all costs."
|
||||
max_integrity = 500
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
icon_state = "nothing"
|
||||
density = FALSE
|
||||
invisibility = INVISIBILITY_MAXIMUM
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF | INDESTRUCTIBLE | FREEZE_PROOF
|
||||
density = TRUE
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF | FREEZE_PROOF
|
||||
can_be_repaired = FALSE
|
||||
immune_to_servant_attacks = TRUE
|
||||
var/active = FALSE
|
||||
var/progress_in_seconds = 0 //Once this reaches GATEWAY_RATVAR_ARRIVAL, it's game over
|
||||
var/grace_period = ARK_GRACE_PERIOD //This exists to allow the crew to gear up and prepare for the invasion
|
||||
var/initial_activation_delay = -1 //How many seconds the Ark will have initially taken to activate
|
||||
var/seconds_until_activation = -1 //How many seconds until the Ark activates; if it should never activate, set this to -1
|
||||
var/purpose_fulfilled = FALSE
|
||||
var/first_sound_played = FALSE
|
||||
var/second_sound_played = FALSE
|
||||
@@ -20,31 +26,41 @@
|
||||
var/fourth_sound_played = FALSE
|
||||
var/obj/effect/clockwork/overlay/gateway_glow/glow
|
||||
var/obj/effect/countdown/clockworkgate/countdown
|
||||
var/list/required_components = list(BELLIGERENT_EYE = ARK_CONSUME_COST, VANGUARD_COGWHEEL = ARK_CONSUME_COST, GEIS_CAPACITOR = ARK_CONSUME_COST, REPLICANT_ALLOY = ARK_CONSUME_COST, HIEROPHANT_ANSIBLE = ARK_CONSUME_COST)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/Initialize()
|
||||
. = ..()
|
||||
INVOKE_ASYNC(src, .proc/spawn_animation)
|
||||
glow = new(get_turf(src))
|
||||
if(!GLOB.ark_of_the_clockwork_justiciar)
|
||||
GLOB.ark_of_the_clockwork_justiciar = src
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/cry_havoc()
|
||||
visible_message("<span class='boldwarning'>[src] shudders and roars to life, its parts beginning to whirr and screech!</span>")
|
||||
hierophant_message("<span class='bold large_brass'>The Ark is activating! Get back to the base!</span>")
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(is_servant_of_ratvar(M) || isobserver(M) || M.z == z)
|
||||
M.playsound_local(M, 'sound/magic/clockwork/ark_activation_sequence.ogg', 30, FALSE, pressure_affected = FALSE)
|
||||
addtimer(CALLBACK(src, .proc/let_slip_the_dogs), 300)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/let_slip_the_dogs()
|
||||
spawn_animation()
|
||||
first_sound_played = TRUE
|
||||
active = TRUE
|
||||
priority_announce("Massive [Gibberish("bluespace", 100)] anomaly detected on all frequencies. All crew are directed to \
|
||||
@!$, [text2ratvar("PURGE ALL UNTRUTHS")] <&. the anomalies and destroy their source to prevent further damage to corporate property. This is \
|
||||
not a drill.[grace_period ? " Estimated time of appearance: [grace_period] seconds. Use this time to prepare." : ""]", \
|
||||
"Central Command Higher Dimensional Affairs", 'sound/magic/clockwork/ark_activation.ogg')
|
||||
set_security_level("delta")
|
||||
for(var/V in SSticker.mode.servants_of_ratvar)
|
||||
var/datum/mind/M = V
|
||||
if(ishuman(M.current))
|
||||
M.current.add_overlay(mutable_appearance('icons/effects/genetics.dmi', "servitude", -MUTATIONS_LAYER))
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/open_portal(turf/T)
|
||||
new/obj/effect/clockwork/city_of_cogs_rift(T)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/spawn_animation()
|
||||
var/turf/T = get_turf(src)
|
||||
new/obj/effect/clockwork/general_marker/inathneq(T)
|
||||
hierophant_message("<span class='inathneq'>\"[text2ratvar("Engine, come forth and show your servants your mercy")]!\"</span>")
|
||||
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 30, 0)
|
||||
sleep(10)
|
||||
new/obj/effect/clockwork/general_marker/sevtug(T)
|
||||
hierophant_message("<span class='sevtug'>\"[text2ratvar("Engine, come forth and show this station your decorating skills")]!\"</span>")
|
||||
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 45, 0)
|
||||
sleep(10)
|
||||
new/obj/effect/clockwork/general_marker/nezbere(T)
|
||||
hierophant_message("<span class='nezbere'>\"[text2ratvar("Engine, come forth and shine your light across this realm")]!!\"</span>")
|
||||
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 60, 0)
|
||||
sleep(10)
|
||||
new/obj/effect/clockwork/general_marker/nzcrentr(T)
|
||||
hierophant_message("<span class='nzcrentr'>\"[text2ratvar("Engine, come forth")].\"</span>")
|
||||
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 75, 0)
|
||||
sleep(10)
|
||||
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 100, 0)
|
||||
var/list/open_turfs = list()
|
||||
for(var/turf/open/OT in orange(1, T))
|
||||
if(!is_blocked_turf(OT, TRUE))
|
||||
@@ -52,16 +68,10 @@
|
||||
if(open_turfs.len)
|
||||
for(var/mob/living/L in T)
|
||||
L.forceMove(pick(open_turfs))
|
||||
resistance_flags &= ~INDESTRUCTIBLE
|
||||
density = TRUE
|
||||
invisibility = 0
|
||||
glow = new(get_turf(src))
|
||||
countdown = new(src)
|
||||
countdown.start()
|
||||
var/area/gate_area = get_area(src)
|
||||
hierophant_message("<span class='large_brass'><b>An Ark of the Clockwork Justicar has been created in [gate_area.map_name]!</b></span>", FALSE, src)
|
||||
hierophant_message("<span class='bold large_brass'>The Ark has activated! [grace_period ? "You have [round(grace_period / 60)] minutes until the crew invades! " : ""]Defend it at all costs!</span>", FALSE, src)
|
||||
sound_to_playing_players(volume = 10, channel = CHANNEL_JUSTICAR_ARK, S = sound('sound/effects/clockcult_gateway_charging.ogg', TRUE))
|
||||
seconds_until_activation = 0
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/Destroy()
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
@@ -76,6 +86,18 @@
|
||||
if(countdown)
|
||||
qdel(countdown)
|
||||
countdown = null
|
||||
for(var/mob/L in GLOB.player_list)
|
||||
if(L.z == z)
|
||||
L.forceMove(get_turf(pick(GLOB.generic_event_spawns)))
|
||||
L.overlay_fullscreen("flash", /obj/screen/fullscreen/flash/static)
|
||||
L.clear_fullscreen("flash", 30)
|
||||
if(isliving(L))
|
||||
var/mob/living/LI = L
|
||||
LI.Stun(50)
|
||||
for(var/obj/effect/clockwork/city_of_cogs_rift/R in GLOB.all_clockwork_objects)
|
||||
qdel(R)
|
||||
if(GLOB.ark_of_the_clockwork_justiciar == src)
|
||||
GLOB.ark_of_the_clockwork_justiciar = null
|
||||
. = ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/deconstruct(disassembled = TRUE)
|
||||
@@ -84,12 +106,13 @@
|
||||
resistance_flags |= INDESTRUCTIBLE
|
||||
countdown.stop()
|
||||
visible_message("<span class='userdanger'>[src] begins to pulse uncontrollably... you might want to run!</span>")
|
||||
sound_to_playing_players(volume = 50, channel = CHANNEL_JUSTICAR_ARK, S = sound('sound/effects/clockcult_gateway_disrupted.ogg', 0))
|
||||
sound_to_playing_players(volume = 50, channel = CHANNEL_JUSTICAR_ARK, S = sound('sound/effects/clockcult_gateway_disrupted.ogg'))
|
||||
make_glow()
|
||||
glow.icon_state = "clockwork_gateway_disrupted"
|
||||
resistance_flags |= INDESTRUCTIBLE
|
||||
sleep(27)
|
||||
explosion(src, 1, 3, 8, 8)
|
||||
sound_to_playing_players('sound/effects/explosion_distant.ogg', volume = 50)
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/make_glow()
|
||||
@@ -101,46 +124,11 @@
|
||||
var/damage = max((obj_integrity * 0.7) / severity, 100) //requires multiple bombs to take down
|
||||
take_damage(damage, BRUTE, "bomb", 0)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/attackby(obj/item/I, mob/living/user, params) //add components directly to the ark
|
||||
if(!is_servant_of_ratvar(user) || !still_needs_components())
|
||||
return ..()
|
||||
if(istype(I, /obj/item/clockwork/component))
|
||||
var/obj/item/clockwork/component/C = I
|
||||
if(required_components[C.component_id])
|
||||
required_components[C.component_id]--
|
||||
to_chat(user, "<span class='notice'>You add [C] to [src].</span>")
|
||||
user.drop_item()
|
||||
qdel(C)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>[src] has enough [get_component_name(C.component_id)][C.component_id != REPLICANT_ALLOY ? "s":""].</span>")
|
||||
return 1
|
||||
else if(istype(I, /obj/item/clockwork/slab))
|
||||
var/obj/item/clockwork/slab/S = I
|
||||
var/used_components = FALSE
|
||||
var/used_all = TRUE
|
||||
for(var/i in S.stored_components)
|
||||
if(required_components[i])
|
||||
var/to_use = min(S.stored_components[i], required_components[i])
|
||||
required_components[i] -= to_use
|
||||
S.stored_components[i] -= to_use
|
||||
if(to_use)
|
||||
used_components = TRUE
|
||||
if(S.stored_components[i])
|
||||
used_all = FALSE
|
||||
if(used_components)
|
||||
update_slab_info(S)
|
||||
user.visible_message("<span class='notice'>[user][used_all ? "":" partially"] empties [S] into [src].</span>", \
|
||||
"<span class='notice'>You offload [used_all ? "all":"some"] of your slab's components into [src].</span>")
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/still_needs_components()
|
||||
for(var/i in required_components)
|
||||
if(required_components[i])
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/get_arrival_text(s_on_time)
|
||||
if(seconds_until_activation)
|
||||
return "[seconds_until_activation][s_on_time ? "S" : ""]"
|
||||
if(grace_period)
|
||||
return "[grace_period][s_on_time ? "S" : ""]"
|
||||
. = "IMMINENT"
|
||||
if(!obj_integrity)
|
||||
. = "DETONATING"
|
||||
@@ -152,97 +140,87 @@
|
||||
..()
|
||||
icon_state = initial(icon_state)
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
if(still_needs_components())
|
||||
to_chat(user, "<span class='big'><b>Components required until activation:</b></span>")
|
||||
for(var/i in required_components)
|
||||
if(required_components[i])
|
||||
to_chat(user, "[get_component_icon(i)] <span class='[get_component_span(i)]'>[get_component_name(i)][i != REPLICANT_ALLOY ? "s":""]:</span> \
|
||||
<span class='[get_component_span(i)]_large'>[required_components[i]]</span>")
|
||||
if(!active)
|
||||
to_chat(user, "<span class='big'><b>Seconds until the Ark's activation:</b> [get_arrival_text(TRUE)]</span>")
|
||||
else
|
||||
if(grace_period)
|
||||
to_chat(user, "<span class='big'><b>Crew grace period time remaining:</b> [get_arrival_text(TRUE)]</span>")
|
||||
else
|
||||
to_chat(user, "<span class='big'><b>Seconds until Ratvar's arrival:</b> [get_arrival_text(TRUE)]</span>")
|
||||
switch(progress_in_seconds)
|
||||
if(-INFINITY to GATEWAY_REEBE_FOUND)
|
||||
to_chat(user, "<span class='heavy_brass'>The Ark is feeding power into the bluespace field.</span>")
|
||||
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
|
||||
to_chat(user, "<span class='heavy_brass'>The field is ripping open a copy of itself in Ratvar's prison.</span>")
|
||||
if(GATEWAY_RATVAR_COMING to INFINITY)
|
||||
to_chat(user, "<span class='heavy_brass'>With the bluespace field established, Ratvar is preparing to come through!</span>")
|
||||
else
|
||||
if(!active)
|
||||
to_chat(user, "<span class='warning'>Whatever it is, it doesn't seem to be active.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='big'><b>Seconds until Ratvar's arrival:</b> [get_arrival_text(TRUE)]</span>")
|
||||
switch(progress_in_seconds)
|
||||
if(-INFINITY to GATEWAY_REEBE_FOUND)
|
||||
to_chat(user, "<span class='heavy_brass'>It's still opening.</span>")
|
||||
to_chat(user, "<span class='warning'>You see a swirling bluespace anomaly steadily growing in intensity.</span>")
|
||||
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
|
||||
to_chat(user, "<span class='heavy_brass'>It's reached the Celestial Derelict and is drawing power from it.</span>")
|
||||
to_chat(user, "<span class='warning'>The anomaly is stable, and you can see flashes of something from it.</span>")
|
||||
if(GATEWAY_RATVAR_COMING to INFINITY)
|
||||
to_chat(user, "<span class='heavy_brass'>Ratvar is coming through the gateway!</span>")
|
||||
else
|
||||
switch(progress_in_seconds)
|
||||
if(-INFINITY to GATEWAY_REEBE_FOUND)
|
||||
to_chat(user, "<span class='warning'>It's a swirling mass of blackness.</span>")
|
||||
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
|
||||
to_chat(user, "<span class='warning'>It seems to be leading somewhere.</span>")
|
||||
if(GATEWAY_RATVAR_COMING to INFINITY)
|
||||
to_chat(user, "<span class='boldwarning'>Something is coming through!</span>")
|
||||
to_chat(user, "<span class='boldwarning'>The anomaly is stable! Something is coming through!</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/process()
|
||||
if(seconds_until_activation == -1) //we never do anything
|
||||
return
|
||||
adjust_clockwork_power(2.5) //Provides weak power generation on its own
|
||||
if(seconds_until_activation)
|
||||
if(!countdown)
|
||||
countdown = new(src)
|
||||
countdown.start()
|
||||
seconds_until_activation--
|
||||
if(!GLOB.script_scripture_unlocked && initial_activation_delay * 0.5 > seconds_until_activation)
|
||||
GLOB.script_scripture_unlocked = TRUE
|
||||
hierophant_message("<span class='large_brass bold'>The Ark is halfway prepared. Script scripture is now available!</span>")
|
||||
if(!seconds_until_activation)
|
||||
cry_havoc()
|
||||
seconds_until_activation = -1 //we'll set this after cry_havoc()
|
||||
return
|
||||
if(!first_sound_played || prob(7))
|
||||
for(var/M in GLOB.player_list)
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(M && !isnewplayer(M))
|
||||
to_chat(M, "<span class='warning'><b>You hear otherworldly sounds from the [dir2text(get_dir(get_turf(M), get_turf(src)))]...</span>")
|
||||
if(M.z == z)
|
||||
to_chat(M, "<span class='warning'><b>You hear otherworldly sounds from the [dir2text(get_dir(get_turf(M), get_turf(src)))]...</span>")
|
||||
else
|
||||
to_chat(M, "<span class='boldwarning'>You hear otherworldly sounds from all around you...</span>")
|
||||
if(!obj_integrity)
|
||||
return 0
|
||||
var/convert_dist = 1 + (round(Floor(progress_in_seconds, 15) * 0.067))
|
||||
for(var/t in RANGE_TURFS(convert_dist, loc))
|
||||
var/turf/T = t
|
||||
if(!T)
|
||||
continue
|
||||
if(get_dist(T, src) < 2)
|
||||
if(iswallturf(T))
|
||||
var/turf/closed/wall/W = T
|
||||
W.dismantle_wall()
|
||||
else if(t && (isclosedturf(T) || !is_blocked_turf(T)))
|
||||
T.ChangeTurf(/turf/open/floor/clockwork)
|
||||
var/dist = cheap_hypotenuse(T.x, T.y, x, y)
|
||||
if(dist < convert_dist)
|
||||
T.ratvar_act(FALSE, TRUE, 3)
|
||||
return
|
||||
for(var/turf/closed/wall/W in RANGE_TURFS(2, src))
|
||||
W.dismantle_wall()
|
||||
for(var/obj/O in orange(1, src))
|
||||
if(!O.pulledby && !istype(O, /obj/effect) && O.density)
|
||||
if(!step_away(O, src, 2) || get_dist(O, src) < 2)
|
||||
O.take_damage(50, BURN, "bomb")
|
||||
O.update_icon()
|
||||
if(still_needs_components())
|
||||
if(!first_sound_played)
|
||||
priority_announce("Massive energy anomaly detected on short-range scanners. Attempting to triangulate location...", "Anomaly Alert")
|
||||
sound_to_playing_players(volume = 10, channel = CHANNEL_JUSTICAR_ARK, S = sound('sound/effects/clockcult_gateway_charging.ogg', 1))
|
||||
first_sound_played = TRUE
|
||||
make_glow()
|
||||
glow.icon_state = "clockwork_gateway_components"
|
||||
var/used_components = FALSE
|
||||
for(var/i in required_components)
|
||||
if(required_components[i])
|
||||
var/to_use = min(GLOB.clockwork_component_cache[i], required_components[i])
|
||||
required_components[i] -= to_use
|
||||
GLOB.clockwork_component_cache[i] -= to_use
|
||||
if(to_use)
|
||||
used_components = TRUE
|
||||
if(used_components)
|
||||
update_slab_info()
|
||||
if(still_needs_components())
|
||||
return
|
||||
if(grace_period)
|
||||
grace_period--
|
||||
return
|
||||
progress_in_seconds += GATEWAY_SUMMON_RATE
|
||||
switch(progress_in_seconds)
|
||||
if(-INFINITY to GATEWAY_REEBE_FOUND)
|
||||
if(!second_sound_played)
|
||||
new /obj/effect/temp_visual/decoy/fading/threesecond(loc, glow)
|
||||
sound_to_playing_players(volume = 30, channel = CHANNEL_JUSTICAR_ARK, S = sound('sound/effects/clockcult_gateway_charging.ogg', 1))
|
||||
for(var/V in GLOB.generic_event_spawns)
|
||||
addtimer(CALLBACK(src, .proc/open_portal, get_turf(V)), rand(100, 600))
|
||||
sound_to_playing_players('sound/magic/clockwork/invoke_general.ogg', 30, FALSE)
|
||||
sound_to_playing_players(volume = 30, channel = CHANNEL_JUSTICAR_ARK, S = sound('sound/effects/clockcult_gateway_charging.ogg', TRUE))
|
||||
second_sound_played = TRUE
|
||||
make_glow()
|
||||
glow.icon_state = "clockwork_gateway_charging"
|
||||
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
|
||||
if(!third_sound_played)
|
||||
var/area/gate_area = get_area(src)
|
||||
priority_announce("Location of massive energy anomaly has been triangulated. Location: [gate_area.map_name].", "Anomaly Alert")
|
||||
new /obj/effect/temp_visual/decoy/fading/threesecond(loc, glow)
|
||||
sound_to_playing_players(volume = 35, channel = CHANNEL_JUSTICAR_ARK, S = sound('sound/effects/clockcult_gateway_active.ogg', 1))
|
||||
sound_to_playing_players(volume = 35, channel = CHANNEL_JUSTICAR_ARK, S = sound('sound/effects/clockcult_gateway_active.ogg', TRUE))
|
||||
third_sound_played = TRUE
|
||||
make_glow()
|
||||
glow.icon_state = "clockwork_gateway_active"
|
||||
if(GATEWAY_RATVAR_COMING to GATEWAY_RATVAR_ARRIVAL)
|
||||
if(!fourth_sound_played)
|
||||
new /obj/effect/temp_visual/decoy/fading/threesecond(loc, glow)
|
||||
sound_to_playing_players(volume = 40, channel = CHANNEL_JUSTICAR_ARK, S = sound('sound/effects/clockcult_gateway_closing.ogg', 1))
|
||||
sound_to_playing_players(volume = 40, channel = CHANNEL_JUSTICAR_ARK, S = sound('sound/effects/clockcult_gateway_closing.ogg', TRUE))
|
||||
fourth_sound_played = TRUE
|
||||
make_glow()
|
||||
glow.icon_state = "clockwork_gateway_closing"
|
||||
@@ -252,38 +230,25 @@
|
||||
resistance_flags |= INDESTRUCTIBLE
|
||||
purpose_fulfilled = TRUE
|
||||
make_glow()
|
||||
animate(glow, transform = matrix() * 3, time = 125)
|
||||
sound_to_playing_players('sound/effects/ratvar_rises.ogg', channel = CHANNEL_JUSTICAR_ARK) //End the sounds
|
||||
animate(glow, transform = matrix() * 1.5, alpha = 255, time = 125)
|
||||
sound_to_playing_players(volume = 100, channel = CHANNEL_JUSTICAR_ARK, S = sound('sound/effects/ratvar_rises.ogg')) //End the sounds
|
||||
sleep(125)
|
||||
var/turf/startpoint = get_turf(src)
|
||||
make_glow()
|
||||
glow.transform = matrix() * 4.5
|
||||
animate(glow, transform = matrix() * 0.1, time = 10)
|
||||
QDEL_IN(src, 10)
|
||||
animate(glow, transform = matrix() * 3, alpha = 0, time = 5)
|
||||
var/turf/startpoint = get_turf(src)
|
||||
QDEL_IN(src, 3)
|
||||
sleep(3)
|
||||
GLOB.clockwork_gateway_activated = TRUE
|
||||
new/obj/structure/destructible/clockwork/massive/ratvar(startpoint)
|
||||
send_to_playing_players("<span class='inathneq_large'>\"[text2ratvar("See Engine's mercy")]!\"</span>\n\
|
||||
<span class='sevtug_large'>\"[text2ratvar("Observe Engine's design skills")]!\"</span>\n<span class='nezbere_large'>\"[text2ratvar("Behold Engine's light")]!!\"</span>\n\
|
||||
<span class='nzcrentr_large'>\"[text2ratvar("Gaze upon Engine's power")].\"</span>")
|
||||
sound_to_playing_players('sound/effects/empulse.ogg')
|
||||
var/x0 = startpoint.x
|
||||
var/y0 = startpoint.y
|
||||
for(var/I in spiral_range_turfs(255, startpoint))
|
||||
var/turf/T = I
|
||||
if(!T)
|
||||
continue
|
||||
var/dist = cheap_hypotenuse(T.x, T.y, x0, y0)
|
||||
if(dist < 100)
|
||||
dist = TRUE
|
||||
else
|
||||
dist = FALSE
|
||||
T.ratvar_act(dist, TRUE)
|
||||
CHECK_TICK
|
||||
var/obj/structure/destructible/clockwork/massive/ratvar/R = new(startpoint)
|
||||
var/turf/T = locate(round(world.maxx * 0.5, 1), round(world.maxy * 0.5, 1), ZLEVEL_STATION_PRIMARY) //approximate center of the station
|
||||
R.forceMove(T)
|
||||
|
||||
|
||||
|
||||
//the actual appearance of the Ark of the Clockwork Justicar; an object so the edges of the gate can be clicked through.
|
||||
/obj/effect/clockwork/overlay/gateway_glow
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "clockwork_gateway_charging"
|
||||
icon_state = "clockwork_gateway_components"
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
layer = BELOW_OPEN_DOOR_LAYER
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
return affected
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/attack_hand(mob/living/user)
|
||||
if(!is_servant_of_ratvar(user) || total_accessable_power() < hierophant_cost || !anchored)
|
||||
if(!is_servant_of_ratvar(user) || !can_access_clockwork_power(src, hierophant_cost) || !anchored)
|
||||
to_chat(user, "<span class='warning'>You place your hand on [src], but it doesn't react.</span>")
|
||||
return
|
||||
var/choice = alert(user,"You place your hand on [src]...",,"Hierophant Broadcast","Spatial Gateway","Cancel")
|
||||
@@ -87,7 +87,7 @@
|
||||
active = TRUE
|
||||
clockwork_say(user, text2ratvar("Spatial Gateway, activate!"))
|
||||
return
|
||||
return_power(gateway_cost) //if we didn't return above, ie, successfully create a gateway, we give the power back
|
||||
adjust_clockwork_power(gateway_cost) //if we didn't return above, ie, successfully create a gateway, we give the power back
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/process()
|
||||
if(!anchored)
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
//Used by the Geis scripture to hold its target in place
|
||||
/obj/structure/destructible/clockwork/geis_binding
|
||||
name = "glowing ring"
|
||||
desc = "A flickering, glowing purple ring around a target."
|
||||
clockwork_desc = "A binding ring around a target, preventing them from taking action."
|
||||
max_integrity = 20
|
||||
light_range = 2
|
||||
light_power = 0.8
|
||||
light_color = "#AF0AAF"
|
||||
anchored = FALSE
|
||||
density = FALSE
|
||||
immune_to_servant_attacks = TRUE
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
icon_state = "geisbinding_full"
|
||||
break_message = null
|
||||
break_sound = 'sound/magic/repulse.ogg'
|
||||
debris = list()
|
||||
can_buckle = TRUE
|
||||
buckle_lying = 0
|
||||
var/mob_layer = MOB_LAYER
|
||||
var/last_mob_health = 0
|
||||
var/apply_time = 0
|
||||
|
||||
/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()
|
||||
var/tick_damage = 1
|
||||
if(locate(/obj/effect/clockwork/sigil/submission) in loc)
|
||||
tick_damage *= 0.5
|
||||
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
|
||||
if(last_mob_health > L.health)
|
||||
tick_damage += last_mob_health - L.health
|
||||
last_mob_health = L.health
|
||||
if(L.layer != mob_layer)
|
||||
mob_layer = L.layer
|
||||
layer = mob_layer - 0.01
|
||||
cut_overlays()
|
||||
add_overlay(mutable_appearance('icons/effects/clockwork_effects.dmi', "geisbinding_top", mob_layer + 0.01))
|
||||
break
|
||||
take_damage(tick_damage, sound_effect = FALSE)
|
||||
playsound(src, 'sound/effects/empulse.ogg', tick_damage * 40, TRUE, -4)
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/attack_hand(mob/living/user)
|
||||
return
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/attackby(obj/item/I, mob/user, params)
|
||||
if(is_servant_of_ratvar(user) && istype(I, /obj/item/clockwork/slab))
|
||||
user.visible_message("<span class='warning'>[user] starts to dispel [src]...</span>", "<span class='danger'>You start to dispel [src]...</span>")
|
||||
if(do_after(user, 30, target = src))
|
||||
user.visible_message("<span class='warning'>[user] dispels [src]!</span>", "<span class='danger'>You dispel [src]!</span>")
|
||||
take_damage(obj_integrity)
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/emp_act(severity)
|
||||
new /obj/effect/temp_visual/emp(loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/post_buckle_mob(mob/living/M)
|
||||
..()
|
||||
if(M.buckled == src)
|
||||
desc = "A flickering, glowing purple ring around [M]."
|
||||
clockwork_desc = "A binding ring around [M], preventing [M.p_them()] from taking action."
|
||||
icon_state = "geisbinding"
|
||||
mob_layer = M.layer
|
||||
layer = mob_layer - 0.01
|
||||
add_overlay(mutable_appearance('icons/effects/clockwork_effects.dmi', "geisbinding_top", mob_layer + 0.01))
|
||||
last_mob_health = M.health
|
||||
apply_time = world.time
|
||||
for(var/obj/item/I in M.held_items)
|
||||
M.dropItemToGround(I)
|
||||
for(var/i in M.get_empty_held_indexes())
|
||||
var/obj/item/geis_binding/B = new(M)
|
||||
M.put_in_hands(B, i)
|
||||
if(iscarbon(M))
|
||||
var/mob/living/carbon/C = M
|
||||
if(!C.handcuffed)
|
||||
C.handcuffed = new /obj/item/restraints/handcuffs/energy/clock(C)
|
||||
M.regenerate_icons()
|
||||
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)
|
||||
G.layer = mob_layer - 0.01
|
||||
T.layer = mob_layer + 0.01
|
||||
G.alpha = alpha
|
||||
T.alpha = alpha
|
||||
animate(G, transform = matrix()*2, alpha = 0, time = 8, easing = EASE_OUT)
|
||||
animate(T, transform = matrix()*2, alpha = 0, time = 8, easing = EASE_OUT)
|
||||
M.visible_message("<span class='warning'>[src] snaps into glowing pieces and dissipates!</span>")
|
||||
M.AdjustStun(-130 + (apply_time - world.time), 1, 1) //remove exactly as much stun as was applied
|
||||
if(iscarbon(M))
|
||||
var/mob/living/carbon/C = M
|
||||
C.silent = max(C.silent - 7, 0)
|
||||
for(var/obj/item/geis_binding/GB in M.held_items)
|
||||
M.dropItemToGround(GB, TRUE)
|
||||
if(iscarbon(M))
|
||||
var/mob/living/carbon/C = M
|
||||
if(istype(C.handcuffed, /obj/item/restraints/handcuffs/energy/clock))
|
||||
QDEL_NULL(C.handcuffed)
|
||||
C.update_handcuffed()
|
||||
|
||||
/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)
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
|
||||
. = ..()
|
||||
if(.)
|
||||
update_icon()
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/update_icon()
|
||||
alpha = min(255 * ((obj_integrity/max_integrity) + 0.2) , 255)
|
||||
|
||||
/obj/structure/destructible/clockwork/geis_binding/proc/repair_and_interrupt()
|
||||
obj_integrity = max_integrity
|
||||
update_icon()
|
||||
for(var/m in buckled_mobs)
|
||||
var/mob/living/L = m
|
||||
if(L)
|
||||
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 += 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)
|
||||
var/obj/effect/temp_visual/ratvar/geis_binding/T1 = new /obj/effect/temp_visual/ratvar/geis_binding/top(loc)
|
||||
var/obj/effect/temp_visual/ratvar/geis_binding/T2 = new /obj/effect/temp_visual/ratvar/geis_binding/top(loc)
|
||||
G1.layer = mob_layer - 0.01
|
||||
G2.layer = mob_layer - 0.01
|
||||
T1.layer = mob_layer + 0.01
|
||||
T2.layer = mob_layer + 0.01
|
||||
animate(G1, pixel_y = pixel_y + 9, alpha = 0, time = 8, easing = EASE_IN)
|
||||
animate(G2, pixel_y = pixel_y - 9, alpha = 0, time = 8, easing = EASE_IN)
|
||||
animate(T1, pixel_y = pixel_y + 9, alpha = 0, time = 8, easing = EASE_IN)
|
||||
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)
|
||||
return ..()
|
||||
|
||||
/obj/item/geis_binding
|
||||
name = "glowing ring"
|
||||
desc = "A flickering ring preventing you from holding items."
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
icon_state = "geisbinding_full"
|
||||
flags_1 = NODROP_1|ABSTRACT_1|DROPDEL_1
|
||||
|
||||
/obj/item/geis_binding/pre_attackby(atom/target, mob/living/user, params)
|
||||
return FALSE
|
||||
|
||||
/obj/item/restraints/handcuffs/energy/clock
|
||||
name = "glowing rings"
|
||||
desc = "Flickering rings preventing you from holding items."
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
icon_state = "geisbinding_full"
|
||||
flags_1 = NODROP_1|ABSTRACT_1|DROPDEL_1
|
||||
@@ -0,0 +1,109 @@
|
||||
//Used to "declare war" against the station. The servants' equipment will be permanently supercharged, and the Ark given extra time to prepare.
|
||||
//This will send an announcement to the station, meaning that they will be warned very early in advance about the impending attack.
|
||||
/obj/structure/destructible/clockwork/heralds_beacon
|
||||
name = "herald's beacon"
|
||||
desc = "An imposing spire formed of brass, with a thrumming gemstone at its peak."
|
||||
clockwork_desc = "A massively-powerful beacon. If enough servants decide to activate it, it will send an incredibly large energy pulse to the Ark, \
|
||||
permanently empowering many clockwork objects and reducing all power costs by 50%, but alerting the crew to your presence. It doesn't have enough \
|
||||
energy to sustain itself for long, and if not activated within five minutes, it will permanently shut down."
|
||||
icon_state = "interdiction_lens"
|
||||
break_message = "<span class='warning'>The beacon crackles with power before collapsing into pieces!</span>"
|
||||
max_integrity = 250
|
||||
light_color = "#EF078E"
|
||||
var/time_remaining = 300 //Amount of seconds left to vote on whether or not to activate the beacon
|
||||
var/list/voters //People who have voted to activate the beacon
|
||||
var/votes_needed = 0 //How many votes are needed to activate the beacon
|
||||
var/available = FALSE //If the beacon can be used
|
||||
|
||||
/obj/structure/destructible/clockwork/heralds_beacon/Initialize()
|
||||
. = ..()
|
||||
voters = list()
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/obj/structure/destructible/clockwork/heralds_beacon/Destroy()
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
. = ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/heralds_beacon/process()
|
||||
if(!available)
|
||||
if(istype(SSticker.mode, /datum/game_mode/clockwork_cult))
|
||||
available = TRUE
|
||||
else
|
||||
return
|
||||
if(!SSticker.mode.servants_of_ratvar.len)
|
||||
return
|
||||
if(!votes_needed)
|
||||
var/servants = SSticker.mode.servants_of_ratvar.len
|
||||
if(servants)
|
||||
votes_needed = round(servants * 0.66)
|
||||
time_remaining--
|
||||
if(!time_remaining)
|
||||
hierophant_message("<span class='bold sevtug_small'>[src] has lost its power, and can no longer be activated.</span>")
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(isobserver(M) || is_servant_of_ratvar(M))
|
||||
M.playsound_local(M, 'sound/magic/blind.ogg', 50, FALSE)
|
||||
available = FALSE
|
||||
icon_state = "interdiction_lens_unwrenched"
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
|
||||
/obj/structure/destructible/clockwork/heralds_beacon/examine(mob/user)
|
||||
..()
|
||||
if(isobserver(user) || is_servant_of_ratvar(user))
|
||||
if(!available)
|
||||
if(!GLOB.ratvar_approaches)
|
||||
to_chat(user, "<span class='bold alloy'>It can no longer be activated.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='bold neovgre_small'>It has been activated!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='brass'>There are <b>[time_remaining]</b> second[time_remaining != 1 ? "s" : ""] remaining to vote.</span>")
|
||||
to_chat(user, "<span class='big brass'>There are <b>[voters.len]/[votes_needed]</b> votes to activate the beacon!</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/heralds_beacon/attack_hand(mob/living/user)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
to_chat(user, "<span class='notice'>You can tell how powerful [src] is; you know better than to touch it.</span>")
|
||||
return
|
||||
if(!available)
|
||||
to_chat(user, "<span class='danger'>You can no longer vote with [src].</span>")
|
||||
return
|
||||
var/voting = !(user.key in voters)
|
||||
if(alert(user, "[voting ? "Cast a" : "Undo your"] vote to activate the beacon?", "Herald's Beacon", "Change Vote", "Cancel") == "Cancel")
|
||||
return
|
||||
if(!user.canUseTopic(src) || !is_servant_of_ratvar(user) || !available)
|
||||
return
|
||||
if(voting)
|
||||
if(user.key in voters)
|
||||
return
|
||||
voters += user.key
|
||||
else
|
||||
if(!user.key in voters)
|
||||
return
|
||||
voters -= user.key
|
||||
var/votes_left = votes_needed - voters.len
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] has [voting ? "voted" : "undone their vote"] to activate [src]! [ADMIN_JMP(user)]")
|
||||
hierophant_message("<span class='brass'><b>[user.real_name]</b> has [voting ? "voted" : "undone their vote"] to activate [src]! The beacon needs [votes_left] more votes to activate.")
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(isobserver(M) || is_servant_of_ratvar(M))
|
||||
M.playsound_local(M, 'sound/magic/clockwork/fellowship_armory.ogg', 50, FALSE)
|
||||
if(!votes_left)
|
||||
herald_the_justiciar()
|
||||
|
||||
/obj/structure/destructible/clockwork/heralds_beacon/proc/herald_the_justiciar()
|
||||
priority_announce("A powerful group of fanatical zealots following the cause of Ratvar have brazenly sacrificed stealth for power, and dare anyone \
|
||||
to try and stop them.", title = "The Justiciar Comes", sound = 'sound/magic/clockwork/ark_activation.ogg')
|
||||
GLOB.ratvar_approaches = TRUE
|
||||
available = FALSE
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
icon_state = "interdiction_lens_active"
|
||||
hierophant_message("<span class='big bold brass'>The beacon's activation has given your team great power! Many of your objects are permanently empowered!</span>")
|
||||
for(var/mob/living/simple_animal/hostile/clockwork/C in GLOB.all_clockwork_mobs)
|
||||
if(C.stat == DEAD)
|
||||
continue
|
||||
C.update_values()
|
||||
to_chat(C, C.empower_string)
|
||||
for(var/mob/living/carbon/human/H in GLOB.living_mob_list)
|
||||
if(is_servant_of_ratvar(H))
|
||||
to_chat(H, "<span class='bold alloy'>The beacon's power warps your body into a clockwork form! You are now immune to many hazards, and your body is more robust against damage!</span>")
|
||||
H.set_species(/datum/species/golem/clockwork/no_scrap)
|
||||
SSshuttle.registerHostileEnvironment(GLOB.ark_of_the_clockwork_justiciar) //no leaving when we need to purge you, heretics
|
||||
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
|
||||
G.grace_period = FALSE //no grace period if we've declared war
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/mania_motor/attack_hand(mob/living/user)
|
||||
if(user.canUseTopic(src, !issilicon(user), NO_DEXTERY) && is_servant_of_ratvar(user))
|
||||
if(!total_accessable_power() >= mania_cost)
|
||||
if(!can_access_clockwork_power(src, mania_cost))
|
||||
to_chat(user, "<span class='warning'>[src] needs more power to function!</span>")
|
||||
return 0
|
||||
toggle(0, user)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
break_message = "<span class='warning'>The warden's eye gives a glare of utter hate before falling dark!</span>"
|
||||
debris = list(/obj/item/clockwork/component/belligerent_eye/blind_eye = 1)
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
var/damage_per_tick = 2.7
|
||||
var/damage_per_tick = 2.5
|
||||
var/sight_range = 3
|
||||
var/atom/movable/target
|
||||
var/list/idle_messages = list(" sulkily glares around.", " lazily drifts from side to side.", " looks around for something to burn.", " slowly turns in circles.")
|
||||
@@ -68,9 +68,9 @@
|
||||
else
|
||||
R.reveal(10)
|
||||
if(prob(50))
|
||||
L.playsound_local(null,'sound/machines/clockcult/ocularwarden-dot1.ogg',50,1)
|
||||
L.playsound_local(null,'sound/machines/clockcult/ocularwarden-dot1.ogg',75 * get_efficiency_mod(),1)
|
||||
else
|
||||
L.playsound_local(null,'sound/machines/clockcult/ocularwarden-dot2.ogg',50,1)
|
||||
L.playsound_local(null,'sound/machines/clockcult/ocularwarden-dot2.ogg',75 * get_efficiency_mod(),1)
|
||||
L.adjustFireLoss((!iscultist(L) ? damage_per_tick : damage_per_tick * 2) * get_efficiency_mod()) //Nar-Sian cultists take additional damage
|
||||
if(GLOB.ratvar_awakens && L)
|
||||
L.adjust_fire_stacks(damage_per_tick)
|
||||
@@ -89,10 +89,10 @@
|
||||
visible_message("<span class='warning'>[src] swivels to face [target]!</span>")
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
to_chat(L, "<span class='heavy_brass'>\"I SEE YOU!\"</span>\n<span class='userdanger'>[src]'s gaze [GLOB.ratvar_awakens ? "melts you alive" : "burns you"]!</span>")
|
||||
to_chat(L, "<span class='neovgre'>\"I SEE YOU!\"</span>\n<span class='userdanger'>[src]'s gaze [GLOB.ratvar_awakens ? "melts you alive" : "burns you"]!</span>")
|
||||
else if(istype(target, /obj/mecha))
|
||||
var/obj/mecha/M = target
|
||||
to_chat(M.occupant, "<span class='heavy_brass'>\"I SEE YOU!\"</span>" )
|
||||
to_chat(M.occupant, "<span class='neovgre'>\"I SEE YOU!\"</span>" )
|
||||
else if(prob(0.5)) //Extremely low chance because of how fast the subsystem it uses processes
|
||||
if(prob(50))
|
||||
visible_message("<span class='notice'>[src][pick(idle_messages)]</span>")
|
||||
@@ -112,7 +112,7 @@
|
||||
continue
|
||||
if(is_servant_of_ratvar(L) || (L.disabilities & BLIND) || L.null_rod_check())
|
||||
continue
|
||||
if(L.stat || L.restrained() || L.buckled || L.lying || istype(L.buckled, /obj/structure/destructible/clockwork/geis_binding))
|
||||
if(L.stat || L.restrained() || L.buckled || L.lying)
|
||||
continue
|
||||
if(ishostile(L))
|
||||
var/mob/living/simple_animal/hostile/H = L
|
||||
@@ -134,3 +134,15 @@
|
||||
target = null
|
||||
visible_message("<span class='warning'>[src] settles and seems almost disappointed.</span>")
|
||||
return 1
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/get_efficiency_mod()
|
||||
if(GLOB.ratvar_awakens)
|
||||
return 2
|
||||
. = 1
|
||||
if(target)
|
||||
for(var/turf/T in getline(src, target))
|
||||
for(var/obj/structure/O in T)
|
||||
if(O.density)
|
||||
. -= 0.15
|
||||
. -= (get_dist(src, target) * 0.05)
|
||||
. = max(., 0.1) //The lowest damage a warden can do is 10% of its normal amount (0.25 by default)
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
//Prolonging Prism: A prism that consumes power to delay the shuttle
|
||||
/obj/structure/destructible/clockwork/powered/prolonging_prism
|
||||
name = "prolonging prism"
|
||||
desc = "A dark onyx prism, held in midair by spiraling tendrils of stone."
|
||||
clockwork_desc = "A powerful prism that will delay the arrival of an emergency shuttle."
|
||||
icon_state = "prolonging_prism_inactive"
|
||||
active_icon = "prolonging_prism"
|
||||
inactive_icon = "prolonging_prism_inactive"
|
||||
unanchored_icon = "prolonging_prism_unwrenched"
|
||||
construction_value = 20
|
||||
max_integrity = 125
|
||||
break_message = "<span class='warning'>The prism falls to the ground with a heavy thud!</span>"
|
||||
debris = list(/obj/item/clockwork/alloy_shards/small = 3, \
|
||||
/obj/item/clockwork/alloy_shards/medium = 1, \
|
||||
/obj/item/clockwork/alloy_shards/large = 1, \
|
||||
/obj/item/clockwork/component/vanguard_cogwheel/onyx_prism = 1)
|
||||
var/static/list/component_refund = list(VANGUARD_COGWHEEL = 2, GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 1)
|
||||
var/static/delay_cost = 3000
|
||||
var/static/delay_cost_increase = 1250
|
||||
var/static/delay_remaining = 0
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/prolonging_prism/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_IGNITING || SSshuttle.emergency.mode == SHUTTLE_STRANDED || SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
|
||||
to_chat(user, "<span class='inathneq'>An emergency shuttle has arrived and this prism is no longer useful; attempt to activate it to gain a partial refund of components used.</span>")
|
||||
else
|
||||
var/efficiency = get_efficiency_mod(TRUE)
|
||||
to_chat(user, "<span class='inathneq_small'>It requires at least <b>[DisplayPower(get_delay_cost())]</b> of power to attempt to delay the arrival of an emergency shuttle by <b>[2 * efficiency]</b> minutes.</span>")
|
||||
to_chat(user, "<span class='inathneq_small'>This cost increases by <b>[DisplayPower(delay_cost_increase)]</b> for every previous activation.</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/prolonging_prism/forced_disable(bad_effects)
|
||||
if(active)
|
||||
if(bad_effects)
|
||||
try_use_power(MIN_CLOCKCULT_POWER*4)
|
||||
visible_message("<span class='warning'>[src] emits an airy chuckling sound and falls dark!</span>")
|
||||
toggle()
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/prolonging_prism/attack_hand(mob/living/user)
|
||||
if(user.canUseTopic(src, !issilicon(user), NO_DEXTERY) && is_servant_of_ratvar(user))
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_IGNITING || SSshuttle.emergency.mode == SHUTTLE_STRANDED || SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
|
||||
to_chat(user, "<span class='brass'>You break [src] apart, refunding some of the components used.</span>")
|
||||
for(var/i in component_refund)
|
||||
generate_cache_component(i, src)
|
||||
take_damage(max_integrity)
|
||||
return 0
|
||||
if(active)
|
||||
return 0
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T || !(T.z in GLOB.station_z_levels))
|
||||
to_chat(user, "<span class='warning'>[src] must be on the station to function!</span>")
|
||||
return 0
|
||||
if(SSshuttle.emergency.mode != SHUTTLE_CALL)
|
||||
to_chat(user, "<span class='warning'>No emergency shuttles are attempting to arrive at the station!</span>")
|
||||
return 0
|
||||
if(!try_use_power(get_delay_cost()))
|
||||
to_chat(user, "<span class='warning'>[src] needs more power to function!</span>")
|
||||
return 0
|
||||
delay_cost += delay_cost_increase
|
||||
delay_remaining += PRISM_DELAY_DURATION
|
||||
toggle(0, user)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/prolonging_prism/process()
|
||||
var/turf/own_turf = get_turf(src)
|
||||
if(SSshuttle.emergency.mode != SHUTTLE_CALL || delay_remaining <= 0 || !own_turf || !(own_turf.z in GLOB.station_z_levels))
|
||||
forced_disable(FALSE)
|
||||
return
|
||||
. = ..()
|
||||
var/delay_amount = 40
|
||||
delay_remaining -= delay_amount
|
||||
var/efficiency = get_efficiency_mod()
|
||||
SSshuttle.emergency.setTimer(SSshuttle.emergency.timeLeft(1) + (delay_amount * efficiency))
|
||||
var/highest_y
|
||||
var/highest_x
|
||||
var/lowest_y
|
||||
var/lowest_x
|
||||
var/list/prism_turfs = list()
|
||||
for(var/t in SSshuttle.emergency.ripple_area(SSshuttle.getDock("emergency_home")))
|
||||
prism_turfs[t] = TRUE
|
||||
var/turf/T = t
|
||||
if(!highest_y || T.y > highest_y)
|
||||
highest_y = T.y
|
||||
if(!highest_x || T.x > highest_x)
|
||||
highest_x = T.x
|
||||
if(!lowest_y || T.y < lowest_y)
|
||||
lowest_y = T.y
|
||||
if(!lowest_x || T.x < lowest_x)
|
||||
lowest_x = T.x
|
||||
var/mean_y = Lerp(lowest_y, highest_y)
|
||||
var/mean_x = Lerp(lowest_x, highest_x)
|
||||
if(prob(50))
|
||||
mean_y = Ceiling(mean_y)
|
||||
else
|
||||
mean_y = Floor(mean_y)
|
||||
if(prob(50))
|
||||
mean_x = Ceiling(mean_x)
|
||||
else
|
||||
mean_x = Floor(mean_x)
|
||||
var/turf/semi_random_center_turf = locate(mean_x, mean_y, ZLEVEL_STATION_PRIMARY)
|
||||
for(var/t in getline(src, semi_random_center_turf))
|
||||
prism_turfs[t] = TRUE
|
||||
var/placement_style = prob(50)
|
||||
for(var/t in prism_turfs)
|
||||
var/turf/T = t
|
||||
if(placement_style)
|
||||
if(IsOdd(T.x + T.y))
|
||||
seven_random_hexes(T, efficiency)
|
||||
else if(prob(50 * efficiency))
|
||||
new /obj/effect/temp_visual/ratvar/prolonging_prism(T)
|
||||
else
|
||||
if(IsEven(T.x + T.y))
|
||||
seven_random_hexes(T, efficiency)
|
||||
else if(prob(50 * efficiency))
|
||||
new /obj/effect/temp_visual/ratvar/prolonging_prism(T)
|
||||
CHECK_TICK //we may be going over a hell of a lot of turfs
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/prolonging_prism/proc/get_delay_cost()
|
||||
return Floor(delay_cost, MIN_CLOCKCULT_POWER)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/prolonging_prism/proc/seven_random_hexes(turf/T, efficiency)
|
||||
var/static/list/hex_states = list("prismhex1", "prismhex2", "prismhex3", "prismhex4", "prismhex5", "prismhex6", "prismhex7")
|
||||
var/mutable_appearance/hex_combo
|
||||
for(var/n in hex_states) //BUILD ME A HEXAGON
|
||||
if(prob(50 * efficiency))
|
||||
if(!hex_combo)
|
||||
hex_combo = mutable_appearance('icons/effects/64x64.dmi', n, RIPPLE_LAYER)
|
||||
else
|
||||
hex_combo.add_overlay(mutable_appearance('icons/effects/64x64.dmi', n, RIPPLE_LAYER))
|
||||
if(hex_combo) //YOU BUILT A HEXAGON
|
||||
hex_combo.pixel_x = -16
|
||||
hex_combo.pixel_y = -16
|
||||
hex_combo.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
hex_combo.plane = GAME_PLANE
|
||||
new /obj/effect/temp_visual/ratvar/prolonging_prism(T, hex_combo)
|
||||
@@ -1,8 +1,8 @@
|
||||
//Ratvar himself. Impossible to damage by most standard means, He will dominate the station and all upon it.
|
||||
//Ratvar himself. Impossible to damage by most standard means, and converts nearby objects and players into clockwork variants and Servants.
|
||||
/obj/structure/destructible/clockwork/massive/ratvar
|
||||
name = "Ratvar, the Clockwork Justiciar"
|
||||
desc = "<span class='userdanger'>What is what is what are what real what is all a lie all a lie it's all a lie why how can what is</span>"
|
||||
clockwork_desc = "<span class='large_brass'><b><i>Ratvar, the Clockwork Justiciar, your master eternal.</i></b></span>"
|
||||
desc = "..."
|
||||
clockwork_desc = "<span class='large_brass bold italics'>Ratvar, free at last!</span>"
|
||||
icon = 'icons/effects/512x512.dmi'
|
||||
icon_state = "ratvar"
|
||||
pixel_x = -235
|
||||
@@ -13,7 +13,7 @@
|
||||
light_range = 15
|
||||
light_color = "#BE8700"
|
||||
var/atom/prey //Whatever Ratvar is chasing
|
||||
var/clashing = FALSE //If Ratvar is FUCKING FIGHTING WITH NAR-SIE
|
||||
var/clashing = FALSE //If Ratvar is fighting with Nar-Sie
|
||||
var/convert_range = 10
|
||||
dangerous_possession = TRUE
|
||||
|
||||
@@ -22,20 +22,21 @@
|
||||
GLOB.ratvar_awakens++
|
||||
for(var/obj/O in GLOB.all_clockwork_objects)
|
||||
O.ratvar_act()
|
||||
for(var/mob/living/simple_animal/hostile/clockwork/M in GLOB.all_clockwork_mobs)
|
||||
M.ratvar_act()
|
||||
START_PROCESSING(SSobj, src)
|
||||
INVOKE_ASYNC(SSshuttle.emergency, /obj/docking_port/mobile/emergency.proc/request, null, 0, null, FALSE, 0)
|
||||
send_to_playing_players("<span class='ratvar'>\"[text2ratvar("ONCE AGAIN MY LIGHT SHALL SHINE ACROSS THIS PATHETIC REALM")]!!\"</span>")
|
||||
send_to_playing_players("<span class='ratvar'>[text2ratvar("ONCE AGAIN MY LIGHT SHINES AMONG THESE PATHETIC STARS")]</span>")
|
||||
sound_to_playing_players('sound/effects/ratvar_reveal.ogg')
|
||||
var/mutable_appearance/alert_overlay = mutable_appearance('icons/effects/clockwork_effects.dmi', "ratvar_alert")
|
||||
var/area/A = get_area(src)
|
||||
notify_ghosts("The Justiciar's light calls to you! Reach out to Ratvar in [A.name] to be granted a shell to spread his glory!", null, source = src, alert_overlay = alert_overlay)
|
||||
INVOKE_ASYNC(SSshuttle.emergency, /obj/docking_port/mobile/emergency.proc/request, null, 10, null, FALSE, 0)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/Destroy()
|
||||
GLOB.ratvar_awakens--
|
||||
for(var/obj/O in GLOB.all_clockwork_objects)
|
||||
O.ratvar_act()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
send_to_playing_players("<span class='heavy_brass'><font size=6>\"NO! I will not... be...</font> <font size=5>banished...</font> <font size=4>again...\"</font></span>")
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/attack_ghost(mob/dead/observer/O)
|
||||
@@ -100,12 +101,12 @@
|
||||
return
|
||||
clashing = TRUE
|
||||
GLOB.cult_narsie.clashing = TRUE
|
||||
to_chat(world, "<span class='heavy_brass'><font size=5>\"[pick("BLOOD GOD!!!", "NAR-SIE!!!", "AT LAST, YOUR TIME HAS COME!")]\"</font></span>")
|
||||
to_chat(world, "<span class='cult'><font size=5>\"<b>Ratvar?! How?!</b>\"</font></span>")
|
||||
clash_of_the_titans(GLOB.cult_narsie) //IT'S TIME FOR THE BATTLE OF THE AGES
|
||||
to_chat(world, "<span class='bold brass'><font size=5>\"YOU.\"</font></span>")
|
||||
to_chat(world, "<span class='bold cult'><font size=5>\"Ratvar?!\"</font></span>")
|
||||
clash_of_the_titans(GLOB.cult_narsie) // >:(
|
||||
return TRUE
|
||||
|
||||
//Put me in Reebe, will you? Ratvar has found and is going to fucking murder Nar-Sie
|
||||
//Put me in Reebe, will you? Ratvar has found and is going to do a hecking murder on Nar-Sie
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/proc/clash_of_the_titans(obj/singularity/narsie/narsie)
|
||||
var/winner = "Undeclared"
|
||||
var/base_victory_chance = 1
|
||||
@@ -136,7 +137,7 @@
|
||||
base_victory_chance *= 2 //The clash has a higher chance of resolving each time both gods attack one another
|
||||
switch(winner)
|
||||
if("Ratvar")
|
||||
send_to_playing_players("<span class='heavy_brass'><font size=5>\"[pick("DIE! DIE! DIE!", "FILTH!!!", "SUFFER!!!", text2ratvar("ROT FOR CENTURIES AS I HAVE!!"))]\"</font></span>\n\
|
||||
send_to_playing_players("<span class='heavy_brass'><font size=5>\"[pick("DIE.", "ROT.")]\"</font></span>\n\
|
||||
<span class='cult'><font size=5>\"<b>[pick("Nooooo...", "Not die. To y-", "Die. Ratv-", "Sas tyen re-")]\"</b></font></span>") //nar-sie get out
|
||||
sound_to_playing_players('sound/magic/clockwork/anima_fragment_attack.ogg')
|
||||
sound_to_playing_players('sound/magic/demon_dies.ogg', 50)
|
||||
|
||||
66
code/game/gamemodes/clock_cult/clock_structures/stargazer.dm
Normal file
66
code/game/gamemodes/clock_cult/clock_structures/stargazer.dm
Normal file
@@ -0,0 +1,66 @@
|
||||
#define STARGAZER_RANGE 3 //How many tiles the stargazer can see out to
|
||||
#define STARGAZER_POWER 20 //How many watts will be produced per second when the stargazer sees starlight
|
||||
|
||||
//Stargazer: A very fragile but cheap generator that creates power from starlight.
|
||||
/obj/structure/destructible/clockwork/stargazer
|
||||
name = "stargazer"
|
||||
desc = "A large lantern-shaped machine made of thin brass. It looks fragile."
|
||||
clockwork_desc = "A lantern-shaped generator that produces power when near starlight."
|
||||
icon_state = "stargazer"
|
||||
unanchored_icon = "stargazer_unwrenched"
|
||||
max_integrity = 40
|
||||
construction_value = 5
|
||||
layer = WALL_OBJ_LAYER
|
||||
break_message = "<span class='warning'>The stargazer's fragile body shatters into pieces!</span>"
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
light_color = "#DAAA18"
|
||||
var/star_light_star_bright = FALSE //If this stargazer can see starlight
|
||||
|
||||
/obj/structure/destructible/clockwork/stargazer/Initialize()
|
||||
. = ..()
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/obj/structure/destructible/clockwork/stargazer/Destroy()
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
. = ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/stargazer/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user))
|
||||
to_chat(user, "<span class='nzcrentr_small'>Generates <b>[DisplayPower(STARGAZER_POWER)]</b> per second while viewing starlight within [STARGAZER_RANGE] tiles.</span>")
|
||||
if(star_light_star_bright)
|
||||
to_chat(user, "[is_servant_of_ratvar(user) ? "<span class='nzcrentr_small'>It can see starlight!</span>" : "It's shining brilliantly!"]")
|
||||
|
||||
/obj/structure/destructible/clockwork/stargazer/process()
|
||||
star_light_star_bright = check_starlight()
|
||||
if(star_light_star_bright)
|
||||
adjust_clockwork_power(STARGAZER_POWER)
|
||||
|
||||
/obj/structure/destructible/clockwork/stargazer/update_anchored(mob/living/user, damage)
|
||||
. = ..()
|
||||
star_light_star_bright = check_starlight()
|
||||
|
||||
/obj/structure/destructible/clockwork/stargazer/proc/check_starlight()
|
||||
var/old_status = star_light_star_bright
|
||||
var/has_starlight
|
||||
if(!anchored)
|
||||
has_starlight = FALSE
|
||||
else
|
||||
for(var/turf/T in view(3, src))
|
||||
if(isspaceturf(T))
|
||||
has_starlight = TRUE
|
||||
break
|
||||
if(old_status != has_starlight)
|
||||
if(has_starlight)
|
||||
visible_message("<span class='nzcrentr_small'>[src] hums and shines brilliantly!</span>")
|
||||
playsound(src, 'sound/machines/clockcult/stargazer_activate.ogg', 50, TRUE)
|
||||
add_overlay("stargazer_light")
|
||||
set_light(1.5, 5)
|
||||
else
|
||||
if(anchored) //We lost visibility somehow
|
||||
visible_message("<span class='danger'>[src] flickers, and falls dark.</span>")
|
||||
else
|
||||
visible_message("<span class='danger'>[src] whooshes quietly as it slides into a less bulky form.</span>")
|
||||
cut_overlays()
|
||||
set_light(0)
|
||||
return has_starlight
|
||||
@@ -105,7 +105,7 @@
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
if(linkedwall)
|
||||
to_chat(user, "<span class='brass'>It is linked to a Clockwork Wall and will generate a component every <b>[round(get_production_time() * 0.1, 0.1)]</b> seconds!</span>")
|
||||
to_chat(user, "<span class='brass'>It is linked to a Clockwork Wall and will generate a component every <b>[DisplayTimeText(get_production_time())]</b>!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='alloy'>It is unlinked! Construct a Clockwork Wall nearby to generate components!</span>")
|
||||
to_chat(user, "<b>Stored components:</b>")
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
//Tinkerer's Daemon: A machine that rapidly produces components at a power cost.
|
||||
/obj/structure/destructible/clockwork/powered/tinkerers_daemon
|
||||
name = "tinkerer's daemon"
|
||||
desc = "A strange machine with three small brass obelisks attached to it."
|
||||
clockwork_desc = "An efficient machine that can rapidly produce components at a small power cost. It will only function if active daemons are outnumbered by servants at a rate to 5:1."
|
||||
icon_state = "tinkerers_daemon"
|
||||
active_icon = "tinkerers_daemon"
|
||||
inactive_icon = "tinkerers_daemon"
|
||||
unanchored_icon = "tinkerers_daemon_unwrenched"
|
||||
max_integrity = 100
|
||||
construction_value = 20
|
||||
break_message = "<span class='warning'>The daemon shatters into millions of pieces, leaving only a disc of metal!</span>"
|
||||
debris = list(/obj/item/clockwork/alloy_shards/medium = 1, \
|
||||
/obj/item/clockwork/alloy_shards/small = 6, \
|
||||
/obj/item/clockwork/component/replicant_alloy/replication_plate = 1)
|
||||
var/static/mutable_appearance/daemon_glow = mutable_appearance('icons/obj/clockwork_objects.dmi', "tinkerglow")
|
||||
var/static/mutable_appearance/component_glow = mutable_appearance('icons/obj/clockwork_objects.dmi', "t_random_component")
|
||||
var/component_id_to_produce
|
||||
var/production_time = 0 //last time we produced a component
|
||||
var/production_cooldown = 70
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/Destroy()
|
||||
GLOB.active_daemons -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
if(active)
|
||||
if(component_id_to_produce)
|
||||
to_chat(user, "<span class='[get_component_span(component_id_to_produce)]_small'>It is currently producing [get_component_name(component_id_to_produce)][component_id_to_produce != REPLICANT_ALLOY ? "s":""].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='brass'>It is currently producing random components.</span>")
|
||||
to_chat(user, "<span class='nezbere_small'>It will produce a component every <b>[round((production_cooldown*0.1) * get_efficiency_mod(TRUE), 0.1)]</b> seconds and requires at least the following power for each component type:</span>")
|
||||
for(var/i in GLOB.clockwork_component_cache)
|
||||
to_chat(user, "[get_component_icon(i)] <span class='[get_component_span(i)]_small'><i>[get_component_name(i)]:</i> <b>[DisplayPower(get_component_cost(i))]</b> <i>([GLOB.clockwork_component_cache[i]] exist[GLOB.clockwork_component_cache[i] == 1 ? "s" : ""])</i></span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/forced_disable(bad_effects)
|
||||
if(active)
|
||||
if(bad_effects)
|
||||
try_use_power(MIN_CLOCKCULT_POWER*4)
|
||||
visible_message("<span class='warning'>[src] shuts down with a horrible grinding noise!</span>")
|
||||
playsound(src, 'sound/magic/clockwork/anima_fragment_attack.ogg', 50, 1)
|
||||
else
|
||||
visible_message("<span class='warning'>[src] shuts down!</span>")
|
||||
toggle()
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/attack_hand(mob/living/user)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
to_chat(user, "<span class='warning'>You place your hand on the daemon, but nothing happens.</span>")
|
||||
return
|
||||
if(active)
|
||||
toggle(0, user)
|
||||
else
|
||||
if(!anchored)
|
||||
to_chat(user, "<span class='warning'>[src] needs to be secured to the floor before it can be activated!</span>")
|
||||
return FALSE
|
||||
if(!GLOB.clockwork_caches)
|
||||
to_chat(user, "<span class='nezbere'>\"You require a cache for this daemon to operate. Get to it.\"</span>")
|
||||
return
|
||||
var/min_power_usable = 0
|
||||
for(var/i in GLOB.clockwork_component_cache)
|
||||
if(!min_power_usable)
|
||||
min_power_usable = get_component_cost(i)
|
||||
else
|
||||
min_power_usable = min(min_power_usable, get_component_cost(i))
|
||||
if(total_accessable_power() < min_power_usable)
|
||||
to_chat(user, "<span class='nezbere'>\"You need more power to activate this daemon, friend.\"</span>")
|
||||
return
|
||||
var/servants = 0
|
||||
for(var/mob/living/L in GLOB.living_mob_list)
|
||||
if(is_servant_of_ratvar(L))
|
||||
servants++
|
||||
if(servants * 0.2 < 1)
|
||||
to_chat(user, "<span class='nezbere'>\"There are too few servants for daemons to work.\"</span>")
|
||||
return
|
||||
var/choice = alert(user,"Activate Daemon...",,"Specific Component","Random Component","Cancel")
|
||||
switch(choice)
|
||||
if("Specific Component")
|
||||
var/list/components = list()
|
||||
for(var/i in GLOB.clockwork_component_cache)
|
||||
components["[get_component_name(i)] ([DisplayPower(get_component_cost(i))])"] = i
|
||||
var/input_component = input(user, "Choose a component type.", name) as null|anything in components
|
||||
component_id_to_produce = components[input_component]
|
||||
servants = 0
|
||||
for(var/mob/living/L in GLOB.living_mob_list)
|
||||
if(is_servant_of_ratvar(L))
|
||||
servants++
|
||||
if(!is_servant_of_ratvar(user) || !user.canUseTopic(src, !issilicon(user), NO_DEXTERY) || active || !GLOB.clockwork_caches || servants * 0.2 < 1)
|
||||
return
|
||||
if(!component_id_to_produce)
|
||||
to_chat(user, "<span class='warning'>You decide not to select a component and activate the daemon.</span>")
|
||||
return
|
||||
if(total_accessable_power() < get_component_cost(component_id_to_produce))
|
||||
to_chat(user, "<span class='warning'>There is too little power to produce this type of component!</span>")
|
||||
return
|
||||
toggle(0, user)
|
||||
if("Random Component")
|
||||
component_id_to_produce = null
|
||||
servants = 0
|
||||
for(var/mob/living/L in GLOB.living_mob_list)
|
||||
if(is_servant_of_ratvar(L))
|
||||
servants++
|
||||
if(!is_servant_of_ratvar(user) || !user.canUseTopic(src, !issilicon(user), NO_DEXTERY) || active || !GLOB.clockwork_caches || servants * 0.2 < 1)
|
||||
return
|
||||
toggle(0, user)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/toggle(fast_process, mob/living/user)
|
||||
. = ..()
|
||||
if(active)
|
||||
GLOB.active_daemons += src
|
||||
var/component_color = get_component_color(component_id_to_produce)
|
||||
daemon_glow.color = component_color
|
||||
add_overlay(daemon_glow)
|
||||
component_glow.icon_state = "t_[component_id_to_produce ? component_id_to_produce :"random_component"]"
|
||||
component_glow.color = component_color
|
||||
add_overlay(component_glow)
|
||||
production_time = world.time + production_cooldown //don't immediately produce when turned on after being off
|
||||
set_light(2, 0.9, get_component_color_bright(component_id_to_produce))
|
||||
else
|
||||
GLOB.active_daemons -= src
|
||||
cut_overlays()
|
||||
set_light(0)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/proc/get_component_cost(id)
|
||||
return max(MIN_CLOCKCULT_POWER*2, (MIN_CLOCKCULT_POWER*2) * (1 + round(GLOB.clockwork_component_cache[id] * 0.2)))
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/process()
|
||||
var/servants = 0
|
||||
for(var/mob/living/L in GLOB.living_mob_list)
|
||||
if(is_servant_of_ratvar(L))
|
||||
servants++
|
||||
while(servants * 0.2 < LAZYLEN(GLOB.active_daemons))
|
||||
var/obj/structure/destructible/clockwork/powered/tinkerers_daemon/D = GLOB.active_daemons[1]
|
||||
if(!istype(D))
|
||||
break
|
||||
if(D.active)
|
||||
D.forced_disable(FALSE)
|
||||
if(D == src)
|
||||
return
|
||||
. = ..()
|
||||
var/min_power_usable = 0
|
||||
if(!component_id_to_produce)
|
||||
for(var/i in GLOB.clockwork_component_cache)
|
||||
if(!min_power_usable)
|
||||
min_power_usable = get_component_cost(i)
|
||||
else
|
||||
min_power_usable = min(min_power_usable, get_component_cost(i))
|
||||
else
|
||||
min_power_usable = get_component_cost(component_id_to_produce)
|
||||
if(!GLOB.clockwork_caches || . < min_power_usable) //if we don't have enough to produce the lowest or what we chose to produce, cancel out
|
||||
forced_disable(FALSE)
|
||||
return
|
||||
if(production_time <= world.time)
|
||||
var/component_to_generate = component_id_to_produce
|
||||
if(!component_to_generate)
|
||||
component_to_generate = get_weighted_component_id() //more likely to generate components that we have less of
|
||||
if(!try_use_power(get_component_cost(component_to_generate)))
|
||||
component_to_generate = null
|
||||
if(!component_id_to_produce)
|
||||
for(var/i in GLOB.clockwork_component_cache)
|
||||
if(try_use_power(get_component_cost(i))) //if we fail but are producing random, try and get a different component to produce
|
||||
component_to_generate = i
|
||||
break
|
||||
if(component_to_generate)
|
||||
generate_cache_component(component_to_generate, src)
|
||||
production_time = world.time + (production_cooldown * get_efficiency_mod(TRUE)) //go on cooldown
|
||||
visible_message("<span class='warning'>[src] hums as it produces a </span><span class='[get_component_span(component_to_generate)]'>component</span><span class='warning'>.</span>")
|
||||
else
|
||||
forced_disable(FALSE) //we shouldn't actually ever get here, as we should cancel out way before this
|
||||
@@ -96,7 +96,7 @@
|
||||
|
||||
/proc/pollCultists(var/mob/living/Nominee) //Cult Master Poll
|
||||
if(world.time < CULT_POLL_WAIT)
|
||||
to_chat(Nominee, "It would be premature to select a leader while everyone is still settling in, try again in [round((CULT_POLL_WAIT-world.time)/10)] seconds.")
|
||||
to_chat(Nominee, "It would be premature to select a leader while everyone is still settling in, try again in [DisplayTimeText(CULT_POLL_WAIT-world.time)].")
|
||||
return
|
||||
GLOB.cult_vote_called = TRUE //somebody's trying to be a master, make sure we don't let anyone else try
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
@@ -232,7 +232,7 @@
|
||||
return FALSE
|
||||
if(cooldown > world.time)
|
||||
if(!CM.active)
|
||||
to_chat(owner, "<span class='cultlarge'><b>You need to wait [round((cooldown - world.time) * 0.1)] seconds before you can mark another target!</b></span>")
|
||||
to_chat(owner, "<span class='cultlarge'><b>You need to wait [DisplayTimeText(cooldown - world.time)] before you can mark another target!</b></span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
@@ -324,7 +324,7 @@
|
||||
return FALSE
|
||||
if(cooldown > world.time)
|
||||
if(!PM.active)
|
||||
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>")
|
||||
to_chat(owner, "<span class='cultlarge'><b>You need to wait [DisplayTimeText(cooldown - world.time)] before you can pulse again!</b></span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
..()
|
||||
to_chat(user, "<span class='notice'>\The [src] is [anchored ? "":"not "]secured to the floor.</span>")
|
||||
if((iscultist(user) || isobserver(user)) && cooldowntime > world.time)
|
||||
to_chat(user, "<span class='cultitalic'>The magic in [src] is too weak, [p_they()] will be ready to use again in [getETA()].</span>")
|
||||
to_chat(user, "<span class='cultitalic'>The magic in [src] is too weak, [p_they()] will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].</span>")
|
||||
|
||||
/obj/structure/destructible/cult/examine_status(mob/user)
|
||||
if(iscultist(user) || isobserver(user))
|
||||
@@ -50,13 +50,6 @@
|
||||
animate(src, color = previouscolor, time = 8)
|
||||
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8)
|
||||
|
||||
/obj/structure/destructible/cult/proc/getETA()
|
||||
var/time = (cooldowntime - world.time)/600
|
||||
var/eta = "[round(time, 1)] minutes"
|
||||
if(time <= 1)
|
||||
time = (cooldowntime - world.time)*0.1
|
||||
eta = "[round(time, 1)] seconds"
|
||||
return eta
|
||||
|
||||
/obj/structure/destructible/cult/talisman
|
||||
name = "altar"
|
||||
@@ -72,7 +65,7 @@
|
||||
to_chat(user, "<span class='cultitalic'>You need to anchor [src] to the floor with a tome first.</span>")
|
||||
return
|
||||
if(cooldowntime > world.time)
|
||||
to_chat(user, "<span class='cultitalic'>The magic in [src] is weak, it will be ready to use again in [getETA()].</span>")
|
||||
to_chat(user, "<span class='cultitalic'>The magic in [src] is weak, it will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].</span>")
|
||||
return
|
||||
var/choice = alert(user,"You study the schematics etched into the forge...",,"Eldritch Whetstone","Zealot's Blindfold","Flask of Unholy Water")
|
||||
var/pickedtype
|
||||
@@ -105,7 +98,7 @@
|
||||
to_chat(user, "<span class='cultitalic'>You need to anchor [src] to the floor with a tome first.</span>")
|
||||
return
|
||||
if(cooldowntime > world.time)
|
||||
to_chat(user, "<span class='cultitalic'>The magic in [src] is weak, it will be ready to use again in [getETA()].</span>")
|
||||
to_chat(user, "<span class='cultitalic'>The magic in [src] is weak, it will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].</span>")
|
||||
return
|
||||
var/choice = alert(user,"You study the schematics etched into the forge...",,"Shielded Robe","Flagellant's Robe","Nar-Sien Hardsuit")
|
||||
var/pickedtype
|
||||
@@ -212,7 +205,7 @@
|
||||
to_chat(user, "<span class='cultitalic'>You need to anchor [src] to the floor with a tome first.</span>")
|
||||
return
|
||||
if(cooldowntime > world.time)
|
||||
to_chat(user, "<span class='cultitalic'>The magic in [src] is weak, it will be ready to use again in [getETA()].</span>")
|
||||
to_chat(user, "<span class='cultitalic'>The magic in [src] is weak, it will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].</span>")
|
||||
return
|
||||
var/choice = alert(user,"You flip through the black pages of the archives...",,"Supply Talisman","Shuttle Curse","Veil Walker Set")
|
||||
var/list/pickedtype = list()
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
var/probability = 0
|
||||
var/false_report_weight = 0 //How often will this show up incorrectly in a centcom report?
|
||||
var/station_was_nuked = 0 //see nuclearbomb.dm and malfunction.dm
|
||||
var/explosion_in_progress = 0 //sit back and relax
|
||||
var/round_ends_with_antag_death = 0 //flags the "one verse the station" antags as such
|
||||
var/list/datum/mind/modePlayer = new
|
||||
var/list/datum/mind/antag_candidates = list() // List of possible starting antags goes here
|
||||
@@ -562,3 +561,8 @@
|
||||
|
||||
/datum/game_mode/proc/generate_report() //Generates a small text blurb for the gamemode in centcom report
|
||||
return "Gamemode report for [name] not set. Contact a coder."
|
||||
|
||||
//By default nuke just ends the round
|
||||
/datum/game_mode/proc/OnNukeExplosion(off_station)
|
||||
if(off_station < 2)
|
||||
station_was_nuked = TRUE //Will end the round on next check.
|
||||
@@ -1,5 +1,17 @@
|
||||
/datum/objective_team/abductor_team
|
||||
member_name = "abductor"
|
||||
var/list/objectives = list()
|
||||
var/team_number
|
||||
|
||||
/datum/objective_team/abductor_team/is_solo()
|
||||
return FALSE
|
||||
|
||||
/datum/objective_team/abductor_team/proc/add_objective(datum/objective/O)
|
||||
O.team = src
|
||||
O.update_explanation_text()
|
||||
objectives += O
|
||||
|
||||
/datum/game_mode
|
||||
var/abductor_teams = 0
|
||||
var/list/datum/mind/abductors = list()
|
||||
var/list/datum/mind/abductees = list()
|
||||
|
||||
@@ -12,12 +24,8 @@
|
||||
required_players = 15
|
||||
maximum_players = 50
|
||||
var/max_teams = 4
|
||||
abductor_teams = 1
|
||||
var/list/datum/mind/scientists = list()
|
||||
var/list/datum/mind/agents = list()
|
||||
var/list/datum/objective/team_objectives = list()
|
||||
var/list/team_names = list()
|
||||
var/finished = 0
|
||||
var/list/datum/objective_team/abductor_team/abductor_teams = list()
|
||||
var/finished = FALSE
|
||||
|
||||
/datum/game_mode/abduction/announce()
|
||||
to_chat(world, "<B>The current game mode is - Abduction!</B>")
|
||||
@@ -26,163 +34,78 @@
|
||||
to_chat(world, "<b>Crew</b> - don't get abducted and stop the abductors.")
|
||||
|
||||
/datum/game_mode/abduction/pre_setup()
|
||||
abductor_teams = max(1, min(max_teams,round(num_players()/config.abductor_scaling_coeff)))
|
||||
var/possible_teams = max(1,round(antag_candidates.len / 2))
|
||||
abductor_teams = min(abductor_teams,possible_teams)
|
||||
var/num_teams = max(1, min(max_teams, round(num_players() / config.abductor_scaling_coeff)))
|
||||
var/possible_teams = max(1, round(antag_candidates.len / 2))
|
||||
num_teams = min(num_teams, possible_teams)
|
||||
|
||||
abductors.len = 2*abductor_teams
|
||||
scientists.len = abductor_teams
|
||||
agents.len = abductor_teams
|
||||
team_objectives.len = abductor_teams
|
||||
team_names.len = abductor_teams
|
||||
for(var/i = 1 to num_teams)
|
||||
if(!make_abductor_team())
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
for(var/i=1,i<=abductor_teams,i++)
|
||||
if(!make_abductor_team(i))
|
||||
return 0
|
||||
/datum/game_mode/abduction/proc/make_abductor_team(datum/mind/agent, datum/mind/scientist)
|
||||
var/team_number = abductor_teams.len+1
|
||||
|
||||
return 1
|
||||
var/datum/objective_team/abductor_team/team = new
|
||||
team.team_number = team_number
|
||||
team.name = "Mothership [pick(GLOB.possible_changeling_IDs)]" //TODO Ensure unique and actual alieny names
|
||||
team.add_objective(new/datum/objective/experiment)
|
||||
|
||||
/datum/game_mode/abduction/proc/make_abductor_team(team_number,preset_agent=null,preset_scientist=null)
|
||||
//Team Name
|
||||
team_names[team_number] = "Mothership [pick(GLOB.possible_changeling_IDs)]" //TODO Ensure unique and actual alieny names
|
||||
//Team Objective
|
||||
var/datum/objective/experiment/team_objective = new
|
||||
team_objective.team_number = team_number
|
||||
team_objectives[team_number] = team_objective
|
||||
//Team Members
|
||||
if(antag_candidates.len < (!agent + !scientist))
|
||||
return
|
||||
|
||||
if(!preset_agent || !preset_scientist)
|
||||
if(antag_candidates.len <=2)
|
||||
return 0
|
||||
|
||||
var/datum/mind/scientist
|
||||
var/datum/mind/agent
|
||||
|
||||
if(!preset_scientist)
|
||||
if(!scientist)
|
||||
scientist = pick(antag_candidates)
|
||||
antag_candidates -= scientist
|
||||
else
|
||||
scientist = preset_scientist
|
||||
antag_candidates -= scientist
|
||||
team.members |= scientist
|
||||
scientist.assigned_role = "Abductor Scientist"
|
||||
log_game("[scientist.key] (ckey) has been selected as [team.name] abductor scientist.")
|
||||
|
||||
if(!preset_agent)
|
||||
if(!agent)
|
||||
agent = pick(antag_candidates)
|
||||
antag_candidates -= agent
|
||||
else
|
||||
agent = preset_agent
|
||||
antag_candidates -= agent
|
||||
team.members |= agent
|
||||
agent.assigned_role = "Abductor Agent"
|
||||
log_game("[agent.key] (ckey) has been selected as [team.name] abductor agent.")
|
||||
|
||||
|
||||
scientist.assigned_role = "abductor scientist"
|
||||
scientist.special_role = "abductor scientist"
|
||||
log_game("[scientist.key] (ckey) has been selected as an abductor team [team_number] scientist.")
|
||||
|
||||
agent.assigned_role = "abductor agent"
|
||||
agent.special_role = "abductor agent"
|
||||
log_game("[agent.key] (ckey) has been selected as an abductor team [team_number] agent.")
|
||||
|
||||
abductors |= agent
|
||||
abductors |= scientist
|
||||
scientists[team_number] = scientist
|
||||
agents[team_number] = agent
|
||||
return 1
|
||||
abductor_teams += team
|
||||
return team
|
||||
|
||||
/datum/game_mode/abduction/post_setup()
|
||||
for(var/team_number=1,team_number<=abductor_teams,team_number++)
|
||||
post_setup_team(team_number)
|
||||
for(var/datum/objective_team/abductor_team/team in abductor_teams)
|
||||
post_setup_team(team)
|
||||
return ..()
|
||||
|
||||
//Used for create antag buttons
|
||||
/datum/game_mode/abduction/proc/post_setup_team(team_number)
|
||||
var/list/obj/effect/landmark/abductor/agent_landmarks = list()
|
||||
var/list/obj/effect/landmark/abductor/scientist_landmarks = list()
|
||||
agent_landmarks.len = max_teams
|
||||
scientist_landmarks.len = max_teams
|
||||
for(var/obj/effect/landmark/abductor/A in GLOB.landmarks_list)
|
||||
if(istype(A, /obj/effect/landmark/abductor/agent))
|
||||
agent_landmarks[text2num(A.team)] = A
|
||||
else if(istype(A, /obj/effect/landmark/abductor/scientist))
|
||||
scientist_landmarks[text2num(A.team)] = A
|
||||
|
||||
var/team_name = team_names[team_number]
|
||||
|
||||
var/datum/mind/agent
|
||||
var/obj/effect/landmark/L
|
||||
var/datum/mind/scientist
|
||||
var/mob/living/carbon/human/H
|
||||
var/datum/species/abductor/S
|
||||
|
||||
agent = agents[team_number]
|
||||
H = agent.current
|
||||
L = agent_landmarks[team_number]
|
||||
H.forceMove(L.loc)
|
||||
H.set_species(/datum/species/abductor)
|
||||
S = H.dna.species
|
||||
S.team = team_number
|
||||
H.real_name = team_name + " Agent"
|
||||
H.equipOutfit(/datum/outfit/abductor/agent)
|
||||
greet_agent(agent,team_number)
|
||||
|
||||
|
||||
scientist = scientists[team_number]
|
||||
H = scientist.current
|
||||
L = scientist_landmarks[team_number]
|
||||
H.forceMove(L.loc)
|
||||
H.set_species(/datum/species/abductor)
|
||||
S = H.dna.species
|
||||
S.scientist = TRUE
|
||||
S.team = team_number
|
||||
H.real_name = team_name + " Scientist"
|
||||
H.equipOutfit(/datum/outfit/abductor/scientist)
|
||||
greet_scientist(scientist,team_number)
|
||||
|
||||
|
||||
|
||||
/datum/game_mode/abduction/proc/greet_agent(datum/mind/abductor,team_number)
|
||||
abductor.objectives += team_objectives[team_number]
|
||||
var/team_name = team_names[team_number]
|
||||
|
||||
to_chat(abductor.current, "<span class='notice'>You are an agent of [team_name]!</span>")
|
||||
to_chat(abductor.current, "<span class='notice'>With the help of your teammate, kidnap and experiment on station crew members!</span>")
|
||||
to_chat(abductor.current, "<span class='notice'>Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve.</span>")
|
||||
|
||||
abductor.announce_objectives()
|
||||
|
||||
/datum/game_mode/abduction/proc/greet_scientist(datum/mind/abductor,team_number)
|
||||
abductor.objectives += team_objectives[team_number]
|
||||
var/team_name = team_names[team_number]
|
||||
|
||||
to_chat(abductor.current, "<span class='notice'>You are a scientist of [team_name]!</span>")
|
||||
to_chat(abductor.current, "<span class='notice'>With the help of your teammate, kidnap and experiment on station crew members!</span>")
|
||||
to_chat(abductor.current, "<span class='notice'>Use your tool and ship consoles to support the agent and retrieve human specimens.</span>")
|
||||
|
||||
abductor.announce_objectives()
|
||||
|
||||
/datum/game_mode/abduction/proc/get_team_console(team_number)
|
||||
for(var/obj/machinery/abductor/console/C in GLOB.machines)
|
||||
if(C.team == team_number)
|
||||
return C
|
||||
/datum/game_mode/abduction/proc/post_setup_team(datum/objective_team/abductor_team/team)
|
||||
for(var/datum/mind/M in team.members)
|
||||
if(M.assigned_role == "Abductor Scientist")
|
||||
M.add_antag_datum(ANTAG_DATUM_ABDUCTOR_SCIENTIST, team)
|
||||
else
|
||||
M.add_antag_datum(ANTAG_DATUM_ABDUCTOR_AGENT, team)
|
||||
|
||||
/datum/game_mode/abduction/check_finished()
|
||||
if(!finished)
|
||||
for(var/team_number=1,team_number<=abductor_teams,team_number++)
|
||||
var/obj/machinery/abductor/console/con = get_team_console(team_number)
|
||||
var/datum/objective/objective = team_objectives[team_number]
|
||||
if (con.experiment.points >= objective.target_amount)
|
||||
SSshuttle.emergency.request(null, set_coefficient = 0.5)
|
||||
finished = 1
|
||||
return ..()
|
||||
for(var/datum/objective_team/abductor_team/team in abductor_teams)
|
||||
for(var/datum/objective/O in team.objectives)
|
||||
if(O.check_completion())
|
||||
SSshuttle.emergency.request(null, set_coefficient = 0.5)
|
||||
finished = TRUE
|
||||
return ..()
|
||||
return ..()
|
||||
|
||||
/datum/game_mode/abduction/declare_completion()
|
||||
for(var/team_number=1,team_number<=abductor_teams,team_number++)
|
||||
var/obj/machinery/abductor/console/console = get_team_console(team_number)
|
||||
var/datum/objective/objective = team_objectives[team_number]
|
||||
var/team_name = team_names[team_number]
|
||||
if(console.experiment.points >= objective.target_amount)
|
||||
to_chat(world, "<span class='greenannounce'>[team_name] team fulfilled its mission!</span>")
|
||||
for(var/datum/objective_team/abductor_team/team in abductor_teams)
|
||||
var/won = TRUE
|
||||
for(var/datum/objective/O in team.objectives)
|
||||
if(!O.check_completion())
|
||||
won = FALSE
|
||||
if(won)
|
||||
to_chat(world, "<span class='greenannounce'>[team.name] team fulfilled its mission!</span>")
|
||||
else
|
||||
to_chat(world, "<span class='boldannounce'>[team_name] team failed its mission.</span>")
|
||||
to_chat(world, "<span class='boldannounce'>[team.name] team failed its mission.</span>")
|
||||
..()
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/datum/game_mode/proc/auto_declare_completion_abduction()
|
||||
var/text = ""
|
||||
@@ -200,40 +123,28 @@
|
||||
text += "<br>"
|
||||
to_chat(world, text)
|
||||
|
||||
//Landmarks
|
||||
// TODO: Split into separate landmarks for prettier ships
|
||||
// LANDMARKS
|
||||
/obj/effect/landmark/abductor
|
||||
var/team = 1
|
||||
var/team_number = 1
|
||||
|
||||
/obj/effect/landmark/abductor/agent
|
||||
/obj/effect/landmark/abductor/scientist
|
||||
|
||||
|
||||
// OBJECTIVES
|
||||
/datum/objective/experiment
|
||||
target_amount = 6
|
||||
var/team_number
|
||||
|
||||
/datum/objective/experiment/New()
|
||||
explanation_text = "Experiment on [target_amount] humans."
|
||||
|
||||
/datum/objective/experiment/check_completion()
|
||||
var/ab_team = team_number
|
||||
if(owner)
|
||||
if(!owner.current || !ishuman(owner.current))
|
||||
return 0
|
||||
var/mob/living/carbon/human/H = owner.current
|
||||
if(H.dna.species.id != "abductor")
|
||||
return 0
|
||||
var/datum/species/abductor/S = H.dna.species
|
||||
ab_team = S.team
|
||||
for(var/obj/machinery/abductor/experiment/E in GLOB.machines)
|
||||
if(E.team == ab_team)
|
||||
if(E.points >= target_amount)
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
return 0
|
||||
if(!istype(team, /datum/objective_team/abductor_team))
|
||||
return FALSE
|
||||
var/datum/objective_team/abductor_team/T = team
|
||||
if(E.team_number == T.team_number)
|
||||
return E.points >= target_amount
|
||||
return FALSE
|
||||
|
||||
/datum/game_mode/proc/update_abductor_icons_added(datum/mind/alien_mind)
|
||||
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_ABDUCTOR]
|
||||
|
||||
@@ -328,7 +328,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
return
|
||||
|
||||
/obj/item/paper/guides/antag/abductor/AltClick()
|
||||
return
|
||||
return //otherwise it would fold into a paperplane.
|
||||
|
||||
#define BATON_STUN 0
|
||||
#define BATON_SLEEP 1
|
||||
|
||||
@@ -5,20 +5,14 @@
|
||||
back = /obj/item/storage/backpack
|
||||
ears = /obj/item/device/radio/headset/abductor
|
||||
|
||||
/datum/outfit/abductor/proc/get_team_console(team_number)
|
||||
for(var/obj/machinery/abductor/console/C in GLOB.machines)
|
||||
if(C.team == team_number)
|
||||
return C
|
||||
|
||||
/datum/outfit/abductor/proc/link_to_console(mob/living/carbon/human/H, team_number)
|
||||
if(!team_number && isabductor(H))
|
||||
var/datum/species/abductor/S = H.dna.species
|
||||
team_number = S.team
|
||||
|
||||
var/datum/antagonist/abductor/A = H.mind.has_antag_datum(ANTAG_DATUM_ABDUCTOR)
|
||||
if(!team_number && A)
|
||||
team_number = A.team.team_number
|
||||
if(!team_number)
|
||||
team_number = 1
|
||||
|
||||
var/obj/machinery/abductor/console/console = get_team_console(team_number)
|
||||
var/obj/machinery/abductor/console/console = get_abductor_console(team_number)
|
||||
if(console)
|
||||
var/obj/item/clothing/suit/armor/abductor/vest/V = locate() in H
|
||||
if(V)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/obj/machinery/computer/camera_advanced/abductor
|
||||
name = "Human Observation Console"
|
||||
var/team = 0
|
||||
var/team_number = 0
|
||||
networks = list("SS13","Abductor")
|
||||
var/datum/action/innate/teleport_in/tele_in_action = new
|
||||
var/datum/action/innate/teleport_out/tele_out_action = new
|
||||
@@ -9,7 +9,7 @@
|
||||
var/datum/action/innate/vest_disguise_swap/vest_disguise_action = new
|
||||
var/datum/action/innate/set_droppoint/set_droppoint_action = new
|
||||
var/obj/machinery/abductor/console/console
|
||||
z_lock = ZLEVEL_STATION_PRIMARY
|
||||
station_lock_override = TRUE
|
||||
|
||||
icon = 'icons/obj/abductor.dmi'
|
||||
icon_state = "camera"
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
/proc/get_abductor_console(team_number)
|
||||
for(var/obj/machinery/abductor/console/C in GLOB.machines)
|
||||
if(C.team_number == team_number)
|
||||
return C
|
||||
|
||||
//Common
|
||||
|
||||
/obj/machinery/abductor
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
var/team = 0
|
||||
var/team_number = 0
|
||||
|
||||
//Console
|
||||
|
||||
@@ -139,21 +144,21 @@
|
||||
return INITIALIZE_HINT_LATELOAD
|
||||
|
||||
/obj/machinery/abductor/console/LateInitialize()
|
||||
if(!team)
|
||||
if(!team_number)
|
||||
return
|
||||
|
||||
for(var/obj/machinery/abductor/pad/p in GLOB.machines)
|
||||
if(p.team == team)
|
||||
if(p.team_number == team_number)
|
||||
pad = p
|
||||
break
|
||||
|
||||
for(var/obj/machinery/abductor/experiment/e in GLOB.machines)
|
||||
if(e.team == team)
|
||||
if(e.team_number == team_number)
|
||||
experiment = e
|
||||
e.console = src
|
||||
|
||||
for(var/obj/machinery/computer/camera_advanced/abductor/c in GLOB.machines)
|
||||
if(c.team == team)
|
||||
if(c.team_number == team_number)
|
||||
camera = c
|
||||
c.console = src
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
var/flash = " - || - "
|
||||
var/obj/machinery/abductor/console/console
|
||||
var/message_cooldown = 0
|
||||
var/breakout_time = 0.75
|
||||
var/breakout_time = 450
|
||||
|
||||
/obj/machinery/abductor/experiment/MouseDrop_T(mob/target, mob/user)
|
||||
if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user) || !ishuman(target))
|
||||
@@ -50,9 +50,9 @@
|
||||
user.changeNext_move(CLICK_CD_BREAKOUT)
|
||||
user.last_special = world.time + CLICK_CD_BREAKOUT
|
||||
user.visible_message("<span class='notice'>You see [user] kicking against the door of [src]!</span>", \
|
||||
"<span class='notice'>You lean on the back of [src] and start pushing the door open... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)</span>", \
|
||||
"<span class='notice'>You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)</span>", \
|
||||
"<span class='italics'>You hear a metallic creaking from [src].</span>")
|
||||
if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds
|
||||
if(do_after(user,(breakout_time), target = src))
|
||||
if(!user || user.stat != CONSCIOUS || user.loc != src || state_open)
|
||||
return
|
||||
user.visible_message("<span class='warning'>[user] successfully broke out of [src]!</span>", \
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user